如何获取 MethodInvocation 的完全限定目标?

6

我正在尝试查找特定方法的用法。在这种情况下,我想查找foo.go()的用法/调用,但不包括bar.go()。以下代码将查找任何类上go()的所有调用。在下面的代码中,node.target仅给出变量名x,但我很难确定该方法属于哪个类。

test.dart

void main() {
  var x = new Foo();
  x.go();

  x = new Bar();
  x.go();
}

class Foo {
  go() {
    print('I am foo');
  }
}

class Bar {
  go() {
    print('I am bar');
  }
}

analyze.dart

import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';

void main() {
  var targetFile = parseDartFile('test.dart');
  var visitor    = new UsageVisitor('foo.go');
  targetFile.visitChildren(visitor);
}

class UsageVisitor extends UnifyingAstVisitor {
  String _class;
  String _method;

  UsageVisitor(this._class, this._method);

  @override
  visitMethodInvocation(MethodInvocation node) {
    print({
      'target'    : node.target.toString(),    // in both cases, gives "x" -- I need "Foo" and "Bar", respectively
      'methodName': node.methodName.toString() // gives "go"
    });

    return super.visitNode(node);
  }
}

如何在分析器级别上区分foo.go()bar.go()之间的差异?


2个回答

3
问题在于解析test.dart时缺少上下文信息,无法解析其中包含的元素。
其中一个例子可以在Dart SDK的分析器包中找到
将其分解为以下步骤:

1-设置解析器

PhysicalResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
DartSdk sdk = new FolderBasedDartSdk(resourceProvider, resourceProvider.getFolder(args[0]));

var resolvers = [
  new DartUriResolver(sdk),
  new ResourceUriResolver(resourceProvider)
];

2 - Create an AnalysisContext using the resolvers

AnalysisContext context = AnalysisEngine.instance.createAnalysisContext()
  ..sourceFactory = new SourceFactory(resolvers);

3 - 将您的添加到ChangeSet

Source source = new FileSource(resourceProvider.getFile(args[1]));
ChangeSet changeSet = new ChangeSet()..addedSource(source);

3.1 - 将ChangeSet应用于AnalysisContext

context.applyChanges(changeSet);

3.2 - 获取 LibraryElement

我不确定是否总是需要。对于简单的文件,可能可以跳过此步骤。 ¯(◉◡◔)/¯

LibraryElement libElement = context.computeLibraryElement(source);

4 - 解析你的源代码

CompilationUnit resolvedUnit = context.resolveCompilationUnit(source, libElement);

5 - 运行你的 Visitor

resolvedUnit.accept(visitor)

不幸的是,这比仅仅调用parseDartFile()要多得多的代码,但好消息是您的Visitor应该可以在没有进一步更改的情况下工作。

祝你好运!


这太棒了!正是我所需要的! - KOGI

1
我找到了一些东西,但我不熟悉分析器,也许可以简化它并且只适用于你的情况。
@override
visitMethodInvocation(MethodInvocation node) {
  if (node.methodName.toString() == "go" && node.target.toString() == "x") {
    for (dynamic child in node.parent?.parent?.childEntities) {
      if (child is VariableDeclarationStatement) {
        if ((child.childEntities.first as VariableDeclarationList).type.toString() == "Foo" &&
          ((child.childEntities.first as VariableDeclarationList).childEntities.elementAt(1) as VariableDeclaration)
                  .beginToken
                  .toString() ==
              "x") {
          print(node);
        }
      }
    }
  }
  return super.visitNode(node);
}

感谢您的努力,但是您说得对,这只适用于我非常简单的示例代码。一旦涉及到“真正”的(更复杂的)代码并引入if/else块、闭包、方法、类等,这种方法就变得不可行了。 - KOGI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接