11

I have a CSharpCompilation instance containing an array of SyntaxTrees and I am trying to find all the class declarations that inherit from a class

e.g

// Not in syntax tree but referenced in project
public class Base{}

// In syntax tree, how to find all such classes?
public class MyClass : Base {}

I've tried a few things but am a bit confused with all the options and can't seem to find the right way to do this.

I've tried to get the symbols but this doesn't work for inherited types

SyntaxTree[] trees = context.CSharpCompilation.SyntaxTrees;
IEnumerable<ISymbol> symbols = context.CSharpCompilation.GetSymbolsWithName(x => x == typeof(Base).Name, SymbolFilter.Type);

Quite new to Roslyn and would be most grateful for any suggestions or pointers for how to achieve this.

Andry
  • 16,172
  • 27
  • 138
  • 246
Scott Mackay
  • 1,194
  • 10
  • 34

3 Answers3

7

First you'll need to get the symbol for Base. If this is a particular type you know about in advance, you can use Compilation.GetTypeByMetadataName for this. That link will also show you over 100 examples of that method in use.

From there, it depends on what you're trying to do. If you're doing this from inside an analyzer (which I suspect from the "context.CSharpCompilation" in your code), and you're trying to identify and then check some property of these derived types, you could use RegisterSymbolAction for SymbolKind.NamedType, and then check each type's BaseType (possibly recursively, depending on what you're trying to accomplish) to see if you find the type discovered by GetTypeByMetadataName above.

If you're doing solution-wide analysis outside the context of an analyzer, then there's a helper for this in the Roslyn codebase, but it's internal. There's an existing request to make ITypeSymbolExtensions public, so I've mentioned this thread in that request and suggested expanding it to include INamedTypeSymbolExtensions.

David Poeschl
  • 864
  • 4
  • 11
  • Thanks for this useful info, will research more. Actually I'm doing this inside a SyntaxRewriter and after a few hours of pain have come up with a method which is probably naive and your info will show me a much better way. Have included the code in another answer rather than comments – Scott Mackay Jan 31 '15 at 01:46
  • 3
    Links are dead. It would have been nice to include the relevant example. – Dave Hillier Oct 29 '20 at 09:37
  • 1
    link is dead -1 – David Sep 02 '21 at 16:42
  • 1
    . . . . . . . . R.I.P. . . . . . . . . – Frank Nov 20 '21 at 08:12
4

So I came up with the following which will recursively check all classes for the inherited type

public class BaseClassRewriter : CSharpSyntaxRewriter
{
    private readonly SemanticModel _model;

    public BaseClassRewriter(SemanticModel model)
    {
        _model = model;
    }

    public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        var symbol = _model.GetDeclaredSymbol(node);
        if (InheritsFrom<BaseClass>(symbol))
        {
            // hit!
        }
    }

    private bool InheritsFrom<T>(INamedTypeSymbol symbol)
    {
        while (true)
        {
            if (symbol.ToString() == typeof(T).FullName)
            {
                return true;
            }
            if (symbol.BaseType != null)
            {
                symbol = symbol.BaseType;
                continue;
            }
            break;
        }
        return false;
    }
}
Scott Mackay
  • 1,194
  • 10
  • 34
  • You don't handle generics. Look at http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ITypeSymbolExtensions.cs,310 – SLaks Feb 01 '15 at 00:06
  • Thanks for that, the extensions for ITypeSymbol and INamedTypeSymbol look useful but are internal at the moment. I've checked my use case for this code and fortunately I do not need to worry about generics as for my purposes at least, the base class I'm looking for is never generic. – Scott Mackay Feb 01 '15 at 12:08
  • What you can do is expose them in your project and make them private. I can't exactly tell you how but back at my old job this winter, we use those classes for analysis – Kevin Avignon Oct 26 '15 at 11:55
1
var classDecSynList = classDecSynList.Where(x=>
       (((IdentifierNameSyntax(x.BaseList.Types.FirstOrDefault()))
              .Identifier.ValueText=="Base"));

Assuming you have all the class declaration Syntax list;

Ankur Ghelani
  • 659
  • 4
  • 16