建立标准编码规则(二)-DiagnosticAnalyzer 增加诊断分析代码

1.使用语法树

当我们要编写一个规则,例如 检测正值表达式的时候,如何编写有效的规则呢

Regex.Match("my text", @"\pXXX");

这里我们可以借助分析工具 Roslyn Syntax Visualizer,在 视图>其他窗口>Syntax Visualizer

当我们在ConsoleApp项目中编写如下代码

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Regex.Match("my text", @"\pXXX");
        } 
    }
}

发现 SyntaxTree (以下称语法树)自动定位到对应的语法中

在语法树中

1 蓝色表示语法节点

2 绿色表示编译器读取源文件时所发现的语法令牌、各个词、数字和符号

3 红色表示琐碎内容,代表不是令牌的其他内容:空格、注释等。

 2.编写实例

新建RegexAnalyzerAnalyzer 类,继承DiagnosticAnalyzer,写法类似默认生成的 DiagnosticAnalyzer.cs

  public class RegexAnalyzerAnalyzer : DiagnosticAnalyzer
   {
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
        public override void Initialize(AnalysisContext context)
        {
            context.RegisterSyntaxNodeAction(
              AnalyzeNode, SyntaxKind.InvocationExpression);
        }
}

 

其中 AnalysisContext 如下:

RegisterSyntaxNodeAction 在分析特定类型的语法节点时触发
RegisterSymbolAction 在分析特定类型的符号时触发
RegisterSyntaxTreeAction 在分析文件的整棵语法树时触发
RegisterSemanticModelAction 在语义模型可用于整个文件时触发
RegisterCodeBlockStartAction
RegisterCodeBlockEndAction
在分析方法主体或其他代码块之前/之后触发

RegisterCompilationStartAction
RegisterCompilationEndAction
在分析整个项目之前/之后触发

11

具体判断代码

/// <summary>
        /// 1 首先他是一个表达式节点
        /// 2 他是Match方法
        /// 3 他是ystem.Text.RegularExpressions.Regex.Match下的方法
        /// 4 他有两个参数
        /// 5 第二个参数有值
        /// 6 使用Match捕捉第二个参数的正值表达式异常
        /// </summary>
        /// <param name="context"></param>
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            var invocationExpr = (InvocationExpressionSyntax)context.Node;//InvocationExpressionSyntax 表达式特定节点
            var memberAccessExpr =
              invocationExpr.Expression as MemberAccessExpressionSyntax;
            if (memberAccessExpr?.Name.ToString() != "Match") return;//如果不是Match 返回
            var memberSymbol = context.SemanticModel.
              GetSymbolInfo(memberAccessExpr).Symbol as IMethodSymbol;//获取上下文memberAccessExpr的语义模型
            if (!memberSymbol?.ToString().StartsWith(
              "System.Text.RegularExpressions.Regex.Match") ?? true) return;//如果memberAccessExpr不是System.Text.RegularExpressions.Regex.Match 返回
            var argumentList = invocationExpr.ArgumentList as ArgumentListSyntax;//获取节点参数 
            if ((argumentList?.Arguments.Count ?? 0) < 2) return;//参数小于2返回
            var regexLiteral =
              argumentList.Arguments[1].Expression as LiteralExpressionSyntax;//获取第二个参数内容
            if (regexLiteral == null) return;//第二个参数是null的返回
            var regexOpt = context.SemanticModel.GetConstantValue(regexLiteral);//获取参数的常量字符串
            if (!regexOpt.HasValue) return;//空值返回
            var regex = regexOpt.Value as string;//获取字符串
            if (regex == null) return;
            try
            {
                System.Text.RegularExpressions.Regex.Match("", regex);//使用System.Text.RegularExpressions.Regex.Match 如果异常抛出异常
            }
            catch (ArgumentException e)
            {
                //ArgumentException异常 抛出定义的说明
                var diagnostic =
                  Diagnostic.Create(Rule, regexLiteral.GetLocation(), e.Message);
                context.ReportDiagnostic(diagnostic);
            }
        }

参考:https://msdn.microsoft.com/zh-cn/library/dn879356

posted @ 2017-11-21 19:35  fishpro  阅读(733)  评论(0编辑  收藏