Reputation: 155
I am trying to use Roslyn analyzers to find all instances of using .ToString()
on an enum value so that I can suggest a codefix to use the nameof()
expression instead. How can I go about doing this? I've trudged through it for the string interpolation scenario in what feels like an overly complicated way, but still need to do it for the other scenarios listed below.
public void PrintStuffOut() {
//all below lines should flag to suggest using nameof(Foo.Bar)
Console.WriteLine(Foo.Bar);
Console.WriteLine(Foo.Bar.ToString());
Console.WriteLine($"Your enum is {Foo.Bar}");
Console.WriteLine($"Your enum is {Foo.Bar.ToString()}");
Console.WriteLine("Your enum is " + Foo.Bar);
Console.WriteLine("Your enum is " + Foo.Bar.ToString());
}
public enum Foo {
Bar
}
Here's what I have so far. This works, but surely this can be done far better
public override void Initialize(AnalysisContext context) {
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.RegisterSyntaxNodeAction(AnalyzeInterpolatedString, SyntaxKind.InterpolatedStringExpression);
}
private void AnalyzeInterpolatedString(SyntaxNodeAnalysisContext ctx) {
var interpolationSyntax = (InterpolatedStringExpressionSyntax)ctx.Node;
foreach (var interpolatedChunk in interpolationSyntax.Contents.OfType<InterpolationSyntax>()) {
var expTypeInfo = ctx.SemanticModel.GetTypeInfo(interpolatedChunk.Expression);
//this if covers the case of when there is an explicit .ToString() on the enum's value in the string interpolation. Feels super hacky.
if (expTypeInfo.Type != null && expTypeInfo.Type.SpecialType == SpecialType.System_String) {
var childrenExpressions = interpolatedChunk.Expression.ChildNodes().OfType<MemberAccessExpressionSyntax>();
foreach (var childExpression in childrenExpressions) {
var childExpTypeInfo = ctx.SemanticModel.GetTypeInfo(childExpression.Expression);
if (childExpTypeInfo.Type != null && childExpTypeInfo.Type.TypeKind == TypeKind.Enum) {
//super hacky way to get the enum name and value. I need to report back EnumName and Value in the example of EnumName.Value.ToString()
ctx.ReportDiagnostic(Diagnostic.Create(Descriptors.UseNameOfForEnum, interpolationSyntax.GetLocation(), interpolatedChunk.Expression.ToString().Split('.').Take(2).ToArray()));
}
}
}
//the else if here covers when there is no explicit .ToString() in the interpolated string
else if (expTypeInfo.Type != null && expTypeInfo.Type.TypeKind == TypeKind.Enum) {
//super hacky way to get the enum name and value. I need to report back EnumName and Value in the example of EnumName.Value.ToString()
ctx.ReportDiagnostic(Diagnostic.Create(Descriptors.UseNameOfForEnum, interpolationSyntax.GetLocation(), interpolatedChunk.Expression.ToString().Split('.')));
}
}
}
I feel like I should be able to do something by registering an action on SyntaxKind.InvocationExpression
, checking that the method being invoked is .ToString()
, and that it's being invoked on an enum value. Is it possible to do it this way? Would that catch the scenarios above where I'm not explicitly using .ToString()
? If not, what's the best way to go about accomplishing this?
Upvotes: 0
Views: 261