使用Roslyn选择性地删除预处理程序指令

时间:2017-10-22 06:06:26

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

我想使用Roslyn来清理一些旧的预处理程序指令的代码。

例如,从此代码

#define TEST_1_0
#define TEST_1_1
namespace ConsoleApplication1
{
class TypeName
{   
   public static void Main(string[] args)
   {
#if TEST_1_0
        int TEST_1_0 = 1;
#if TEST_1_1
        int TEST_1_1 = 1;
#else//TEST_1_1
        int TEST_1_1 = 0;
#endif//TEST_1_1
#else//TEST_1_0
        int TEST_1_0 = 0;
#endif//TEST_1_0
    }
}
}

我想删除其他// TEST_1_0,但保留其他// TEST_1_1。我不能指望评论,所以我应该将#if与相应的#else相关联,如果有的话。

找到#if很容易,但找到相应的#else并不容易。

我尝试了两种策略:

  1. 这里我在分析器中查找#else // TEST_1_0,并为该位置创建一个codefix
  2. 这里我只是在分析器中为#if TEST_1_0创建一个codefix,并尝试从CodeFixprovider获取相应的else
  3. 两者都很快变得复杂,指令是琐事似乎有问题,这些琐事分布在不同SyntaxTokens的leadingTrivia上。代码中的更改会对位置指令产生相当大的影响,因此对所有情况进行编程看起来很多工作。

    我错过了什么吗?如果不手动编写所有不同的案例,是否有更简单的方法可以做到这一点?

    你会选择策略1还是2?

2 个答案:

答案 0 :(得分:3)

我同意Arjan - Roslyn无法完成任务。为了解决类似的任务,我基于regexp和Python sympy库创建了我自己的简单C#预处理器工具:undefine。我相信这对你有所帮助。至于您描述的任务,请尝试以下命令:

>> python undefine apply -d TEST_1_0 YourFile.cs

答案 1 :(得分:1)

我的结论是,罗斯林不是去这里的方式。

Roslyn将preprocesessor指令建模为语法树中的琐事,并且根据实际代码的结构,琐事的位置有很大的变化。

因此,在语法树上工作会引入查找复杂性,这在工作基于文本时不是问题,而更复杂意味着更多风险。二进制文件在处理之前/之后应该是相同的!

所以我选择放弃Roslyn并简单地将代码/指令混合解析为文本,使用正则表达式解析和旧的堆栈来处理指令逻辑。

现在它变得更容易,甚至是一块蛋糕...... 仍然需要处理一些编码问题,然后我就完成了! :) 快乐解析!