1

I'm using ICSharpCode.Decompiler.Ast.AstBuilder (which is used by SharpDevelop, NRefactory and ILSpy under the hood; has taken inspiration from there too) from code to build an abstract syntax tree from a .NET Common Intermediate Language assembly.

var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var astBuilder = new AstBuilder(new DecompilerContext(assembly.MainModule));
astBuilder.AddAssembly(assembly);
// astBuilder.SyntaxTree ...

The syntax tree contains TypeReferenceExpressions whenever a line like Math.Abs() is there. How can I retrieve the TypeDeclaration of the referenced type when it also exists in the same syntax tree?

The closest I got is TypeReferenceExpression.Type.ToTypeReference().Resolve() but this is very heavy to orchestrate, and I already have (I suppose) all the information in the syntax tree. I also tried manual lookup by using namespaces an identifiers but I guess there should be a better way.

Piedone
  • 2,693
  • 2
  • 24
  • 43
  • Do you want the `TypeDeclaration` or `TypeDefinition`? Based on my recollection of those APIs, calling `Resolve()` as in your example produces the definition (metadata), not the declaration (AST node). – Mike Strobel Mar 24 '15 at 21:55
  • I'd like to access the TypeDeclaration (which is in the same syntax tree). But you're right that Resolve() returns metadata only so that's not really an option. – Piedone Mar 24 '15 at 23:10

1 Answers1

3

You can use SyntaxTree.GetTypes() to enumerate all decompiled types. Since that's rather heavy, I'd build up a reference-to-declaration lookup, e.g.:

var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var astBuilder = new AstBuilder(new DecompilerContext(assembly.MainModule));

astBuilder.AddAssembly(assembly);

var ast = astBuilder.SyntaxTree;

var lookup = ast.GetTypes(true)
                .ToDictionary(d => (TypeReference)d.Annotation<TypeDefinition>());

You can then fetch the TypeReference from your TypeReferenceExpression and use it to find the type's declaration in the lookup:

TypeReferenceExpression e = /* ... */;
TypeDeclaration declaration;

if (lookup.TryGetValue(e.Type.Annotation<TypeReference>(), out declaration))
    Console.WriteLine(declaration.GetText());  // do whatever
Mike Strobel
  • 25,075
  • 57
  • 69
  • Nice, very clever, thank you! Didn't know about such annotations automatically added to nodes. – Piedone Mar 25 '15 at 21:01
  • It's worth noting that while this will work fine for types within the same assembly it won't find the type declaration once the referencing code is in a separate assembly (the TypeReference objects will differ). Changing the implementation to use the FullName as the key seems like a solution. – Piedone Mar 25 '15 at 21:40
  • Interesting. Using the full, assembly-qualified type name as the key might be the best solution then. You may need to compute it yourself, though--I don't recall whether `TypeReference` has a specific property to access the assembly-qualified name. – Mike Strobel Mar 26 '15 at 13:36
  • The FullName property is good enough in this use-case, although not bullet proof. – Piedone Mar 26 '15 at 16:47