【发布时间】:2012-04-12 10:16:17
【问题描述】:
使用语句 Roslyn 脚本/代码排序和删除(未使用)?我正在寻找一些可以在项目中运行并对未使用的 using 语句进行排序和删除的 .NET/Roslyn(编译器即服务)代码。我相信罗斯林有可能吗?谁能指点我可以重写的代码?
【问题讨论】:
标签: c# compiler-construction refactoring roslyn
使用语句 Roslyn 脚本/代码排序和删除(未使用)?我正在寻找一些可以在项目中运行并对未使用的 using 语句进行排序和删除的 .NET/Roslyn(编译器即服务)代码。我相信罗斯林有可能吗?谁能指点我可以重写的代码?
【问题讨论】:
标签: c# compiler-construction refactoring roslyn
我使用这个下面的扩展方法来排序 usings
internal static SyntaxList<UsingDirectiveSyntax> Sort(this SyntaxList<UsingDirectiveSyntax> usingDirectives, bool placeSystemNamespaceFirst = false) =>
SyntaxFactory.List(
usingDirectives
.OrderBy(x => x.StaticKeyword.IsKind(SyntaxKind.StaticKeyword) ? 1 : x.Alias == null ? 0 : 2)
.ThenBy(x => x.Alias?.ToString())
.ThenByDescending(x => placeSystemNamespaceFirst && x.Name.ToString().StartsWith(nameof(System) + "."))
.ThenBy(x => x.Name.ToString()));
和
compilationUnit = compilationUnit.WithUsings(SortUsings(compilationUnit.Usings))
【讨论】:
Roslyn CTP 2012 年 9 月提供了一个 GetUnusedImportDirectives() 方法,在这里非常有用。
通过修改 Matt 引用的 OrganizeSolution 示例项目,您可以使用指令实现(未使用)的排序和删除。可以在此处找到该项目的(过时)版本:http://go.microsoft.com/fwlink/?LinkId=263977。它已经过时了,因为
document.GetUpdatedDocument() 不存在了,
var document = newSolution.GetDocument(documentId);
var transformation = document.OrganizeImports();
var newDocument = transformation.GetUpdatedDocument();
可以简化为
var document = newSolution.GetDocument(documentId);
var newDocument = document.OrganizeImports();
添加newDocument = RemoveUnusedImportDirectives(newDocument); 并提供以下方法即可解决问题。
private static IDocument RemoveUnusedImportDirectives(IDocument document)
{
var root = document.GetSyntaxRoot();
var semanticModel = document.GetSemanticModel();
// An IDocument can refer to both a CSharp as well as a VisualBasic source file.
// Therefore we need to distinguish those cases and provide appropriate casts.
// Since the question was tagged c# only the CSharp way is provided.
switch (document.LanguageServices.Language)
{
case LanguageNames.CSharp:
var oldUsings = ((CompilationUnitSyntax)root).Usings;
var unusedUsings = ((SemanticModel)semanticModel).GetUnusedImportDirectives();
var newUsings = Syntax.List(oldUsings.Where(item => !unusedUsings.Contains(item)));
root = ((CompilationUnitSyntax)root).WithUsings(newUsings);
document = document.UpdateSyntaxRoot(root);
break;
case LanguageNames.VisualBasic:
// TODO
break;
}
return document;
}
【讨论】:
要删除语句,请查看 FAQ.cs 文件中以下目录中解决方案中的常见问题解答项目 30:(请注意,这是针对 Roslyn 的 2012 年 6 月 CTP 版本)。
%userprofile%\Documents\Microsoft Roslyn CTP - 2012 年 6 月\CSharp\APISampleUnitTestsCS
还有一个关于这个项目的常见问题解答:
http://www.codeplex.com/Download?ProjectName=dlr&DownloadId=386858
这是示例代码中的示例重写器,它删除了赋值语句。
// Below SyntaxRewriter removes multiple assignement statements from under the
// SyntaxNode being visited.
public class AssignmentStatementRemover : SyntaxRewriter
{
public override SyntaxNode VisitExpressionStatement(ExpressionStatementSyntax node)
{
SyntaxNode updatedNode = base.VisitExpressionStatement(node);
if (node.Expression.Kind == SyntaxKind.AssignExpression)
{
if (node.Parent.Kind == SyntaxKind.Block)
{
// There is a parent block so it is ok to remove the statement completely.
updatedNode = null;
}
else
{
// The parent context is some statement like an if statement without a block.
// Return an empty statement.
updatedNode = Syntax.EmptyStatement()
.WithLeadingTrivia(updatedNode.GetLeadingTrivia())
.WithTrailingTrivia(updatedNode.GetTrailingTrivia());
}
}
return updatedNode;
}
}
【讨论】:
查看 Roslyn 附带的 OrganizeSolution 示例项目。它做的事情类似于你想要的。它执行排序部分。您还必须使用 Jeff 展示的 SemanticModel 来确定源中是否没有对特定命名空间的引用。
【讨论】:
这是 Visual Studio 中的一项功能,但在学术上我认为您会使用 SyntaxTree 中的语句来收集,如下所示:
var usings = syntaxTree.Root.DescendentNodes().Where(node is UsingDirectiveSyntax);
...并将其与符号表解析的命名空间进行比较,如下所示:
private static IEnumerable<INamespaceSymbol> GetNamespaceSymbol(ISymbol symbol)
{
if (symbol != null && symbol.ContainingNamespace != null)
yield return symbol.ContainingNamespace;
}
var ns = semanticModel.SyntaxTree.Root.DescendentNodes().SelectMany(node =>
GetNamespaceSymbol(semanticModel.GetSemanticInfo(node).Symbol)).Distinct();
【讨论】:
Microsoft.CodeAnalysis.CSharp.CSharpSemanticModel 没有方法 GetSemanticInfo。它的现代等价物是什么?