Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Roslyn: How to get the ITypeSymbol associated with an identifier?

Tags:

c#

.net

roslyn

I'm attempting to write a Roslyn analyzer to detect usages of Enumerable.Count() being called on arrays. Here is the relevant code in my analyzer:

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxNodeAction(AnalyzeInvocationExpression, SyntaxKind.InvocationExpression);
}

private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
{
    var invocation = (InvocationExpressionSyntax)context.Node;
    var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
    if (!memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression))
    {
        return;
    }

    Debug.Assert(memberAccess != null);
    var ident = memberAccess.Name.Identifier;
    // Check whether the method is Count() and there is no parameter list before we try to use the Symbol APIs.
    if (ident.ToString() != nameof(Enumerable.Count))
    {
        return;
    }

    var arguments = invocation.ArgumentList.Arguments;
    if (arguments.Count > 0)
    {
        return;
    }

    // Make sure that the subject is an array.
    var subject = memberAccess.Expression;
    var subjectSymbol = context.SemanticModel.GetSymbolInfo(subject).Symbol;
    if (subjectSymbol == null)
    {
        return;
    }

    // ???
}

I'm stuck trying to determine whether the object that Count() is being invoked on is an array. I scanned the API a bit and I see there is an ILocalSymbol with a Type property, and also an IFieldSymbol with a Type property that will both presumably get you the type of the object. However, I don't know whether the object I'm analyzing is a local/field/result of a method call/etc, so I would expect IFieldSymbol and ILocalSymbol to e.g. share some common base interface, say IVariableSymbol, that offers you the Type without having to know all the possible places the variable could have come from. However, it seems both interfaces derive directly from ISymbol.

Is the best solution just to do something like this?

internal static class SymbolUtilities
{
    public static ITypeSymbol GetType(ISymbol symbol)
    {
        if (symbol is IFieldSymbol)
        {
            return ((IFieldSymbol)symbol).Type;
        }

        if (symbol is ILocalSymbol)
        {
            return ((ILocalSymbol)symbol).Type;
        }

        ...
    }
}
like image 448
James Ko Avatar asked Feb 26 '17 01:02

James Ko


1 Answers

You can get the information about the type, using the method GetTypeInfo of the SemanticModel class:

ITypeSymbol subjectType = context.SemanticModel.GetTypeInfo(subject).Type;

You will find more details about it in the article

"Introduction to Roslyn and its use in program development"

like image 94
Night walker Avatar answered Nov 09 '22 23:11

Night walker