HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Remove Empty Argument Lists from Attributes

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
argumentemptyremoveattributeslistsfrom

Problem

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

Solution

It seems you could combine the two methods into one by making it generic:

private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
    where TSyntax : class
{
    var attributeExpression = context.Node as TSyntax;

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


If CSharpAttributeSyntax and VisualBasicAttributeSyntax share a common interface or base class (looks like it), use that to refine the generic type parameter constraint, as a class constraint merely ensures the type is a reference type. Otherwise you'd have to cast to dynamic for it to work.

Same here:

private SyntaxNode RemoveEmptyArgumentList(SyntaxNode root, TSyntax attributeExpression)
     where TSyntax : WhateverTheInterfaceOrBaseTypeIs
{
    return root.RemoveNode(attributeExpression.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
}


The call site already had the responsibility of knowing which method to call: now you can just change that to knowing which generic type parameter to use.

Side note, this assignment is redundant:

SyntaxNode newRoot = null;


A reference type is initialized to null anyway, so this suffices:

SyntaxNode newRoot;

Code Snippets

private void AnalyzeSymbol<TSyntax>(SyntaxNodeAnalysisContext context)
    where TSyntax : class
{
    var attributeExpression = context.Node as TSyntax;

    // 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 SyntaxNode RemoveEmptyArgumentList<TSyntax>(SyntaxNode root, TSyntax attributeExpression)
     where TSyntax : WhateverTheInterfaceOrBaseTypeIs
{
    return root.RemoveNode(attributeExpression.ArgumentList, SyntaxRemoveOptions.KeepNoTrivia);
}
SyntaxNode newRoot = null;
SyntaxNode newRoot;

Context

StackExchange Code Review Q#103965, answer score: 3

Revisions (0)

No revisions yet.