12

Roslyn スクリプト/コードのステートメントを使用して (未使用) を並べ替えて削除しますか? プロジェクト全体で実行し、未使用の using ステートメントを並べ替えて削除できる .NET/Roslyn (サービスとしてのコンパイラ) コードを探しています。これはRoslynで可能だと思いますか? この書き換えを実行できるコードを教えてもらえますか?

4

5 に答える 5

10

これは Visual Studio の機能ですが、学問的には、次のように SyntaxTree から using ステートメントを収集すると思います。

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();
于 2012-04-02T20:21:50.073 に答える
4

Roslyn CTP September 2012 は、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;
}
于 2013-07-16T12:52:46.160 に答える
2

私はこれを次の拡張メソッドを使用して、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))
于 2015-12-03T10:19:13.453 に答える
1

Roslyn に付属の OrganizeSolution サンプル プロジェクトを確認してください。それはあなたが望むものと同様のことをします。ソート部分を行います。ソースに特定の名前空間への参照がないかどうかを判断するには、Jeff が示すように SemanticModel も使用する必要があります。

于 2012-04-03T22:46:05.757 に答える
0

ステートメントを削除するには、次のディレクトリにあるソリューションの FAQ 項目 30 を確認してください。

%userprofile%\Documents\Microsoft Roslyn 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;
    }
}
于 2012-07-15T12:53:32.997 に答える