使用Roslyn脚本/代码语句对(未使用的)进行排序和删除

本文关键字:排序 删除 未使用 脚本 Roslyn 代码 语句 使用 | 更新日期: 2023-09-27 18:29:13

使用Roslyn脚本/代码语句对(未使用的)进行排序和删除?我正在寻找一些.NET/Roslyn(编译器即服务)代码,这些代码可以在项目中运行,并对未使用的using语句进行排序和删除。我相信这对罗斯林来说是可能的?有人能给我指一下可以重写的代码吗?

使用Roslyn脚本/代码语句对(未使用的)进行排序和删除

这是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();

Roslyn CTP September 2012提供了一个GetUnusedImportDirectives()方法,在这里非常有用。

通过修改马特引用的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;
}

我使用以下扩展方法使用进行排序

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附带的OrganizeSolution示例项目。它做的事情与你想要的类似。它完成排序部分。您还必须使用Jeff展示的SemanticModel来确定源中是否没有对特定命名空间的引用。

要删除语句,请在以下目录的FAQ.cs文件中查看解决方案中的常见问题解答项目30:(请注意,这适用于2012年6月的Roslyn CTP版本)。

%userprofile%''Documents''Microsoft Roslyn CTP-2012年6月''CSharp''APISampleUnitTestsCS

还有一个关于这个项目的常见问题解答:

http://www.codeplex.com/Download?ProjectName=dlr&下载Id=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;
    }
}