how to get type of identifier dart-analyzer

Issue

I am processing method statements in a class and i want to find type of an identifier in those statements.

import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:dstore/dstore.dart';
import 'package:dstore_generator/src/utils.dart';
import 'package:source_gen/source_gen.dart';

AstNode getAstNodeFromElement(Element element) {
  AnalysisSession session = element.session;
  ParsedLibraryResult parsedLibResult =
      session.getParsedLibraryByElement(element.library);
  ElementDeclarationResult elDeclarationResult =
      parsedLibResult.getElementDeclaration(element);
  return elDeclarationResult.node;
}

class SelectorsGenerator extends GeneratorForAnnotation<Selectors> {
  @override
  String generateForAnnotatedElement(
      Element element, ConstantReader annotation, BuildStep buildStep) {
    if (!(element is ClassElement)) {
      throw Exception("Selectors should be applied on class only");
    }
    final className = element.name;

    if (!className.startsWith("_")) {
      throw Exception("Selectors functions class should start with _");
    }
    final modelName = className.substring(1);
    final visitor = SelectorsVisitor(modelName);
    final astNode = getAstNodeFromElement(element);
    astNode.visitChildren(visitor);

    return """
       // Selector
       
    """;
  }
}

class SelectorsVisitor extends SimpleAstVisitor {
  final String modelName;
  final selectors = <String>[];

  SelectorsVisitor(this.modelName);

  @override
  dynamic visitMethodDeclaration(MethodDeclaration node) {
    final fields = convertParamsToFields(node.parameters);
    if (fields.isEmpty || fields.length > 1) {
      throw Exception(
          "Selector functions should be only one param with app state");
    }
    final field = fields.first;
    var name = node.name.toString();
    if (node.returnType == null) {
      throw Exception("You sould annontate return type of method ${name} ");
    }
    final rType = node.returnType.toString();
    final sType = field.type;
    final bvs = SelectorBodyVisitor(field.param!.identifier);
    node.body.visitChildren(bvs);

    //  node.body.visitChildren(visitor)
    return super.visitMethodDeclaration(node);
  }
}

class SelectorBodyVisitor extends RecursiveAstVisitor {
  final Identifier identifier;

  final List<List<String>> depsList = [];

  SelectorBodyVisitor(this.identifier);
  List<String> getListOfPropAccess(PropertyAccess node) {
    final result = <String>[];
    final prop = node.propertyName.toString();
    result.add(prop);
    final target = node.target;
    print("target type ${target.runtimeType}");
    if (target is PropertyAccess) {
      result.addAll(getListOfPropAccess(target));
    } else if (target is PrefixedIdentifier) {
      if (target.prefix.toString() == identifier.toString()) {
        // I am trying to get identifier type here
        print("IdentifierElement2  ${target.identifier.staticType}");
        result.add(target.identifier.toString());
      } else {
        print("target is not identifier ${target.runtimeType} ${target}");
      }
    }
    return result;
  }

  @override
  dynamic visitPropertyAccess(PropertyAccess node) {
    print("***&&& propsAccess  ${node}");
    final list = getListOfPropAccess(node);
    final sa = node.toString().split(".").toList();
    if (sa.length - 1 == list.length) {
      // property access of state identifier
      depsList.add(list.reversed.toList().take(2).toList());
    }
    print("Property access list ++++=== ++++++ ${list}");
  }

  @override
  dynamic visitPrefixedIdentifier(PrefixedIdentifier node) {
    print(
        "**##### IdenAccess  ${node} id:  ${node.identifier} prefix : ${node.prefix} mid :${identifier.toString()}");
    if (node.prefix.toString() == identifier.toString()) {
      print("IdentifierElement1 ${node.identifier.staticType}");

      depsList.add([node.identifier.toString()]);
    } else {
      print("identifier is not equal ${node.prefix == identifier}");
    }
  }
}

Example

class User {
 final String name;
 User(this.name)
} 
class Model {

  final User user;
  Model(this.user)

}

@Selectors()
abstract class MySelectors {
  static s1(Model model) {
     final n = model.user.name; // i want to know type of name in code generation time , please check this line  print("IdentifierElement2  ${target.identifier.staticType}"); in above code , where i am getting null
     
   }
}

Solution

Found answer , I have to use getResolvedLibraryByElement instead of getParsedLibraryByElement in getAstNodeFromElement method.

Future<AstNode> getAstNodeFromElement(Element element) async {
  AnalysisSession session = element.session;

  final s = await session.getResolvedLibraryByElement(element.library);
  final s2 = s.getElementDeclaration(element);

  return s2.node;
}

Answered By – invariant

Answer Checked By – Clifford M. (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *