【问题标题】:SyntaxNode.ContainsDiagnostics not working with your own diagnostics?SyntaxNode.ContainsDiagnostics 不适用于您自己的诊断?
【发布时间】:2019-01-22 15:32:04
【问题描述】:

我正在尝试编写一个分析器来阻止用户提供自动提供的参数(例如:由带有[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)

【问题讨论】:

  • “它似乎没有考虑您自己报告的诊断。”这确实是正确的。现在你的问题是什么?
  • 嗯,我的问题基本上是“我认为是真的吗?”既然您回答得很好,我正在寻找一种解决方法,以仍然能够检测参数声明是否具有诊断功能^^

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


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    相关资源
    最近更新 更多