9

I'm using source_gen to parse some Dart files, through the Dart analyzer.

I'm extending GeneratorForAnnotation<>, and overriding method FutureOr<String> generateForAnnotatedElement(Element element, ConstantReader annotation, BuildStep buildStep). This method gives me a base element, which I navigate until I find some other element, say a MethodElement.

Once I get hold of this MethodElement, I want to analyze the method's block, in detail. I'd like something like this:

AstNode node = methodElement.computeNode();

In more detail:

class MyGenerator extends GeneratorForAnnotation<MyAnnotation> {

    @override
    FutureOr<String> generateForAnnotatedElement(
        Element element, ConstantReader annotation, BuildStep buildStep,
    ) {
      if (element is ClassElement)
        for (MethodElement methodElement in element.methods) {
          AstNode node = methodElement.computeNode();
          processMyNode(node);
        }
      else
        throw AssertionError();
    }
}

Unfortunately, computeNode is deprecated. If I try to call it, I get:

NoSuchMethodError: Class 'RestrictedAnalysisContext' has no instance method 'resolveCompilationUnit' with matching arguments.
Receiver: Instance of 'RestrictedAnalysisContext'
Tried calling: resolveCompilationUnit(Instance of 'FileSource', Instance of 'LibraryElementImpl')
Found: resolveCompilationUnit(Source, LibraryElement) => CompilationUnit

My question: How can I get the AstNode?

Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133

2 Answers2

11

Got it:

AstNode getAstNodeFromElement(Element element) {
  AnalysisSession session = element.session;
  ParsedLibraryResult parsedLibResult = session.getParsedLibraryByElement(element.library);
  ElementDeclarationResult elDeclarationResult = parsedLibResult.getElementDeclaration(element);
  return elDeclarationResult.node;
}
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
  • 2
    You can also use [`NodeLocator`](https://github.com/dart-lang/sdk/blob/b8c5ecd5aaecf0a70794d344bfdf5a3064e3bb12/pkg/analyzer/lib/src/dart/ast/utilities.dart#L2444) or [`NodeLocator2`](https://github.com/dart-lang/sdk/blob/b8c5ecd5aaecf0a70794d344bfdf5a3064e3bb12/pkg/analyzer/lib/src/dart/ast/utilities.dart#L2537), from the `analyzer` package. For some reason it's not exported to the API documentation, but it's very useful. There's also a counterpart called `ElementLocator` that does the opposite: get an `Element` from an `AstNode`. – Mateus Felipe May 17 '21 at 09:27
2

While MarcG's solution works for most elements, it does not work for the root LibraryElements themselves.

To get the AstNode (or, more specifically, a CompilationUnit) for a LibraryElement's defining CompilationUnitElement, the following can be done:

final libraryCompilationUnit = (libraryElement.session
        .getParsedLibraryByElement(libraryElement) as ParsedLibraryResult)
    .units[0]
    .unit;

hacker1024
  • 3,186
  • 1
  • 11
  • 31