SyntaxNode.ContainsDiagnostics无法与您自己的诊断一起使用?

时间:2019-01-22 15:32:05

标签: c# visual-studio roslyn static-code-analysis roslyn-code-analysis

我正在尝试编写一个分析器,以防止用户提供自动提供的参数(例如,编译器使用[CallerMemberName]),并且当您提供了不应提供的参数时,我希望分析器使您出错不提供(为了告诉我不应该提供参数,我创建了一个属性:DontProvideAttribute)。

事情是这样的,自动提供的参数必须是可选的(否则,用户提供的值将覆盖自动提供的参数),因此我进行了第二次分析,以防止用户在非提供的参数上使用[DontProvide] -可选参数。

问题来了,我希望方法调用中的错误仅在参数声明中没有[DontProvide] should only be used on optional parameters错误

时出现。
foreach (SyntaxReference parameterDefinition in parameter.DeclaringSyntaxReferences)
{
    if (parameterDefinition.GetSyntax().ContainsDiagnostics)
    {
        return;
    }
}

应该完成此操作,但似乎不考虑您报告的诊断信息。

我尝试过的事情:

-更改诊断顺序以在方法调用之前对声明进行分析

-改用.GetDiagnostics().Count() > 0

-更改分析文档中文本的顺序,使方法声明位于方法调用之上

分析器:

public override void Initialize(AnalysisContext context)
{
    context.RegisterSymbolAction(AnalyzeParametersDeclaration, SymbolKind.Parameter);
    context.RegisterOperationAction(AnalyzeArguments, OperationKind.Argument);
}

private void AnalyzeArguments(OperationAnalysisContext context)
{
    IArgumentOperation reference = (IArgumentOperation)context.Operation;
    IParameterSymbol parameter = reference.Parameter;
    foreach (SyntaxReference parameterDefinition in parameter.DeclaringSyntaxReferences)
    {
        if (parameterDefinition.GetSyntax().ContainsDiagnostics)
            return;
    }
    foreach (AttributeData attribute in parameter.GetAttributes())
    {
        if (attribute.AttributeClass.Name == "DontProvideAttribute")
        {
            context.ReportDiagnostic(Diagnostic.Create(DontProvide, reference.Syntax.GetLocation(), parameter.Name));
        }
    }
}

private void AnalyzeParametersDeclaration(SymbolAnalysisContext context)
{
    IParameterSymbol parameter = (IParameterSymbol)context.Symbol;
    if (parameter.GetAttributes().Any(a => a.AttributeClass.Name == "DontProvideAttribute") && !parameter.IsOptional)
    {
        context.ReportDiagnostic(Diagnostic.Create(DontProvideOnlyForOptional, parameter.Locations[0]))         
    }
}

一些用于分析的测试代码:

using System;

namespace test
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            MyClass.MyMethod(null);
        }
    }

    internal class MyClass
    {
        public static void MyMethod([DontProvide] object parameter)
        {

        }
    }

    [AttributeUsage(AttributeTargets.Parameter)]
    public class DontProvideAttribute : Attribute
    {

    } 
}

PS :编译器可能会告诉您,不支持与context.RegisterSymbolAction()一起使用的SymbolKind.Parameter,这是错误的(see more here

1 个答案:

答案 0 :(得分:2)

来自讨论here和@Kris Vandermotten的评论

  

ContainsDiagnostics仅适用于语法诊断(即,语法树内的正式诊断)   不适用于以后通过的报告所报告的诊断(即语义诊断或您自己的分析器诊断)。   原因如下:由于roslyn能够分叉和推测事物,因此特定的语法树可能包含在许多不同的语义上下文中   因此,在一种情况下,该语法在语义上可能是正确的,而在另一种情况下,则不是   因此,诊断信息不会存储在树本身上。

事实上,我的解决方案非常简单:我只需要删除

foreach (SyntaxReference parameterDefinition in parameter.DeclaringSyntaxReferences)
{
    if (parameterDefinition.GetSyntax().ContainsDiagnostics)
        return;
}

并在其中的&& parameter.IsOptionnal语句上添加if

foreach (AttributeData attribute in parameter.GetAttributes())
{
    if (attribute.AttributeClass.Name == "DontProvideAttribute")
    {
        context.ReportDiagnostic(Diagnostic.Create(DontProvide, reference.Syntax.GetLocation(), parameter.Name));
    }
}