Рослин, как проверить для определенных типов атрибутов - PullRequest
0 голосов
/ 10 июля 2019

TL; DR: В Roslyn я хочу знать, как проверить тип атрибута по известному типу (связанный вопрос не помог).

Я следовал Microsoftучебное пособие по созданию анализатора кода C # , которое в основном включает использование шаблона проекта Visual Studio под названием «Анализатор с исправлением кода (.NET Standard)».Этот шаблон предоставляет вам проект анализатора (включая работающий анализатор и «исправление кода» для него), а также проект модульного тестирования (с некоторыми классами для обеспечения инфраструктуры для тестирования анализатора и «исправления кода») и проект VSIX.Очень приятно: спасибо Microsoft.

Я сейчас пытаюсь написать свой первый анализатор, и я падаю на первое препятствие.Я пытаюсь создать анализатор, который проверяет, что методы, которые приписываются с использованием определенных типов, имеют то же имя, что и имя типа атрибута.Я планирую использовать это для того, чтобы метод NUnit [Setup] назывался «SetUp», метод [TearDown] назывался «TearDown» и т. Д. ... методам присваивались те же имена, что и у атрибута, который присоединен кmethod.

Я смотрел на Roslyn Check Тип атрибута ;но ответ на самом деле не сформулирован в контексте вопроса (в нем не упоминается, как сравнить desiredSymbol с attr - я предполагаю, что они не будут 'ReferenceEquals');и я думаю, что моя ситуация усугубляется вторичной проблемой ...

Когда я смотрел на x.AttributeClass с помощью отладчика, имени типа атрибута предшествовал "ErrorType", поэтому я предположил, что он не имелне удалось разрешить тип;поэтому я изменил ссылки, которые используются в рамках тестирования, предоставленной в проекте шаблона, изменив метод «DiagnosticVerifier.Helper.cs» «CreateProject», добавив следующие 2 строки в соответствующих местах:

    private static readonly MetadataReference NUnitReference = MetadataReference.CreateFromFile(typeof(NUnit.Framework.SetUpAttribute).Assembly.Location);

и

            .AddMetadataReference(projectId, NUnitReference);

Это исправило два элемента в symbolsToCheckFor, которые теперь оба разрешаются правильно, а не равны нулю.

Трудно предоставить MCVE для чего-то подобного;но вот что у меня есть для моего DiagnosticAnalyser:

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class MethodAnalyzer : DiagnosticAnalyzer
{
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rules.CO1000_UseAttributeNameForSetUpAndTearDown);

    public override void Initialize(AnalysisContext context)
    {
        context.RegisterSymbolAction(AnalyzeMethod, SymbolKind.Method);
    }

    private static void AnalyzeMethod(SymbolAnalysisContext context)
    {
        var symbol = (IMethodSymbol)context.Symbol;

        var symbolsToCheckFor = new[]
        {
            context.Compilation.GetTypeByMetadataName("NUnit.Framework.SetUpAttribute"),
            context.Compilation.GetTypeByMetadataName("NUnit.Framework.TearDownAttribute"),
        };

        // The next line is what I need help with making it match correctly
        var first = symbol.GetAttributes().FirstOrDefault(attr => symbolsToCheckFor.Contains(attr.AttributeClass));
        if (first != null && first.AttributeClass.Name != symbol.Name)
        {
            var diagnostic = Diagnostic.Create(Rules.CO1000_UseAttributeNameForSetUpAndTearDown, symbol.Locations[0], symbol.Name, first.AttributeClass.Name);

            context.ReportDiagnostic(diagnostic);
        }
    }
}

, а вот модульный тест NUnit, который я хотел бы пройти, когда приведенный выше код исправлен:

    [TestCase("SetUp")]
    [TestCase("TearDown")]
    [TestCase("NUnit.Framework.SetUp")]
    [TestCase("NUnit.Framework.TearDown")]
    public void Diagnostic_triggered_correctly(string attributeName)
    {
        const string faultyMethodName = "MyMethod";
        var test = $@"
using NUnit.Framework;

namespace ConsoleApplication1
{{
    [TestFixture]
    public class MyTests
    {{
        [{attributeName}]
        public void {faultyMethodName}()
        {{
        }}
    }}
}}";
        var expected = new DiagnosticResult
        {
            Id = Rules.CO1000_UseAttributeNameForSetUpAndTearDown.Id,
            Message = $"Method name '{faultyMethodName}' should match the attribute name '{attributeName}'",
            Severity = DiagnosticSeverity.Warning,
            Locations =
                new[] {
                    new DiagnosticResultLocation("Test0.cs", 11, 15)
                }
        };

        VerifyCSharpDiagnostic(test, expected);
    }

Любая помощьс благодарностью получил, спасибо.

...