【发布时间】:2021-02-21 22:50:13
【问题描述】:
Resharper 的 cleanupcode.exe 工具似乎不知道这样做。
也许其他一些工具可以,但我没有找到任何工具。
到目前为止,尝试使用 Roslyn SemanticModel 自己做这件事还没有成功,因为我不知道模型需要什么样的处理,也找不到相关文档(或错过了)。
所以,问题是 - 是否有一种工具可以识别实际使用的命名空间,或者甚至可以立即从给定的源文件中删除多余的 using 指令?关于如何处理语义模型的想法也很受欢迎。
编辑 1
考虑以下 C# 源代码:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace CSTool.Tests.Input
{
public class Sample
{
public void Func()
{
static ICollection<ArrayList> action(string _) => null;
Console.WriteLine(action(Directory.GetFiles(Directory.GetCurrentDirectory()).FirstOrDefault())?.Count);
}
}
}
那么,我怎样才能确认 using 指令都是必需的呢?我尝试了以下代码:
private static IEnumerable<string> GetNamespaceSymbol(ISymbol symbol)
{
if (symbol != null && symbol.ContainingNamespace != null)
{
yield return symbol.ContainingNamespace.Name;
}
}
public static HashSet<string> Run(CSharpCompilation compilation, SyntaxTree tree)
{
var semanticModel = compilation.GetSemanticModel(tree);
return tree.GetRoot().DescendantNodes().SelectMany(node =>
GetNamespaceSymbol(semanticModel.GetSymbolInfo(node).Symbol)).ToHashSet();
}
但它返回以下无意义的结果 - {"", "CSTool", "System", "Tests"}
根本不需要。
我被指出了以下问题 - https://stackoverflow.com/a/9983275/2501279。但显然自 2012 年以来发生了很大变化,而今天的答案没有任何意义。至少对我来说。
编辑 2
这是我获得树和编译对象的方法:
public List<string> Test(string text, Type[] types)
{
var tree = CSharpSyntaxTree.ParseText(text);
var compilation = CSharpCompilation
.Create("test")
.AddReferences(types.Select(t => MetadataReference.CreateFromFile(t.Assembly.Location)))
.AddSyntaxTrees(tree);
return CleanupNamespacesCmd.Run(compilation, tree).OrderBy(ns => ns).ToList();
}
编辑 3
所以,我尝试了新方法。代码如下:
public static void Run(string projectFilePath)
{
var project = new Project(projectFilePath);
var outDir = project.GetPropertyValue("OutDir");
using var a = AssemblyDefinition.ReadAssembly(project.GetPropertyValue("TargetPath"));
var trees = MapTypesCmd
.YieldCSFiles(project)
.Select(filePath => CSharpSyntaxTree.ParseText(File.ReadAllText(filePath), path: filePath));
var compilation = CSharpCompilation
.Create(project.GetPropertyValue("AssemblyName"))
.AddReferences(a.MainModule.AssemblyReferences.Select(CreateMetadataReference))
.AddSyntaxTrees(trees);
foreach (var tree in compilation.SyntaxTrees)
{
var model = compilation.GetSemanticModel(tree);
var diag = model.GetDiagnostics();
}
MetadataReference CreateMetadataReference(AssemblyNameReference asmRef)
{
var asm = a.MainModule.AssemblyResolver.Resolve(asmRef);
var path = asm.MainModule.FileName;
if (!Path.IsPathRooted(path))
{
path = outDir + asm.MainModule.Name;
}
return MetadataReference.CreateFromFile(path);
}
}
代码已经编译好了,所以我使用Mono.Cecil读取程序集引用列表,将它们转换为MetadataReferences,并在创建CSharpCompilation对象时使用。
但是,diag 数组包含虚假的诊断消息,例如这个 - C:\xyz\tip\DB\DL\Db\FilterDB.cs(25,24): error CS0518: Predefined type ' System.String' 未定义或导入
这太假了。监视窗口告诉我 compilation.References.First().Display 等于 C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.12\mscorlib.dll 并且正如我之前提到的 - 代码编译干净利落。
我做错了什么?
【问题讨论】:
-
你试过this回答吗?
-
我尝试了类似的方法,但并不完全如此。并错过了那个答案。我会检查并报告
-
没有骰子。
Microsoft.CodeAnalysis.CSharp.CSharpSemanticModel类没有方法GetSemanticInfo。