Я пытаюсь написать анализатор, который запрещает пользователям предоставлять параметры, которые автоматически предоставляются (например, компилятором с [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
, не поддерживается, что неправильно ( подробнее здесь )