2012-03-28 57 views
7

使用語句排序和刪除(未使用)Roslyn腳本/代碼?我正在尋找一些.NET/Roslyn(編譯器作爲服務)代碼,它們可以運行一個項目並對未使用的使用語句進行排序和刪除。我相信Roslyn可以做到這一點?任何人都可以指向我可以做這個重寫的代碼嗎?使用語句排序並刪除(未使用)Roslyn腳本/代碼?

回答

5

這是在Visual Studio中的功能,但在學術上我想你會收集using語句從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(); 
+1

可以使用 「().OfType」 而不是」。凡排序(節點是UsingDirectiveSyntax)「 – 2016-08-30 23:29:56

1

查看Roslyn附帶的OrganizeSolution示例項目。它做了類似於你想要的東西。它做排序的一部分。您還必須使用像Jeff所示的SemanticModel來確定是否沒有對源中特定名稱空間的引用。

0

要刪除語句,請查看FAQ.cs文件中以下目錄中解決方案中的常見問題解答項目30 :(注意這是2012年6月CTP版本的Roslyn)。

%USERPROFILE%\文件\微軟羅斯林CTP - 2012年6月\ CSHARP \ APISampleUnitTestsCS

還有它是指這個項目FAQ:

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

Roslyn CTP 2012年9月提供了一個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; 
} 
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))