2016-09-28 2 views
6

mit dem folgenden Stück Code als Beispiel sind:Feststellen, ob zwei SyntaxTokens denselben

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 
    } 
} 

Ich bin ein Roslyn Analysator Schreiben dieser Fälle möglicher verwechselt Selbstzuweisung, relevante Abschnitte unten zu erkennen und melden :

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

aber ich kann, wenn die LHS und RHS der Zuordnung nicht herausfinden, wie sie bestimmen das gleiche Token sind - SyntaxToken.IsEquivalentTo erscheint die Methode, die ich will, aber es gibt immer falsch, wie tun SyntaxToken.Equals und ==.

Was ist der richtige Weg zu bestimmen, ob ein Token sich auf sich selbst bezieht?

+1

SyntaxFactory.AreEquivalent? – Marcus

+0

@Marcus diese Art von Arbeiten, aber es gilt auch Dinge wie 'Item = other.Item' als gleichwertig, das ist nicht was ich will. Ich bin nur an Fällen interessiert, in denen einer Variablen oder Eigenschaft ein eigener Wert zugewiesen wird. –

+0

Können Sie den gesamten zu analysierenden Code posten? Oder der Teil, bei dem der Vergleich fehlschlägt. Wenn ich mir die Implementierung anschaue, kann ich nicht erkennen, wie "IsEquivalentTo" möglicherweise genaue Ergebnisse liefert. – Marcus

Antwort

1

Ich glaube nicht, dass Sie dies auf dem Niveau SyntaxToken tun können. Zuerst dachte ich, dass das semantische Modell Ihnen hier helfen würde, aber in beiden Fällen beziehen sich die Symbole auf dasselbe, Sie können das also nicht zur Unterscheidung verwenden.

jedoch, was Sie tun können, ist nur die SimpleAssignmentExpression untersuchen, ob beide Operanden Identifikatoren sind, und überprüfen ihre Gleichwertigkeit durch die gleiche SyntaxFactory.AreEquivalent(), die Marcus erwähnt. Ich habe dazu (siehe this gist für eine vollständige LINQPad Abfrage):

Angenommen, Sie haben diese Methode schreiben:

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

Dann ist es mit diesem Lauf gibt, was Sie wollen, ich denke:

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 
+0

Der 'if (! Lhs.IsKind (SyntaxKind.IdentifierName))' Check ist wahrscheinlich zu stark. Der Programmtext könnte 'this.Item = Item' sein, und ich schätze, dass das OP auch das Flag haben möchte. –

+0

Stimmt, dachte nicht an diesen. Ich werde die Antwort später aktualisieren (ich bin jetzt auf einem Mac, kann also den Code nicht testen). – Ties

Verwandte Themen