Sign up ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I converted a C# analyzer for removing empty argument lists from attributes to be a C# and VB.NET analyzer:

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxNodeAction(AnalyzeCSharpSymbol, CSharpSyntaxKind.Attribute);
    context.RegisterSyntaxNodeAction(AnalyzeVisualBasicSymbol, VisualBasicSyntaxKind.Attribute);
}

private void AnalyzeCSharpSymbol(SyntaxNodeAnalysisContext context)
{
    var attributeExpression = context.Node as CSharpAttributeSyntax;

    // attribute must have arguments
    // if there are no parenthesis, the ArgumentList is null
    // if there are empty parenthesis, the ArgumentList is empty
    if (attributeExpression?.ArgumentList == null || attributeExpression.ArgumentList.Arguments.Any())
    {
        return;
    }

    context.ReportDiagnostic(Diagnostic.Create(Rule, attributeExpression.GetLocation()));
}

private void AnalyzeVisualBasicSymbol(SyntaxNodeAnalysisContext context)
{
    var attributeExpression = context.Node as VisualBasicAttributeSyntax;

    // attribute must have arguments
    // if there are no parenthesis, the ArgumentList is null
    // if there are empty parenthesis, the ArgumentList is empty
    if (attributeExpression?.ArgumentList == null || attributeExpression.ArgumentList.Arguments.Any())
    {
        return;
    }

    context.ReportDiagnostic(Diagnostic.Create(Rule, attributeExpression.GetLocation()));
}

Here are my custom using definitions for this class:

using CSharpSyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind;
using VisualBasicSyntaxKind = Microsoft.CodeAnalysis.VisualBasic.SyntaxKind;
using CSharpAttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax;
using VisualBasicAttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax;

This seems very WET, but after thinking it over, this seems to be the best way because only what these methods do is the same, the details are just a coincidence.

This is the code fix. Again, I provided overloaded methods:

private Task<Solution> RemoveEmptyArgumentListAsync(Document document, SyntaxNode root, SyntaxNode statement)
{
    SyntaxNode newRoot = null;

    if (statement is Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax)
    {
        newRoot = RemoveEmptyArgumentList(root, (Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax)statement);
    }
    else if (statement is Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax)
    {
        newRoot = RemoveEmptyArgumentList(root, (Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax)statement);
    }

    var newDocument = document.WithSyntaxRoot(newRoot);
    return Task.FromResult(newDocument.Project.Solution);
}

private SyntaxNode RemoveEmptyArgumentList(SyntaxNode root, Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax attributeExpression)
{
    return root.RemoveNode(attributeExpression.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
}

private SyntaxNode RemoveEmptyArgumentList(SyntaxNode root, Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax attributeExpression)
{
    return root.RemoveNode(attributeExpression.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
}

And more custom usings:

using CSharpAttributeSyntax = Microsoft.CodeAnalysis.CSharp.Syntax.AttributeSyntax;
using VisualBasicAttributeSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.AttributeSyntax;

And here are some sample unit tests:

C#

[TestMethod]
public void AttributeWithEmptyArgumentList_AttributeWithEmptyArgumentList()
{
    var original = @"
using System;

namespace ConsoleApplication1
{
    class MyClass
    {   
        [Obsolete()]
        void Method(string input)
        {
        }
    }
}";

    var result = @"
using System;

namespace ConsoleApplication1
{
    class MyClass
    {   
        [Obsolete]
        void Method(string input)
        {
        }
    }
}";

    VerifyDiagnostic(original, AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString());
    VerifyFix(original, result);
}

Visual Basic

[TestMethod]
public void AttributeWithEmptyArgumentList_AttributeWithEmptyArgumentList()
{
    var original = @"
Module Module1

    <Obsolete()>
    Sub Foo()

    End Sub

End Module";

    var result = @"
Module Module1

    <Obsolete>
    Sub Foo()

    End Sub

End Module";

    VerifyDiagnostic(original, AttributeWithEmptyArgumentListAnalyzer.Rule.MessageFormat.ToString());
    VerifyFix(original, result);
}

For reference, these are the test cases that must pass:

Attributes with parameters (no results):

[Obsolete("test")] and <Obsolete("test")>

Attributes without parameters or parenthesis (no results):

[Obsolete] and <Obsolete>

Attributes without parameters and with parenthesis (results):

[Obsolete()] and <Obsolete()>

share|improve this question
    
Where is the definition for CSharpAttributeSyntax and VisualBasicAttributeSyntax? Is this part of Roslyn? –  EBrown Sep 11 at 13:34
    
@EBrown Oh shoot, that is a custom using I set up. –  Hosch250 Sep 11 at 15:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.