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

时间:2017-01-16 21:38:26

标签: dart abstract-syntax-tree static-analysis

我试图找到特定方法的用法。在这种情况下,我想查找foo.go()的使用/调用,但不是bar.go()。以下代码将在任何类上查找go()的所有调用。在下面的代码中,node.target只给我x这是var名称,但我正在努力弄清楚该方法属于哪个类。

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 个答案:

答案 0 :(得分:2)

问题是<input type="file" name="files[]" multiple="multiple" /> 正在解析而没有上下文来解析其中包含的元素。

analyzer package within the Dart SDK

中包含了一个例子

将其分解为您的步骤:

1 - 设置解析器

test.dart

2 - 使用解析器

创建PhysicalResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; DartSdk sdk = new FolderBasedDartSdk(resourceProvider, resourceProvider.getFolder(args[0])); var resolvers = [ new DartUriResolver(sdk), new ResourceUriResolver(resourceProvider) ];
AnalysisContext

3 - 将您的AnalysisContext context = AnalysisEngine.instance.createAnalysisContext() ..sourceFactory = new SourceFactory(resolvers); 添加到Source

ChangeSet

3.1 - 将Source source = new FileSource(resourceProvider.getFile(args[1])); ChangeSet changeSet = new ChangeSet()..addedSource(source); 应用于ChangeSet

AnalysisContext

3.2 - 获取context.applyChanges(changeSet);

我不确定是否总是需要它。也许它可以跳过简单的文件。¯(◉◡◔)/¯

LibraryElement

4 - 解析你的LibraryElement libElement = context.computeLibraryElement(source);

Source

5 - 运行CompilationUnit resolvedUnit = context.resolveCompilationUnit(source, libElement);

Visitor

不幸的是,很多代码而不是仅仅调用resolvedUnit.accept(visitor) ,但好消息是您的parseDartFile()应该无需进一步更改即可使用。

祝你好运!

答案 1 :(得分: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);
}