C# 如何使用Roslyn评估局部变量/参数状态
我的情况有点复杂。我必须为一些情况创建分析器/代码修复提供程序,例如仅分配了参数但从未使用,或者从未使用局部变量 对于参数情况,我将进行方法声明并查看参数列表以获取所有分析器。我将在方法中遍历赋值表达式,并过滤使用辅助方法赋值的参数 它变得模糊的地方是我没有线索,也不知道何时使用了局部变量/参数。我看了符号,但他们不能告诉我使用了/未使用的变量。我可以尝试通过在字符串中转换方法声明语法上下文并查找分配的参数来查找方法中提到变量名称的次数,但这是一个非常糟糕的主意 我真的被卡住了,我会从任何有过这种经历的人那里得到一些帮助 对于可能会问这个问题的人,我主要是在寻找分析器缺少的逻辑。我不知道代码修复提供程序将如何工作。如果你对我能做什么有想法,请在你的答案中包含它!到目前为止,我一直在想,可以从方法中删除未使用的局部变量,也可以删除未使用的参数。我现在不确定 更新 我现在正在尝试使用DataflowAPI,但它目前不适合我。这条线索最古老的答案给了我一个起点,但它实际上不起作用 我想出了自己的办法:C# 如何使用Roslyn评估局部变量/参数状态,c#,roslyn,analyzer,C#,Roslyn,Analyzer,我的情况有点复杂。我必须为一些情况创建分析器/代码修复提供程序,例如仅分配了参数但从未使用,或者从未使用局部变量 对于参数情况,我将进行方法声明并查看参数列表以获取所有分析器。我将在方法中遍历赋值表达式,并过滤使用辅助方法赋值的参数 它变得模糊的地方是我没有线索,也不知道何时使用了局部变量/参数。我看了符号,但他们不能告诉我使用了/未使用的变量。我可以尝试通过在字符串中转换方法声明语法上下文并查找分配的参数来查找方法中提到变量名称的次数,但这是一个非常糟糕的主意 我真的被卡住了,我会从任何有过这
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
当运行时到达readWrite或result(从最早的答案)时,我收到以下消息:
但在此之前,在我的分析器中,当我尝试验证我的节点以确保它不是null并为数据流API创建适当的元素时,没有代码中断(不确定这是否是适当的术语),但目前我无法继续 您可以通过
DataFlowAnalysis
api查看是否使用了大多数变量(读/写)。我已在上编写了此API的介绍
我相信在你的例子中,你在寻找从未被读取过的变量
var tree = CSharpSyntaxTree.ParseText(@"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
var-tree=CSharpSyntaxTree.ParseText(@)
公共类样本
{
公共图书馆
{
int=0;
int=1;
System.Console.Write(已使用);
}
}");
var Mscorlib=PortableExecutableReference.CreateFromAssembly(typeof(object.Assembly));
var compilation=csharpcomilation.Create(“MyCompilation”,
syntaxTrees:new[]{tree},references:new[]{Mscorlib});
var model=compilation.GetSemanticModel(树);
var methodBody=tree.GetRoot().degenantNodes().OfType().Single().Body;
DataFlowAnalysis结果=model.AnalyzedDataflow(methodBody);
var variablesDeclared=result.variablesDeclared;
var variablesRead=result.ReadInside.Union(result.ReadOutside);
var unused=变量已声明。除(variablesRead)外;
foreach(未使用中的var变量)
{
控制台写入线(变量);
}
您可以通过数据流分析
API查看是否使用(读/写)了大多数变量。我已在上编写了此API的介绍
我相信在你的例子中,你在寻找从未被读取过的变量
var tree = CSharpSyntaxTree.ParseText(@"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
var-tree=CSharpSyntaxTree.ParseText(@)
公共类样本
{
公共图书馆
{
int=0;
int=1;
System.Console.Write(已使用);
}
}");
var Mscorlib=PortableExecutableReference.CreateFromAssembly(typeof(object.Assembly));
var compilation=csharpcomilation.Create(“MyCompilation”,
syntaxTrees:new[]{tree},references:new[]{Mscorlib});
var model=compilation.GetSemanticModel(树);
var methodBody=tree.GetRoot().degenantNodes().OfType().Single().Body;
DataFlowAnalysis结果=model.AnalyzedDataflow(methodBody);
var variablesDeclared=result.variablesDeclared;
var variablesRead=result.ReadInside.Union(result.ReadOutside);
var unused=变量已声明。除(variablesRead)外;
foreach(未使用中的var变量)
{
控制台写入线(变量);
}
基于JoshVarty的答案,为了使其在诊断中起作用,我将为所有MethodDeclaration
语法类型注册一个SyntaxNodeAction
,然后在主体内部查找未使用的变量:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}
基于JoshVarty的回答,为了使其在诊断中起作用,我将为所有
MethodDeclaration
语法类型注册一个SyntaxNodeAction
,然后在正文中查找未使用的变量:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}
我真的不明白?应该使用分析流吗?这会把我引向何方?是的,那么你能为这两种情况中的任何一种编写一个代码示例吗?我只是想确定我明白我在做什么,因为我现在迷路了@你能给我一些见解吗?我刚刚更新了我的帖子,我需要帮助!:-)我真的不明白?应该使用分析流吗?这会把我引向何方?是的,那么你能为这两种情况中的任何一种编写一个代码示例吗?我只是想确定我明白我在做什么,因为我现在迷路了@你能给我一些见解吗?我刚刚更新了我的帖子,我需要帮助!:-)这是一个很好的答案。我真的很感激你这么快就回答了。我应该比现在更快地给出你的答案事实上,看看我在更新后说的,答案对我不起作用,这是一个很好的答案。我真的很感激你这么快就回答了。我应该比现在更快地把你的答案作为答案事实上,看看我在更新后说的话,这个答案不适用于meLove这个答案!如果我想标记“inti”而不是简单的I呢?从
context.Node
获取令牌,然后访问其父节点。从那里你可以计算出你想要用于诊断的范围