我正在尝试编写一个分析器,以防止用户提供自动提供的参数(例如,编译器使用[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)
答案 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));
}
}