C# 如何在resharper插件中动态重写AST?

C# 如何在resharper插件中动态重写AST?,c#,resharper,resharper-plugins,C#,Resharper,Resharper Plugins,请求: 我希望能够编写一个分析器,为某个表达式提供代理值,并触发对文档的重新解析 动机: 我们的代码中充斥着ABT测试,这些测试可以是处于已部署状态,也可以是处于活动状态的控制和变量组。 通过数据库查找来确定测试的状态。 对于与控制组一起部署的测试,以下形式的任何语句都将评估为false: if(ExperimentService.IsInVariant(ABTest.Test1)) { } 我试图提供工具,通过在这个场景中使其变灰,使其在开发时更容易处理。 事实上,这是相当有限的,而且不健壮

请求:

我希望能够编写一个分析器,为某个表达式提供代理值,并触发对文档的重新解析

动机:

我们的代码中充斥着ABT测试,这些测试可以是处于已部署状态,也可以是处于活动状态的控制和变量组。 通过数据库查找来确定测试的状态。 对于与控制组一起部署的测试,以下形式的任何语句都将评估为false:

if(ExperimentService.IsInVariant(ABTest.Test1))
{
}
我试图提供工具,通过在这个场景中使其变灰,使其在开发时更容易处理。 事实上,这是相当有限的,而且不健壮,因为我基本上必须自己玩解析器

如果实际代码是

if(!ExperimentService.IsInVariant(ABTest.Test1))

我可以看到提供的一种可能的方法是,允许我们编写一次触发的分析器,并在实际的IDE解析发生之前重写树(或者,好吧,只是第二次解析它)。 这些应该只触发一次,并允许我们用另一个表达式替换某个表达式。这将允许我交换所有这些实验调用的真文本和假文本

因此,这些部分可以从所有其他IDE特性中受益,例如代码灰显以获得无法访问的代码,但也可以从更复杂的特性中受益,例如变量,它永远不会有不同的值


显然,这只是一个例子,我不确定它是否可行。任何关于适当功能或已经存在的东西的建议都是非常受欢迎的。

这还不足以真正保证赏金,但一个可能适用于的解决方案是创建一个新功能并扩展基本规则

你说

我试图提供工具,通过在这个场景中使其变灰,使其在开发时更容易处理

灰显相应的部分可能只是通过修改语法突出显示规则来完成的


请看

我认为没有一种方法是不妥协的

ReSharper不支持在分析之前重写AST,这只会重写文件中的文本

您可以编写一个分析器,通过对
if
块的内容应用“死代码”高亮显示来灰显代码,但正如您所说的,您需要解析代码并分析控制流,以使其正确,我认为这将非常困难(ReSharper确实提供了一个控制流图,因此您可以遍历它,但这取决于a.找到
的返回值IsInVariant
和B.在任何条件下跟踪该值,
&&
|
语句,直到找到合适的
if
块)

或者,您可以使用
ContractAnnotation
属性标记
IsInVariant
方法,类似于:

[ContractAnnotation(=>false”)]
公共布尔值是可变的(字符串标识符)
{
//不管怎样。。。
}
这将告诉ReSharper的分析,该方法总是返回
false
(您也可以说它将根据特定输入返回
true
/
false
/
null
/非null)。因为它总是返回
false
,所以ReSharper将灰显
if
语句中的代码,如果执行
if(!IsInVariant(…)
,则灰显
else
分支


这里的缺点是ReSharper还会在
if
语句中添加一个警告,告诉您表达式总是返回
false
。因此,这是一个折衷方案,但您可以将警告的严重性更改为Hint,这样就不那么麻烦了。

我听到了,我最后的想法是这样的(如果你能发现任何听起来不对劲的地方?)。如果我创建自己的C#语言服务来覆盖resharper的CsharpService实现,会怎么样?我会用自己的服务来装饰现有的resharper服务,我可以用自己的解析器包装CSharpParser,并可能处理AST的最终解析?我会说非常幸运:)我不知道实际会发生什么,但如果它起作用,我会感到惊讶。ReSharper使AST和文档的文本保持同步-如果您更改其中一个,则其他内容也会更改。如果您更改了其中一个方面,我怀疑它会很好地结束。我怀疑编写一个使用控制流图的分析器会更容易(但仍然很重要)而且更有可能成功。但是,一半的乐趣在于尝试:)
if(ExperimentService.IsInVariant(ABTest.Test1) || true)
var val = ..... && (ExperimentService.IsInVariant(ABTest.Test1);
if(val){
  // val is always going to be false if we deployed control.
}