Find Dart Calls by Callee Name
Description
A standalone Dart pattern such as targetFn($$$ARGS) can be parsed as a function signature instead of a call expression. This rule avoids that ambiguity and finds common call forms whose syntactic callee is the exact identifier targetFn.
It covers direct, member, null-aware, generic, nested, parenthesized, null-asserted, common single-level sync or async arrow-body, and direct cascade calls. It does not match tear-offs, comments, strings, explicit new or const constructor expressions, operators, or indirect invocations whose callee is not syntactically named targetFn.
Copy the YAML into find-dart-calls-by-name.yml, replace every occurrence of targetFn with the simple Dart identifier you need, and run:
ast-grep scan --rule find-dart-calls-by-name.yml lib testYAML
id: find-dart-calls-by-name
message: Call to targetFn
severity: hint
language: dart
rule:
any:
# Ordinary, member, null-aware, generic, nested, parenthesized, and
# null-asserted calls.
- all:
- kind: call_expression
- has:
field: function
stopBy: neighbor
all:
- regex: '(?s)^(?:.*\.)?(?:\s|\(|/\*.*?\*/|//[^\n]*(?:\n|$))*targetFn(?:\s|/\*.*?\*/|//[^\n]*(?:\n|$))*(?:<.*>)?(?:\s|\)|!)*$'
- not:
kind: function_expression
- not:
has:
kind: function_expression
stopBy: end
# tree-sitter-dart represents a direct arrow-body call as a call_expression
# whose function field contains the enclosing function expression.
- all:
- kind: call_expression
- has:
field: function
stopBy: neighbor
all:
- regex: '(?s)^.*=>(?:\s|\(|/\*.*?\*/|//[^\n]*(?:\n|$)|await\b)*(?:.*\.)?targetFn(?:\s|/\*.*?\*/|//[^\n]*(?:\n|$))*(?:<.*>)?(?:\s|\)|!)*$'
- any:
- all:
- kind: function_expression
- not:
has:
kind: function_expression
stopBy: end
- all:
- any:
- kind: member_expression
- kind: null_aware_member_expression
- kind: instantiation_expression
- kind: null_assertion_expression
- has:
kind: function_expression
stopBy: end
# obj..targetFn(...) and obj?..targetFn(...)
- all:
- kind: cascade_call_expression
- has:
field: property
stopBy: neighbor
regex: '^targetFn$'Example
void example(Service service, Service? maybeService) {
targetFn('direct');
service.targetFn('member');
maybeService?.targetFn('null-aware');
service..targetFn('cascade');
targetFn<int>(1);
final callback = () => targetFn('arrow body');
final tearOff = targetFn;
service.targetFn.toString();
const text = 'targetFn("not code")';
}For an arrow-body call, the reported match can include the whole closure because that is the range exposed by the current Dart grammar.
This is a syntax rule, not type resolution. Dart can omit new and const, so Type.targetFn() can be either a static method call or a named constructor and is included. Chained cascade sections such as service..child.targetFn() and nested arrow bodies such as () => () => targetFn() are outside this rule's current scope.