Get a list of referenced Types within a project with Roslyn

拥有回忆 提交于 2020-01-24 03:40:27

问题


I want to get a list of all used types in a project, for example:

var x = 1;
var y = x.ToString().GetType();

The code should return System.Int32, System.String, System.Type.

What I have is freaking slow... for each file (syntax tree), I do the following:

var root = await syntaxTree.GetRootAsync();
var nodes = root.DescendantNodes(n => true);

if (nodes != null)
{
    var syntaxNodes = nodes as SyntaxNode[] ?? nodes.ToArray();

    // IdentifierNameSyntax:
    //  - var keyword
    //  - identifiers of any kind (including type names)
    var namedTypes = syntaxNodes
        .OfType<IdentifierNameSyntax>()
        .Select(id => this.compilation
                  .GetSemanticModel(id.SyntaxTree)
                  .GetSymbolInfo(id)
                  .Symbol)
        .OfType<INamedTypeSymbol>()
        .ToArray();

    // add the found types to the list
    this.AddRange(namedTypes);

    // ExpressionSyntax:
    //  - method calls
    //  - property uses
    //  - field uses
    //  - all kinds of composite expressions
    var expressionSyntaxs = syntaxNodes
        .OfType<ExpressionSyntax>()
        .ToList();

    var typeSymbols = new List<ITypeSymbol>();
    for (int index = 0; index < expressionSyntaxs.Count; index++)
    {
        ExpressionSyntax ma = expressionSyntaxs[index];
        typeSymbols.Add(this.compilation
                    .GetSemanticModel(ma.SyntaxTree)
                    .GetTypeInfo(ma)
                    .Type);
    }

    var expressionTypes = typeSymbols
        .OfType<INamedTypeSymbol>()
        .ToArray();

    // add the found types to the list
    this.AddRange(expressionTypes);
}

Motivation:

I am making a tool that analyses a project, and tells what .Net framework versions support the given project (e.g. Portable .Net Frameworks).

I hoped it would be faster to match a set of used types with a set of available types from the framework, before compiling.

With small files this code is fast enough, and the total amount of time is less than that of compiling with every possible framework... but with a large files it is unacceptable.

Is there a way to get the list of types in a way that is acceptable?


回答1:


So, I've learnt a lesson: never assume that an immutable structure is going to cache any of it's calculations just because two calls would return the same result.

It is true that when the method is pure, the return is always the same structurally, but it doesn't have to be the same instance.

My assumption lead me to an error: thinking that this.compilation.GetSemanticModel(id.SyntaxTree) would always return the same instance of the semantic model for a given SyntaxTree... it's not true.

I changed my code to the following, and now it is blazing fast:

var root = await syntaxTree.GetRootAsync();
var nodes = root.DescendantNodes(n => true);

var st = root.SyntaxTree;
var sm = this.compilation.GetSemanticModel(st);

if (nodes != null)
{
    var syntaxNodes = nodes as SyntaxNode[] ?? nodes.ToArray();

    // IdentifierNameSyntax:
    //  - var keyword
    //  - identifiers of any kind (including type names)
    var namedTypes = syntaxNodes
        .OfType<IdentifierNameSyntax>()
        .Select(id => sm.GetSymbolInfo(id).Symbol)
        .OfType<INamedTypeSymbol>()
        .ToArray();

    this.Add(namedTypes);

    // ExpressionSyntax:
    //  - method calls
    //  - property uses
    //  - field uses
    //  - all kinds of composite expressions
    var expressionTypes = syntaxNodes
        .OfType<ExpressionSyntax>()
        .Select(ma => sm.GetTypeInfo(ma).Type)
        .OfType<INamedTypeSymbol>()
        .ToArray();

    this.Add(expressionTypes);
}


来源:https://stackoverflow.com/questions/29176579/get-a-list-of-referenced-types-within-a-project-with-roslyn

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!