我正在编写一个系统来处理作为Noda Time的单元测试编写的代码片段,因此我可以在文档中包含这些片段。我有一个第一关工作,但我想整理代码。在处理代码片段时,需要做的一件事是计算出该片段实际上需要哪些using指令。(一个源文件中可以有多个片段,但是每个代码段将单独出现在文档中--我不希望从一个代码段导入影响另一个片段。)
工作代码处理Document实例--每段代码创建一个单独的Document,其中包含单个方法和所有可能的导入,将其添加到项目中,然后删除不必要的using指令,如下所示:
private async static Task<Document> RemoveUnusedImportsAsync(Document document)
{
var compilation = await document.Project.GetCompilationAsync();
var tree = await document.GetSyntaxTreeAsync();
var root = tree.GetRoot();
var unusedImportNodes = compilation.GetDiagnostics()
.Where(d => d.Id == "CS8019")
.Where(d => d.Location?.SourceTree == tree)
.Select(d => root.FindNode(d.Location.SourceSpan))
.ToList();
return document.WithSyntaxRoot(
root.RemoveNodes(unusedImportNodes, SyntaxRemoveOptions.KeepNoTrivia));
}从那时起,我就知道在处理文档时我可以使用IOrganizeImportsService,但是我想把它写成一个Script,因为这样做在各种方面都要干净得多。
创建脚本很容易,所以我只想对未使用的导入进行分析(在前面的一些清理步骤之后)。下面是我希望对脚本有用的代码:
private static Script RemoveUnusedImports(Script script)
{
var compilation = script.GetCompilation();
var tree = compilation.SyntaxTrees.Single();
var root = tree.GetRoot();
var unusedImportNodes = compilation.GetDiagnostics()
.Where(d => d.Id == "CS8019")
.Where(d => d.Location?.SourceTree == tree)
.Select(d => root.FindNode(d.Location.SourceSpan))
.ToList();
var newRoot = root.RemoveNodes(unusedImportNodes, SyntaxRemoveOptions.KeepNoTrivia);
return CSharpScript.Create(newRoot.ToFullString(), script.Options);
}不幸的是,这根本找不到任何诊断信息--它们只是没有在编译中生成:
下面是一个简短的示例应用程序,它演示了:
using System;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
class Program
{
static void Main(string[] args)
{
string text = @"
using System;
using System.Collections.Generic;
Console.WriteLine(""I only need to use System"");";
Script script = CSharpScript.Create(text);
// Not sure whether this *should* be required, but it doesn't help...
script.Compile();
var compilation = script.GetCompilation();
foreach (var d in compilation.GetDiagnostics())
{
Console.WriteLine($"{d.Id}: {d.GetMessage()}");
}
}
}所需的软件包: Microsoft.CodeAnalysis.CSharp.Scripting (例如v2.1.0)
这不会产生任何输出:(
我猜想这是有意的,因为脚本通常有不同的用例。但是,是否有任何方法为脚本目的启用更多的诊断?或者,是否有其他方法来检测Script中未使用的导入?如果没有,我将回到我的Document-based方法--这将是一个遗憾,因为其他一切似乎都与脚本很好地工作在一起……
发布于 2017-05-18 22:23:57
据我所知,脚本引擎中的默认编译只为语法错误配置诊断信息。不幸的是,脚本引擎只有有限的选项可以自己配置底层编译。
但是,您可能可以通过跳过脚本引擎并直接自己创建编译来实现您所追求的目标。这本质上就是脚本主机在幕后所做的工作,增加了编译的一些缺省值,以及一些花哨的东西,比如提升类声明。跳过脚本主机并自己创建编译的代码如下所示:
using System;
using System.IO;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
class Program
{
static void Main(string[] args)
{
string text = @"
using System;
using System.Collections.Generic;
Console.WriteLine(""I only need to use System"");";
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(text, new CSharpParseOptions(kind: SourceCodeKind.Script));
var coreDir = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);
var mscorlib = MetadataReference.CreateFromFile(Path.Combine(coreDir, "mscorlib.dll"));
var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create("MyAssembly")
.AddSyntaxTrees(syntaxTree)
.AddReferences(mscorlib)
.WithOptions(options);
foreach (var d in compilation.GetDiagnostics())
{
Console.WriteLine($"{d.Id}: {d.GetMessage()}");
}
}
}您会注意到,这会产生一些关于缺少引用的不受欢迎的诊断信息--编译引用需要稍加调整才能包含默认库(您可以看到上面使用mscorlib的模式)。您还应该看到所需的未使用语句的诊断信息。
https://stackoverflow.com/questions/44058243
复制相似问题