I'm trying to find usages of a particular method. In this case, I want to find usages/invocations of foo.go()
, but NOT bar.go()
. The below code will find all invocations of go()
on ANY class. In the code below, node.target
gives me simply x
which is the var name, but I'm struggling to figure out which class the method belongs to.
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');
}
}
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);
}
}
How do I tell the difference (at the analyzer level), between foo.go()
and bar.go()
?
The problem is that test.dart
is being parsed without context needed to resolve the elements contained within.
An example of this is included in the analyzer package within the Dart SDK
Breaking that down to its steps you have:
PhysicalResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
DartSdk sdk = new FolderBasedDartSdk(resourceProvider, resourceProvider.getFolder(args[0]));
var resolvers = [
new DartUriResolver(sdk),
new ResourceUriResolver(resourceProvider)
];
AnalysisContext
using the resolversAnalysisContext context = AnalysisEngine.instance.createAnalysisContext()
..sourceFactory = new SourceFactory(resolvers);
Source
to a ChangeSet
Source source = new FileSource(resourceProvider.getFile(args[1]));
ChangeSet changeSet = new ChangeSet()..addedSource(source);
ChangeSet
to the AnalysisContext
context.applyChanges(changeSet);
LibraryElement
I'm not certain if this is always needed. Maybe it can be skipped for simple files. ¯(◉◡◔)/¯
LibraryElement libElement = context.computeLibraryElement(source);
Source
!CompilationUnit resolvedUnit = context.resolveCompilationUnit(source, libElement);
Visitor
resolvedUnit.accept(visitor)
Unfortunately that's a lot more code than just calling parseDartFile()
but the good news is that your Visitor
should work without further changes.
Good luck!
I found something, but I am not used to the analyzer, maybe it can be simplify and it works only for you case.
@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 you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With