Определение, являются ли два синтаксиса токенов одинаковыми
В качестве примера приведен следующий фрагмент кода:
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
}
}
Я пишу анализатор Roslyn, чтобы выявлять и сообщать об этих случаях возможного ошибочного самостоятельного назначения, соответствующие части ниже:
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);
}
Но я не могу понять, как определить, совпадают ли LHS и RHS назначения - SyntaxToken.IsEquivalentTo
кажется, что метод, который я хочу, но он всегда возвращает ложь, как и SyntaxToken.Equals
а также ==
,
Как правильно определить, ссылается ли токен на себя?
1 ответ
Я не думаю, что вы можете сделать это на SyntaxToken
уровень. Сначала я думал, что семантическая модель поможет вам в этом, но в обоих случаях символы относятся к одному и тому же, поэтому вы не можете использовать это для дифференциации.
Однако, что вы можете сделать, это просто расследовать SimpleAssignmentExpression
проверьте, являются ли оба операнда идентификаторами, и проверьте их эквивалентность через один и тот же SyntaxFactory.AreEquivalent()
что Маркус упомянул. Я дошел до этого (см. Эту суть для полного запроса LINQPad):
Допустим, вы пишете этот метод:
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);
}
Затем, запустив его с этим, вы получите то, что хотите, я думаю:
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