SyntaxNode.ContainsDiagnostics 不使用您自己的诊断程序?
SyntaxNode.ContainsDiagnostics not working with your own diagnostics?
我正在尝试编写一个分析器来防止用户提供自动提供的参数(例如:由编译器使用 [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)
来自讨论 here 和@Kris Vandermotten 的评论
ContainsDiagnostics is only for syntactic diagnostics (i.e. diagnostics acutally inside the syntax tree)
not for diagnostics reported by later passes (i.e. semantic diagnostics or your own analyzer diagnostics).
Here's why : a specific syntax tree may be contained in many different semantic contexts due to roslyn being able to fork and speculate about things
so in one context, the syntax may be semantically correct, and in another, it won't be
as such, the diagnostics are not stored on the tree itself.
事实上,我的解决方案非常简单:我只需要删除
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));
}
}
我正在尝试编写一个分析器来防止用户提供自动提供的参数(例如:由编译器使用 [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)
来自讨论 here 和@Kris Vandermotten 的评论
ContainsDiagnostics is only for syntactic diagnostics (i.e. diagnostics acutally inside the syntax tree) not for diagnostics reported by later passes (i.e. semantic diagnostics or your own analyzer diagnostics). Here's why : a specific syntax tree may be contained in many different semantic contexts due to roslyn being able to fork and speculate about things so in one context, the syntax may be semantically correct, and in another, it won't be as such, the diagnostics are not stored on the tree itself.
事实上,我的解决方案非常简单:我只需要删除
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));
}
}