【问题标题】:Sort and remove (unused) using statements Roslyn script/code?使用语句 Roslyn 脚本/代码排序和删除(未使用)?
【发布时间】:2012-04-12 10:16:17
【问题描述】:

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

【问题讨论】:

    标签: c# compiler-construction refactoring roslyn


    【解决方案1】:

    我使用这个下面的扩展方法来排序 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))
    

    【讨论】:

      【解决方案2】:

      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;
      }
      

      【讨论】:

      • RemoveUnusedImportDirectives 方法是否进入了最终版本?我没看到。
      【解决方案3】:

      要删除语句,请查看 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;
          }
      }
      

      【讨论】:

        【解决方案4】:

        查看 Roslyn 附带的 OrganizeSolution 示例项目。它做的事情类似于你想要的。它执行排序部分。您还必须使用 Jeff 展示的 SemanticModel 来确定源中是否没有对特定命名空间的引用。

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 你可以使用“.OfType()”代替“.Where(node is UsingDirectiveSyntax)”
          • Microsoft.CodeAnalysis.CSharp.CSharpSemanticModel 没有方法 GetSemanticInfo。它的现代等价物是什么?
          猜你喜欢
          • 2015-09-06
          • 2020-12-08
          • 2015-03-06
          • 1970-01-01
          • 2015-08-14
          • 2017-06-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多