在Flutter/Dart中使用SimpleElementVisitor获取接口及方法体的问题求助
在Flutter/Dart中使用SimpleElementVisitor获取接口及方法体的问题求助
Hey,我之前在做source_gen代码生成的时候也碰到过类似的坑,给你梳理下具体的解决方案:
一、为什么visitClassElement完全没执行?
大概率是你的Visitor没有从ClassElement节点开始遍历!看你的代码,目前只处理了ConstructorElement,但如果你的Generator入口没有先拿到目标类的ClassElement并调用它的accept方法,那visitClassElement自然不会被触发。
给你两种修正思路:
- 从ClassElement开始遍历(推荐)
在你的Generator里,先匹配到带注解的ClassElement,再调用它的accept方法触发Visitor的遍历:
class YourGenerator extends GeneratorForAnnotation<YourAnnotation> { @override String generateForAnnotatedElement(Element element, ConstantReader annotation, BuildStep buildStep) { if (element is ClassElement) { final visitor = YourSimpleVisitor(); element.accept(visitor); // 这一步才会触发visitClassElement // 后续用visitor收集的数据生成代码 } return ''; } }
- 从ConstructorElement向上关联ClassElement
如果你的入口只能拿到ConstructorElement,也可以通过enclosingElement获取它所属的类,再手动触发遍历:
@override void visitConstructorElement(ConstructorElement element) { final classElement = element.enclosingElement as ClassElement; classElement.accept(this); // 触发visitClassElement // 你的原有逻辑:获取类名等 final returnType = element.returnType.toString(); className = returnType.replaceFirst('*', ''); }
二、正确获取第一个接口名称
当visitClassElement正常执行后,element.interfaces返回的是List<InterfaceType>对象列表,不是直接的字符串,所以你需要用getDisplayString方法转换为可读的接口名称:
@override void visitClassElement(ClassElement element) { if (element.interfaces.isNotEmpty) { // withNullability控制是否显示可空标记,按需调整 firstInterfaceName = element.interfaces.first.getDisplayString(withNullability: false); } }
三、获取方法体的源代码
这个确实有点棘手,因为MethodElement本身不会直接提供源代码字符串——source_gen是基于编译分析阶段的元素信息,而非原始源码。不过可以借助package:analyzer的AST API来实现:
步骤大概是这样:
- 在Generator中通过
buildStep.resolver获取目标类所在的编译单元(CompilationUnit):
final library = await buildStep.resolver.libraryFor(element.library!); final unit = library.unit;
- 遍历编译单元的节点,找到目标类,再提取它的方法体:
for (final declaration in unit.declarations) { if (declaration is ClassDeclaration && declaration.name.identifier == element.name) { for (final classMember in declaration.members) { if (classMember is MethodDeclaration) { // 这里拿到的就是方法体的原始源代码 final methodBodySource = classMember.body.toSource(); print(methodBodySource); } } } }
注意:这种方式只适用于当前类中定义的方法,如果是继承来的方法,在当前类的AST中是找不到的,需要额外处理继承链的逻辑。
备注:内容来源于stack exchange,提问作者Valentin Rupp
相关产品推荐
相关产品推荐

