【问题标题】:How do I get the current value of a given variable name when writing a Roslyn Analyser?编写 Roslyn 分析器时如何获取给定变量名称的当前值?
【发布时间】:2018-07-24 15:38:22
【问题描述】:

下面的代码sn-p就是我要分析的代码:

var name = "Michael";
name = "John";
var person = new Person(name);

如果Personconstructorname 长度小于5,假设我的分析器应该报错。

我知道如何获取传递给此对象创建表达式的字符串文字 var person = new Person("John") 的值,检查第一个参数类型,然后如果它是字符串文字,则获取 Value 属性。

但是我如何让分析器在Person 对象创建表达式站点上给我name 的值。这个name在代码中定义的很清楚,所以在这种情况下应该是可能的。

到目前为止,我已经尝试过类似...

var nameExpr = (IdentifierNameSyntax)objectCreation.ArgumentList?.Arguments.First()?.Expression;
var nameDataFlow = context.SemanticModel.AnalyzeDataFlow(nameExpr);

看起来我可以通过使用这个数据流来计算 name 的值,但它似乎涉及一组非常复杂和易碎的代码,而且在我看来只有在声明在里面时才能工作数据流代码块。我希望它能够将此令牌解析为它的实际值(如果可能的话),即使在全局编译中也是如此。

即使我自己编写了全局编译钩子,我也必须手动跟踪对变量的每个赋值(包括来自其他变量和方法调用等)

有没有简单的方法让库为我做这件事,如果可以的话,只需在调用站点给我变量的值?

【问题讨论】:

  • 分析器在编译时运行。您无法构建始终知道变量的运行时值是什么的编译时工具。想象一下,您为name 分配了一个来自用户输入的值(例如来自Console.ReadLine()
  • 是的,我对此进行了更多研究,目前 roslyn 似乎没有针对此的算法。但它可以实现,如果它最终解析为一个表达式(而不是一个值),那么我可以在此基础上进行一些分析,即使在多线程环境中,我也可以报告它的可能值,如果分析达到一定的复杂性然后我终于可以放弃它并说“我不知道”这个变量的值是或可能是什么。

标签: c# roslyn code-analysis roslyn-code-analysis


【解决方案1】:

有没有简单的方法让库为我做这件事,如果可以的话,只需在调用站点给我变量的值?

不,事实上,对于具有任意输入的任意程序,这可证明是 impossible

一个例外是当变量是编译类型常量 (const) 时,您可以使用 SemanticModel.GetConstantValue 获取它的值。

我可以报告它的可能值,如果分析达到一定的复杂性,那么我最终可以放弃并说“我不知道”这个变量的值是什么或可能是什么。

即使是简单的情况,这也会很复杂。想想值可能发生变化的所有方式:

  • 可以在代码块内有条件地分配变量。您将如何尝试确定条件是否为真?
  • 可以在 lambda 函数中捕获该变量。您将如何分析 lambda 函数及其调用?
  • 可以将变量分配给表达式,其中可能包括对其他方法的调用等。您将如何确定任意表达式的值?
  • 变量的值可能取决于程序在运行时读取的数据。举个简单的例子,DateTime.Now 的值是多少?您无法使用静态分析来确定这一点。
  • 还有很多其他的。

【讨论】:

  • 你说得对,这将很快完全失控,2^n 个潜在值,其中 n 是刚开始的条件赋值计数!我想我将从在块中声明变量的情况开始,并仅涵盖文字赋值(就像我的具体示例中的情况一样),然后看看你可以用当前资源走多远将会很有趣.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
  • 2016-02-14
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多