罗斯林如何检查特定的属性类型

时间:2019-07-10 14:31:22

标签: c# attributes roslyn

TL; DR:在罗斯林,我想知道如何对照已知类型检查属性的类型(链接的问题无济于事)。

我遵循了Microsoft's tutorial for creating a C# code analyser,它基本上涉及使用称为“带有代码修复(.NET Standard)的分析器”的Visual Studio模板项目。该模板为您提供了一个分析器项目(包括一个正在运行的分析器和一个“代码修复”),一个单元测试项目(带有一些类来提供用于测试分析器和“代码修复”的框架)和一个VSIX项目。非常好:谢谢微软。

我现在正在尝试编写我的第一个分析器,但我遇到了第一个障碍。我正在尝试创建一个分析器,该分析器检查使用某些类型赋予属性的方法是否与属性类型名称具有相同的名称。我打算使用它来确保将NUnit [Setup]方法称为“ SetUp”,将[TearDown]方法称为“ TearDown”,依此类推...这些方法的名称与附加到该属性的属性相同。方法。

我看过Roslyn Check Type of an Attribute;但是答案实际上不是在问题的上下文中表达的(它没有提到如何将desiredSymbolattr进行比较-我认为它们不会是'ReferenceEquals');而且我认为我的处境因次要问题而变得更加复杂...

当我使用调试器查看x.AttributeClass时,属性的类型名称前面带有“ ErrorType”,因此我认为它无法解析该类型。因此我通过在相关位置添加以下两行来更改“ DiagnosticVerifier.Helper.cs”“ CreateProject”方法,从而更改了模板项目提供的测试框架中正在使用的“引用”。

    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);
    }

非常感谢您的帮助。

0 个答案:

没有答案