avoid-dynamic-calls
Same as avoid_dynamic_calls in Dart lints
- Group
- Correctness
- Path
lint/correctness/avoid-dynamic-calls- Default
- On (recommended)
- Origin
- Dart lints
- Rule
- 57 of 512
Avoid method calls or property accesses on a dynamic target.
Members reached through dynamic are looked up at runtime: typos and
signature mismatches surface as NoSuchMethodError instead of compile
errors, and the dispatch is slower:
void log(dynamic event) {
print(event.name); // BAD
}
void log(Event event) {
print(event.name); // GOOD
}
Reported targets: member accesses, method calls, index operations,
user-definable binary operators (not ==/!=), prefix and postfix
operators, and compound assignments on a dynamic receiver, plus calls of a
dynamic or Function-typed variable, including .call() cascade sections.
hashCode, runtimeType, toString, and noSuchMethod — members every
object has — are allowed (except method calls directly on cascade targets),
as are explicit as dynamic casts and x!.
Receiver and callable types come from the semantic resolver, including flow-promoted types at each use site. Diagnostics retain grouped receiver spans; compound updates use the complete update expression, and selector chains retain their cascade-section start.
Invalid
dynamic config;
void member(dynamic event) {
print(event.name);
event.handle();
event?.handle();
}
void operators(dynamic a) {
print(a + 1);
print(a < 2);
print(-a);
a++;
a += 1;
print(a[0]);
}
void invocation(dynamic callback, Function handler) {
callback();
handler(1);
}
void json(Map<String, dynamic> data, List<dynamic> items) {
print(data['user'].name);
print(data['user']['id']);
items.first;
print(items[0].length);
}
void chained(dynamic value) {
dynamic local = value;
local.first.last;
local..add(1)..add(2);
}
void topLevel() {
config.load();
}
class Holder {
dynamic payload;
void read() {
print(payload.length);
}
}
void promotedInOneFunction(dynamic scopedValue) {
if (scopedValue is String) {
print(scopedValue.length);
}
}
void stillDynamicInAnotherFunction(dynamic scopedValue) {
print(scopedValue.length);
}
void cascadeFunction(Function callback) {
callback
..call()
..call();
}void member(dynamic event) { print(event.name); print(event.name); event.handle(); event.handle(); event?.handle();void operators(dynamic a) { print(a + 1); print(a + 1); print(a < 2); print(a < 2); print(-a); print(-a); a++; a++; a += 1; a += 1; print(a[0]);void invocation(dynamic callback, Function handler) { callback(); callback(); handler(1);void json(Map<String, dynamic> data, List<dynamic> items) { print(data['user'].name); print(data['user'].name); print(data['user']['id']); items.first; print(items[0].length); dynamic local = value; local.first.last; dynamic local = value; local.first.last; local.first.last; local..add(1)..add(2);void topLevel() { config.load(); void read() { print(payload.length);void stillDynamicInAnotherFunction(dynamic scopedValue) { print(scopedValue.length); callback ..call() ..call() ..call();Valid
import 'dart:async';
dynamic config;
void allowed(dynamic value) {
print(value.hashCode);
print(value.runtimeType);
print(value.toString());
print(value == 1);
print(value != null);
value!;
print(value ?? 1);
}
void casts(dynamic value) {
(value as dynamic).foo();
(value as String).length;
value = 2;
}
void typed(String text, List<int> numbers, Map<String, int> counts) {
print(text.length);
print(numbers.first.isEven);
print(counts['a']);
}
void untypedClosure(List<String> names) {
names.forEach((name) => print(name.length));
final upper = names.map((name) => name.toUpperCase());
print(upper);
}
void untypedLiteral() {
final values = [1, 2];
print(values.first.isEven);
}
class Holder {
String config = '';
void read() {
print(config.length);
}
}
void functionType(void Function() callback, int Function(int) mapper) {
callback();
print(mapper(1));
}
void shadowed(String value) {
print(value.length);
}
void otherShadowed(dynamic value) {
print(value.hashCode);
}
void promotedMapAndString(dynamic data) {
if (data is Map) {
print(data['key']);
}
if (data is String) {
print(data.length);
}
}
void promotedByEarlyReturn(dynamic list) {
if (list is! List) return;
print(list.length);
}
void collectionForShadow(dynamic item, List<String> items) {
print([for (final String item in items) item.length]);
}
void acceptsTypedCallback(void Function(String) callback) {}
void contextualParameters() {
acceptsTypedCallback((value) => print(value.length));
void Function(String) callback = (value) => print(value.length);
callback('text');
}
void unresolvedExternalContext(Stream<String> events) {
events.listen((event) => print(event.length));
}
void acceptsNamedCallback(void Function({required String value}) callback) {}
void namedContextualParameters() {
acceptsNamedCallback(({required value}) => print(value.length));
}
void acceptsGenericCallback(void Function<T>(T value) callback) {}
void genericContextualParameters() {
acceptsGenericCallback(<T>(value) {
T typed = value;
print(typed);
});
}
void cascadeCallback(List<int> values) {
values..sort((left, right) => left.compareTo(right));
}
void nullCoalescingCallback() {
void Function(String)? callback;
callback ??= (value) => print(value.length);
callback('text');
}
void explicitlyTypedClosureCollections() {
final callbacks = <void Function(String)>[
(value) => print(value.length),
];
final callbackSet = <void Function(String)>{
(value) => print(value.length),
};
final callbackMap = <String, void Function(Map<String, int>)>{
'count': (value) => print(value.length),
};
print([callbacks, callbackSet, callbackMap]);
}
void contextuallyTypedClosureCollections() {
List<void Function(String)> callbacks = [
(value) => print(value.length),
];
Map<String, void Function(String)> callbackMap = {
'text': (value) => print(value.length),
};
print([callbacks, callbackMap]);
}
void explicitlyCastFunctionCascade(Object callback) {
(callback as Function)..call();
}Configure avoid-dynamic-calls
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"correctness": {
"avoid-dynamic-calls": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/correctness/avoid-dynamic-calls: <reason>More correctness rules
- avoid-emit-outside-blocrecommendedbloc
Flags external calls and tear-offs of a Bloc or Cubit's
emitmethod. - avoid-empty-setstaterecommendedflutter
Avoid setState callbacks with empty block bodies.
- avoid-empty-test-groupstest
Reports inline framework groups without any test registrations.
- avoid-global-state
avoid-global-stateDisallow mutable global and static state.
- avoid-hooks-outside-buildrecommendedflutter_hooks
Flags confirmed Flutter hooks outside hook builds, custom hooks, and HookBuilder/HookConsumer builders.
- avoid-incorrect-image-opacityflutter
Flags Opacity directly wrapping a Flutter Image, including named constructors.
- avoid-inherited-widget-in-initstaterecommendedflutter
Avoid inherited-widget subscriptions during initState.
- avoid-instantiating-in-value-providerprovider
Value providers borrow existing instances; newly constructed values need create.