Reputation: 34529
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;
}
...
}
}
Upvotes: 6
Views: 4008
Reputation: 823
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"
Upvotes: 6