在我们开发自定义独立代码分析以帮助开发人员根据VS中的最佳实践编写C#代码时,我们正在使用Roslyn及其功能。
我们的一个要求有点棘手,我们需要解析和编译一个有下面概念问题的方法:
var myVariable = SomeExpression...;
return myVariable;
这意味着如果定义了一个变量,然后立即返回并且再也没有使用过,[GCop] [1]应警告开发人员并说变量声明是不必要的。
protected override void Analyze(SyntaxNodeAnalysisContext context)
{
NodeToAnalyze = context.Node;
var varDeclareSyntax = (LocalDeclarationStatementSyntax)NodeToAnalyze;
if (varDeclareSyntax == null) return;
var variableDeclare = varDeclareSyntax.ChildNodes().OfType<VariableDeclarationSyntax>().FirstOrDefault();
if (variableDeclare == null) return;
var varDeclarator = variableDeclare.ChildNodes().OfType<VariableDeclaratorSyntax>().FirstOrDefault();
if (varDeclarator == null) return;
var identifierToken = varDeclarator.Identifier.Text;
var method = varDeclarator.GetSingleAncestor<MethodDeclarationSyntax>();
var varDeclaratorIndex = method.DescendantNodes().OfType<CSharpSyntaxNode>().IndexOf(varDeclarator);
/// ??????? TO DO :
现在我们可以访问node =&gt; (var item = 10;
)
问题是我们如何能够准确访问下一行
return item;
我找到了myVariable语法节点及其值,但我不知道如何能够找到返回的 Identider
答案 0 :(得分:2)
LocalDeclarationStatement包含在一个更大的语法节点中,并且是ReturnStatementSyntax.
的兄弟。你的分析真的不应该从LocalDeclarationStatement开始 - 从BlockSyntax或其他东西开始然后寻找声明和从那里返回。
尝试这种方法的另一种方法是首先找到ReturnStatementSyntax ,一旦你看到它返回一个简单变量,你就可以调用SemanticModel.GetSymbolInfo()来查找符号,然后从该符号转到定义它的语法。从那里你可以看到它们是否是并排的。
答案 1 :(得分:0)
希望完成......这是我的代码
protected override void Analyze(SyntaxNodeAnalysisContext context)
{
NodeToAnalyze = context.Node;
var varDeclareSyntax = (LocalDeclarationStatementSyntax)NodeToAnalyze;
if (varDeclareSyntax == null) return;
var variableDeclare = varDeclareSyntax.ChildNodes().OfType<VariableDeclarationSyntax>().FirstOrDefault();
if (variableDeclare == null) return;
var varDeclarator = variableDeclare.ChildNodes().OfType<VariableDeclaratorSyntax>().FirstOrDefault();
if (varDeclarator == null) return;
//var identifierToken = varDeclarator.Identifier.Text; // <- here we find [item] in ( var item=expression; )
var method = varDeclarator.GetSingleAncestor<MethodDeclarationSyntax>();
var varDeclaratorIndex = method.DescendantNodes().OfType<CSharpSyntaxNode>().IndexOf(varDeclarator);
var allNodes = method.DescendantNodes().OfType<CSharpSyntaxNode>().Select((node, index) => new Node
{
Index = index,
Syntax = node,
Location = node.GetLocation(),
Kind = node.Kind(),
Ancestors = node.Ancestors()
}).ToArray();
var maxIndex = allNodes.Where(it => it.Ancestors.Any(x => x == varDeclarator)).Max(it => it.Index.Value);
if (maxIndex >= allNodes.Length) return;
var nextReturn = allNodes[maxIndex + 1];
if (nextReturn.Kind != SyntaxKind.ReturnStatement) return;
var @return = nextReturn.Syntax as ReturnStatementSyntax;
if ((@return.Expression as IdentifierNameSyntax)?.Identifier.ValueText == varDeclarator.Identifier.ValueText)
{
ReportDiagnostic(context, varDeclareSyntax);
}
}
protected override RuleDescription GetDescription()
{
return new RuleDescription
{
ID = "176",
Category = Category.Design,
Message = "Variable declaration is unnecessary due to it used only for return statement"
};
}
private class Node : NodeDefinition
{
public IEnumerable<SyntaxNode> Ancestors { get; set; }
public SyntaxNode Syntax { get; set; }
public SyntaxKind Kind { get; set; }
}