Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get type from property with Roslyn

Tags:

c#

roslyn

Using Roslyn I'm trying to interpret some code that looks something like this:

public class Foo
{
    public override Type BarType
    {
        get { return typeof(MyBar); }
    }
}

What I would like to do is get MyBar and then get that type as a symbol, but I'm not sure if this is even something that is possible or practical to do. I'm going to have several classes that look like this and all derive from a base class.

Given the ClassDeclarationSyntax for Foo, I can do this:

var prop = syntax.DescendantNodes().OfType<PropertyDeclarationSyntax>()
              .FirstOrDefault(p => p.Identifier.ToString() == "BarType");

Or given the INamedTypeSymbol for Foo, I can do this:

var member = symbol.GetMembers("BarType").FirstOrDefault();

But I don't know where to go from there.

Ultimately I want to be able to get the symbol for MyBar for further analysis, so maybe even getting the string "MyBar" isn't going to help because it's not fully qualified.

Any suggestions?

EDIT:

I'm getting a project and a compilation like this:

var workspace = MSBuildWorkspace.Create();
var project = workspace.OpenProjectAsync(projectPath).Result;
var compilation = project.GetCompilationAsync().Result;

compilation is a CSharpCompilation here. From there I do something like this:

foreach (var doc in project.Documents)
{
    Console.WriteLine($"Analyzing {doc.Name}");

    //var model = doc.GetSemanticModelAsync().Result;
    var tree = doc.GetSyntaxTreeAsync().Result;
    var root = tree.GetRoot();
    var model = compilation.GetSemanticModel(tree);
    var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();

    foreach (var syntax in classes)
    {
        var symbol = model.GetDeclaredSymbol(syntax);
        //... need to analyze properties in the class here...
    }
}

Either way I get model I end up with a SyntaxTreeSemanticModel which doesn't seem to have a GetTypeSymbol method.

like image 293
Matt Burland Avatar asked Oct 21 '25 15:10

Matt Burland


1 Answers

You should look for the ReturnStatementSyntax and TypeOfExpressionSyntax. This contains the type MyBar. With the SemanticModel you can get the SymbolInfo like this:

var classDeclarationSyntaxs = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach ( var classDeclarationSyntax in classDeclarationSyntaxs )
{
    var propertyDeclarationSyntaxs = classDeclarationSyntax.Members.OfType<PropertyDeclarationSyntax>();
    var barTypePropertyDeclarationSyntax = propertyDeclarationSyntaxs.FirstOrDefault( p => p.Identifier.Text == "BarType" );
    if ( barTypePropertyDeclarationSyntax != null )
    {
        var returnStatementSyntax = barTypePropertyDeclarationSyntax.DescendantNodes().OfType<ReturnStatementSyntax>().FirstOrDefault();
        if ( returnStatementSyntax != null )
        {
            var typeOfExpressionSyntax = returnStatementSyntax.ChildNodes().OfType<TypeOfExpressionSyntax>().FirstOrDefault();
            if ( typeOfExpressionSyntax != null )
            {
                var symbolInfo = semanticModel.GetSymbolInfo( typeOfExpressionSyntax.Type );
                var symbolInfoSymbol = symbolInfo.Symbol;
            }
        }
    }
}

You can also use a SyntaxWalker for this:

public class TypeOfSyntaxWalker : CSharpSyntaxWalker
{
    private readonly SemanticModel _semanticModel;

    public ISymbol SymbolInfoSymbol { get; private set; }

    public TypeOfSyntaxWalker( SemanticModel semanticModel )
    {
        _semanticModel = semanticModel;
    }

    public override void VisitTypeOfExpression( TypeOfExpressionSyntax typeOfExpressionSyntax )
    {
        var parent = typeOfExpressionSyntax.Parent;
        if ( parent.Kind() == SyntaxKind.ReturnStatement )
        {
            var propertyDeclarationSyntax = parent.FirstAncestorOrSelf<PropertyDeclarationSyntax>();
            if ( propertyDeclarationSyntax != null &&
                    propertyDeclarationSyntax.Identifier.ValueText == "BarType" )
            {
                var symbolInfo = _semanticModel.GetSymbolInfo( typeOfExpressionSyntax.Type );
                SymbolInfoSymbol = symbolInfo.Symbol;
            }
        }
        base.VisitTypeOfExpression( typeOfExpressionSyntax );
    }
}

Usage:

var classDeclarationSyntaxs = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach ( var classDeclarationSyntax in classDeclarationSyntaxs )
{
    var typeOfSyntaxWalker = new TypeOfSyntaxWalker( semanticModel );
    typeOfSyntaxWalker.VisitClassDeclaration( classDeclarationSyntax );
    var symbolInfoSymbol = typeOfSyntaxWalker.SymbolInfoSymbol;
}
like image 88
Sievajet Avatar answered Oct 23 '25 05:10

Sievajet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!