C# 使用预处理器指令解析和生成代码
我正在用roslyn做实验,解析并生成c代码。我试图弄清楚CSharpSyntaxTree.ParseText方法如何处理预处理器符号 这是我的测试方法。它将一些C代码作为字符串接收,提取using语句并返回一个新字符串,其中包含那些using语句,同时考虑预处理器指令C# 使用预处理器指令解析和生成代码,c#,roslyn,C#,Roslyn,我正在用roslyn做实验,解析并生成c代码。我试图弄清楚CSharpSyntaxTree.ParseText方法如何处理预处理器符号 这是我的测试方法。它将一些C代码作为字符串接收,提取using语句并返回一个新字符串,其中包含那些using语句,同时考虑预处理器指令 private static string Process(string input, string[] preprocessorSymbols) { var options = CSharpParseOptions.D
private static string Process(string input, string[] preprocessorSymbols)
{
var options = CSharpParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbols);
var syntaxTree = CSharpSyntaxTree.ParseText(input, options);
var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
var usings = compilationUnit.Usings.ToArray();
var cs = SyntaxFactory.CompilationUnit()
.AddUsings(usings)
.NormalizeWhitespace();
var result = cs.ToString();
return result;
}
当使用以下输入输入此方法时,它将按预期工作:
var input = "using MyUsing1;\r\nusing MyUsing2;";
string result = Process(input, new[] { "" });
Assert.AreEqual("using MyUsing1;\r\nusing MyUsing2;", result);
当添加预处理器指令,但不将所述指令传递给解析器时,结果仍然是预期的条件语句,using语句被剥离:
var input =
"using MyUsing1;\r\n" +
"#if CONDITIONAL\r\n" +
"using MyUsing2;\r\n" +
"#endif";
string result = Process(input, new[] { "" });
Assert.AreEqual("using MyUsing1;", result);
然而,当将条件预处理器指令添加到CSharpParseOptions时,我得到了一个奇怪的结果
var input =
"using MyUsing1;\r\n" +
"#if CONDITIONAL\r\n" +
"using MyUsing2;\r\n" +
"#endif";
string result = Process(input, new[] { "CONDITIONAL" });
Assert.AreEqual("using MyUsing1;\r\nusing MyUsing2;", result); // fails??
实际返回值使用MyUsing1\r\n如果有条件\r\n使用MyUsing2;。保留if条件部分,删除endif
这是一个bug,还是我做错了什么?在试图理解这种行为时,我添加了另一个要考虑的测试用例:
var input =
"using MyUsing1;\r\n" +
"#if CONDITIONAL\r\n" +
"using MyUsing2;\r\n" +
"#endif" +
"using MyUsing3;\r\n";
string result = Process(input, new[] { "CONDITIONAL" });
在这种情况下,if和endif都被保留
如果中断调试器并查看usings数组,则每个UsingDirectiveSyntax似乎都知道using语句Span的最小字符范围,以及原始流FullSpan中更大范围的字符,在本例中,原始流FullSpan包括If指令等
再深入一点,文档引用了前面的代码,比如preproc指令,作为主要的琐事,它作为子节点附加到using节点
有趣的是,如果您只传递using指令中的一个,那么它似乎忽略了主要的琐事;但是如果你给它一个多个usingdirectivesyntax的数组,那么除了第一个之外,每个数组都包含了主要的琐事。这可能并不完全正确;我只是从黑匣子观察工作
我不会假装理解这种行为的原因。结果是,许多看起来正常的代码位(如您的示例)将产生令人不安的输出。如果传入新[]{usings[0]、usings[2]、usings[1]},则会得到更糟糕的输出,其中endif在If之前。但是你知道的。。。我想你为什么要这么做
因此,如果您想使用这些工具生成源代码并反馈到完整的构建管道中,您可以将其视为一个bug,或者至少是一个很容易成为bug来源的奇怪行为。如果有一个预期的用法可以让您远离这一点,我找不到直接的文档。在这种情况下,您可以在将using添加到输出之前删除using中的琐事;但在其他情况下,我认为这可能会丢失您想要保留的内容。您看过了吗,它可以显示脚本的语法树。谢谢您的帮助。同时,通过重读,结果证明指令是“琐事”,总是与下一行关联。对于这个用例来说很奇怪,但我想它是按照设计工作的。。。