Determining if two Tokens syntaxes are the same

Given the following code snippet as an example:

public class Thing { public int Item { get; } public Thing(int item) { Item = Item; // note incorrect assignment: rhs should be item, the passed-in arg, hence analyzer should warn } public Thing(Thing other) { Item = other.Item; // correct assignment, should NOT trigger analyzer } } 

I am writing a Roslyn analyzer to detect and report these cases of possible erroneous self-assignment, the relevant parts below:

 public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(MistakenSelfAssignment, SyntaxKind.SimpleAssignmentExpression); } private static void MistakenSelfAssignment(SyntaxNodeAnalysisContext context) { var assignment = context.Node as AssignmentExpressionSyntax; if (assignment == null) { return; } var leftToken = GetIdentifierToken(assignment.Left); var rightToken = GetIdentifierToken(assignment.Right); if (leftToken != null && leftToken.IsEquivalentTo(rightToken)) // this never works { var diagnostic = Diagnostic.Create(Rule, assignment.GetLocation()); context.ReportDiagnostic(diagnostic); } } private static SyntaxToken GetIdentifierToken(ExpressionSyntax syntax) { var identifierName = syntax as IdentifierNameSyntax; if (identifierName != null) { return identifierName.Identifier; } var identifierAccess = syntax as MemberAccessExpressionSyntax; if (identifierAccess != null) { return identifierAccess.Name.Identifier; } return default(SyntaxToken); } 

But I can't figure out how to determine if the LHS and RHS assignments are the same token - SyntaxToken.IsEquivalentTo is represented by the method I want, but it always returns false, like SyntaxToken.Equals and == .

What is the right way to determine if a token belongs to itself?

+6
source share
1 answer

I do not think you can do this at the SyntaxToken level. At first I thought the semantic model would help you here, but in both cases the symbols refer to the same thing, so you cannot use this to differentiate.

However, what you can do is simply examine SimpleAssignmentExpression , check if both operands are identifiers, and check their equivalence through the same SyntaxFactory.AreEquivalent() that Marcus mentioned. I got to this (see this point for a complete LINQPad query):

Let's say you write this method:

 private static bool IsAssignmentBad(AssignmentExpressionSyntax assignmentNode) { if (!assignmentNode.IsKind(SyntaxKind.SimpleAssignmentExpression)) { return false; } var lhs = assignmentNode.Left; if (!lhs.IsKind(SyntaxKind.IdentifierName)) { return false; } var rhs = assignmentNode.Right; if (!rhs.IsKind(SyntaxKind.IdentifierName)) { return false; } return SyntaxFactory.AreEquivalent(lhs, rhs); } 

Then starting with this gives what you want, I think:

 var tree = CSharpSyntaxTree.ParseText( @"public class Thing { public int Item { get; } public Thing(int item) { Item = Item; // note incorrect assignment: rhs should be item, the passed-in arg, hence analyzer should warn } public Thing(Thing other) { Item = other.Item; // correct assignment, should NOT trigger analyzer } }"); var root = tree.GetRoot(); var incorrectAssignment = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().First(); var correctAssignment = root.DescendantNodes().OfType<AssignmentExpressionSyntax>().Last(); var b1 = IsAssignmentBad(correctAssignment); // doesn't consider the assignment bad var b2 = IsAssignmentBad(incorrectAssignment); // this one does 
+1
source

All Articles