implicit-call-tearoffs

Same as implicit_call_tearoffs in Dart lints

Group
Style
Path
lint/style/implicit-call-tearoffs
Default
Off, opt in
Origin
Dart lints
Rule
244 of 512

Explicitly tear off callable objects' call methods.

Reports each ImplicitCallReference the analyzer inserts. The coercion applies to the outermost expression of a conditional, ??, or cascade (and to a type instantiation, c<int>), so their operands are not reported again.

Invalid

example.dartdart
import 'dart:async';

class Callable {
  const Callable();
  void call() {}
}

class ConstructorExpectedTypes {
  final Function callback;
  final Function defaultCallback;

  const ConstructorExpectedTypes(
    Callable callback, {
    this.defaultCallback = const Callable(),
  }) : callback = callback;
}

void accept(Function callback) {}
void acceptNamed({required Function callback}) {}
Function returnTopLevel() => const Callable();
Function topLevelCallback = const Callable();
set topLevelSetter(Function value) {}

class Receiver {
  Receiver(Function callback, {required Function named});
  Receiver.named({required Function callback});

  Function fieldCallback = const Callable();
  static Function staticCallback = const Callable();
  set callbackSetter(Function value) {}
  static set staticSetter(Function value) {}

  void instance(Function callback, {required Function named}) {}
  static void staticMethod(Function callback, {required Function named}) {}

  Function returnMethod() => const Callable();

  void assignments(Callable callback) {
    Function localCallback = callback;
    localCallback = callback;
    fieldCallback = callback;
    this.fieldCallback = callback;
    Receiver.staticCallback = callback;
    topLevelCallback = callback;
    callbackSetter = callback;
    this.callbackSetter = callback;
    Receiver.staticSetter = callback;
    topLevelSetter = callback;
  }

  void methodCalls(Callable callback, Receiver receiver) {
    accept(callback);
    acceptNamed(callback: callback);
    instance(callback, named: callback.call);
    instance(callback.call, named: callback);
    this.instance(callback, named: callback.call);
    receiver.instance(callback.call, named: callback);
    Receiver.staticMethod(callback, named: callback.call);
    Receiver.staticMethod(callback.call, named: callback);
  }

  void constructorCalls(Callable callback) {
    Receiver(callback, named: callback.call);
    Receiver(callback.call, named: callback);
    new Receiver(callback, named: callback.call);
    Receiver.named(callback: callback);
  }

  void localCalls(Callable callback) {
    void localFunction(Function value, {required Function named}) {}
    localFunction(callback, named: callback.call);
    localFunction(callback.call, named: callback);

    void Function(Function, {required Function named}) functionValue = localFunction;
    functionValue(callback, named: callback.call);

    final inferredFunctionValue = localFunction;
    inferredFunctionValue(callback, named: callback.call);
  }

  void scoped(List<Callable> callbacks) {
    Function localReturn() => const Callable();
    localReturn();
    for (Callable callback in callbacks) {
      accept(callback);
    }
    try {
      throw const Callable();
    } on Callable catch (callback) {
      accept(callback);
    }
    final (Callable callback,) = (const Callable(),);
    accept(callback);
  }
}

class BaseReceiver {
  void inherited(Function callback) {}
  set inheritedSetter(Function callback) {}
}

class ChildReceiver extends BaseReceiver {
  void inheritedCalls(Callable callback) {
    inherited(callback);
    this.inherited(callback);
    inheritedSetter = callback;
    this.inheritedSetter = callback;
  }
}

void topLevelCalls(Callable callback, Receiver receiver) {
  Receiver(callback, named: callback.call);
  receiver.instance(callback, named: callback.call);
}

class ObjectReceiver {
  void accept(Object value) {}
}

class LexicalLookup extends ObjectReceiver {
  // Inherited members are not in lexical scope: the top-level `accept` wins.
  void topLevelShadowsInherited(Callable callback) {
    accept(callback);
  }
}

class MutableCallable {
  void call() {}
  int value = 0;
}

void outerCoercions(
  MutableCallable first,
  MutableCallable second,
  MutableCallable? nullable,
  bool condition,
) {
  void Function() conditional = condition ? first : second;
  void Function() cascade = first..value = 1;
  void Function() coalesced = nullable ?? second;
}

extension type CallableView(Callable value) implements Callable {}

void contextualCoercions(Callable callback, CallableView view) {
  void Function() extensionValue = view;
  var spread = <void Function()>[...[callback]];
  (void Function(), int) positional = (callback, 1);
  ({void Function() callback}) named = (callback: callback);
}

Future<void Function()> asyncReturn(Callable callback) async => callback;
Iterable<void Function()> generatorReturn(Callable callback) sync* {
  yield callback;
}

void boundedCoercion<T extends Callable>(T callback) {
  void Function() value = callback;
}

class GenericCallable {
  void call<T>(T value) {}
}

void acceptIntCallback(void Function(int) callback) {}

void instantiatedCoercions(GenericCallable callback) {
  Function functionContext = callback<int>;
  void Function(int) typedContext = callback<int>;
  acceptIntCallback(callback<int>);
  callback<int>;
  Function createdFunctionContext = GenericCallable()<int>;
  void Function(int) createdTypedContext = GenericCallable()<int>;
  acceptIntCallback(GenericCallable()<int>);
  GenericCallable()<int>;
}

void acceptFutureOrCallback(FutureOr<void Function()> callback) {}

void futureOrCoercion(Callable callback) {
  acceptFutureOrCallback(callback);
}

Stream<void Function()> asyncGeneratorReturn(Callable callback) async* {
  yield callback;
}
Explicitly tear off the `call` method.
13 Callable callback, {
14 this.defaultCallback = const Callable(),
Explicitly tear off the `call` method.
14 this.defaultCallback = const Callable(),
15 }) : callback = callback;
Explicitly tear off the `call` method.
19void acceptNamed({required Function callback}) {}
20Function returnTopLevel() => const Callable();
Explicitly tear off the `call` method.
20Function returnTopLevel() => const Callable();
21Function topLevelCallback = const Callable();
Explicitly tear off the `call` method.
27
28 Function fieldCallback = const Callable();
Explicitly tear off the `call` method.
28 Function fieldCallback = const Callable();
29 static Function staticCallback = const Callable();
Explicitly tear off the `call` method.
35
36 Function returnMethod() => const Callable();
Explicitly tear off the `call` method.
38 void assignments(Callable callback) {
39 Function localCallback = callback;
Explicitly tear off the `call` method.
39 Function localCallback = callback;
40 localCallback = callback;
Explicitly tear off the `call` method.
40 localCallback = callback;
41 fieldCallback = callback;
Explicitly tear off the `call` method.
41 fieldCallback = callback;
42 this.fieldCallback = callback;
Explicitly tear off the `call` method.
42 this.fieldCallback = callback;
43 Receiver.staticCallback = callback;
Explicitly tear off the `call` method.
43 Receiver.staticCallback = callback;
44 topLevelCallback = callback;
Explicitly tear off the `call` method.
44 topLevelCallback = callback;
45 callbackSetter = callback;
Explicitly tear off the `call` method.
45 callbackSetter = callback;
46 this.callbackSetter = callback;
Explicitly tear off the `call` method.
46 this.callbackSetter = callback;
47 Receiver.staticSetter = callback;
Explicitly tear off the `call` method.
47 Receiver.staticSetter = callback;
48 topLevelSetter = callback;
Explicitly tear off the `call` method.
51 void methodCalls(Callable callback, Receiver receiver) {
52 accept(callback);
Explicitly tear off the `call` method.
52 accept(callback);
53 acceptNamed(callback: callback);
Explicitly tear off the `call` method.
53 acceptNamed(callback: callback);
54 instance(callback, named: callback.call);
Explicitly tear off the `call` method.
54 instance(callback, named: callback.call);
55 instance(callback.call, named: callback);
Explicitly tear off the `call` method.
55 instance(callback.call, named: callback);
56 this.instance(callback, named: callback.call);
Explicitly tear off the `call` method.
56 this.instance(callback, named: callback.call);
57 receiver.instance(callback.call, named: callback);
Explicitly tear off the `call` method.
57 receiver.instance(callback.call, named: callback);
58 Receiver.staticMethod(callback, named: callback.call);
Explicitly tear off the `call` method.
58 Receiver.staticMethod(callback, named: callback.call);
59 Receiver.staticMethod(callback.call, named: callback);
Explicitly tear off the `call` method.
62 void constructorCalls(Callable callback) {
63 Receiver(callback, named: callback.call);
Explicitly tear off the `call` method.
63 Receiver(callback, named: callback.call);
64 Receiver(callback.call, named: callback);
Explicitly tear off the `call` method.
64 Receiver(callback.call, named: callback);
65 new Receiver(callback, named: callback.call);
Explicitly tear off the `call` method.
65 new Receiver(callback, named: callback.call);
66 Receiver.named(callback: callback);
Explicitly tear off the `call` method.
70 void localFunction(Function value, {required Function named}) {}
71 localFunction(callback, named: callback.call);
Explicitly tear off the `call` method.
71 localFunction(callback, named: callback.call);
72 localFunction(callback.call, named: callback);
Explicitly tear off the `call` method.
74 void Function(Function, {required Function named}) functionValue = localFunction;
75 functionValue(callback, named: callback.call);
Explicitly tear off the `call` method.
77 final inferredFunctionValue = localFunction;
78 inferredFunctionValue(callback, named: callback.call);
Explicitly tear off the `call` method.
81 void scoped(List<Callable> callbacks) {
82 Function localReturn() => const Callable();
Explicitly tear off the `call` method.
84 for (Callable callback in callbacks) {
85 accept(callback);
Explicitly tear off the `call` method.
89 } on Callable catch (callback) {
90 accept(callback);
Explicitly tear off the `call` method.
92 final (Callable callback,) = (const Callable(),);
93 accept(callback);
Explicitly tear off the `call` method.
103 void inheritedCalls(Callable callback) {
104 inherited(callback);
Explicitly tear off the `call` method.
104 inherited(callback);
105 this.inherited(callback);
Explicitly tear off the `call` method.
105 this.inherited(callback);
106 inheritedSetter = callback;
Explicitly tear off the `call` method.
106 inheritedSetter = callback;
107 this.inheritedSetter = callback;
Explicitly tear off the `call` method.
111void topLevelCalls(Callable callback, Receiver receiver) {
112 Receiver(callback, named: callback.call);
Explicitly tear off the `call` method.
112 Receiver(callback, named: callback.call);
113 receiver.instance(callback, named: callback.call);
Explicitly tear off the `call` method.
122 void topLevelShadowsInherited(Callable callback) {
123 accept(callback);
Explicitly tear off the `call` method.
137) {
138 void Function() conditional = condition ? first : second;
Explicitly tear off the `call` method.
138 void Function() conditional = condition ? first : second;
139 void Function() cascade = first..value = 1;
Explicitly tear off the `call` method.
139 void Function() cascade = first..value = 1;
140 void Function() coalesced = nullable ?? second;
Explicitly tear off the `call` method.
145void contextualCoercions(Callable callback, CallableView view) {
146 void Function() extensionValue = view;
Explicitly tear off the `call` method.
146 void Function() extensionValue = view;
147 var spread = <void Function()>[...[callback]];
Explicitly tear off the `call` method.
147 var spread = <void Function()>[...[callback]];
148 (void Function(), int) positional = (callback, 1);
Explicitly tear off the `call` method.
148 (void Function(), int) positional = (callback, 1);
149 ({void Function() callback}) named = (callback: callback);
Explicitly tear off the `call` method.
151
152Future<void Function()> asyncReturn(Callable callback) async => callback;
Explicitly tear off the `call` method.
153Iterable<void Function()> generatorReturn(Callable callback) sync* {
154 yield callback;
Explicitly tear off the `call` method.
157void boundedCoercion<T extends Callable>(T callback) {
158 void Function() value = callback;
Explicitly tear off the `call` method.
167void instantiatedCoercions(GenericCallable callback) {
168 Function functionContext = callback<int>;
Explicitly tear off the `call` method.
168 Function functionContext = callback<int>;
169 void Function(int) typedContext = callback<int>;
Explicitly tear off the `call` method.
169 void Function(int) typedContext = callback<int>;
170 acceptIntCallback(callback<int>);
Explicitly tear off the `call` method.
170 acceptIntCallback(callback<int>);
171 callback<int>;
Explicitly tear off the `call` method.
171 callback<int>;
172 Function createdFunctionContext = GenericCallable()<int>;
Explicitly tear off the `call` method.
172 Function createdFunctionContext = GenericCallable()<int>;
173 void Function(int) createdTypedContext = GenericCallable()<int>;
Explicitly tear off the `call` method.
173 void Function(int) createdTypedContext = GenericCallable()<int>;
174 acceptIntCallback(GenericCallable()<int>);
Explicitly tear off the `call` method.
174 acceptIntCallback(GenericCallable()<int>);
175 GenericCallable()<int>;
Explicitly tear off the `call` method.
180void futureOrCoercion(Callable callback) {
181 acceptFutureOrCallback(callback);
Explicitly tear off the `call` method.
184Stream<void Function()> asyncGeneratorReturn(Callable callback) async* {
185 yield callback;

Valid

example.dartdart
class Callable {
  const Callable();
  void call() {}
}

void accept(Function callback) {}
void acceptNamed({required Function callback}) {}
void acceptsString(String value) {}

Function returnExplicit() => const Callable().call;
Function topLevelCallback = const Callable().call;

class Receiver {
  Receiver(Function callback, {required Function named});
  Receiver.named({required Function callback});

  Function fieldCallback = const Callable().call;
  static Function staticCallback = const Callable().call;

  void instance(Function callback, {required Function named}) {}
  static void staticMethod(Function callback, {required Function named}) {}

  Function returnMethod() => const Callable().call;

  void explicit(Callable callback, Receiver receiver) {
    Function localCallback = callback.call;
    localCallback = callback.call;
    fieldCallback = callback.call;
    this.fieldCallback = callback.call;
    Receiver.staticCallback = callback.call;
    topLevelCallback = callback.call;

    accept(callback.call);
    acceptNamed(callback: callback.call);
    instance(callback.call, named: callback.call);
    receiver.instance(callback.call, named: callback.call);
    Receiver.staticMethod(callback.call, named: callback.call);
    Receiver(callback.call, named: callback.call);
    new Receiver(callback.call, named: callback.call);
    Receiver.named(callback: callback.call);
  }

  void memberShadowsTopLevel(Callable callback) {
    void accept(String value) {}
    accept(callback);
  }
}

void lexicalShadowing(Callable callback) {
  void accept(String value) {}
  accept(callback);

  void Receiver(String value) {}
  Receiver(callback);

  void localFunction(String value, {required String named}) {}
  localFunction(callback, named: callback);

  void Function(String) functionValue = acceptsString;
  functionValue(callback);

  final inferredFunctionValue = acceptsString;
  inferredFunctionValue(callback);
}

void importedOrUnknownCalls(Callable callback, dynamic importedReceiver) {
  importedAccept(callback);
  importedReceiver.accept(callback);
}

class BaseStringReceiver {
  void accept(Object value) {}
  set callback(Object value) {}
}

class OwnStringReceiver extends BaseStringReceiver {
  @override
  void accept(Object value) {}

  void declaredMembersShadowTopLevel(Callable callable) {
    accept(callable);
  }
}

class ChildStringReceiver extends BaseStringReceiver {
  void inheritedMembersShadowTopLevel(Callable callable) {
    this.accept(callable);
    callback = callable;
    this.callback = callable;
  }
}

void prefixedImportedTypes(
  ext.Callable callback,
  ext.Receiver receiver,
) {
  accept(callback);
  receiver.instance(callback);
  ext.Receiver(callback);
  new ext.Receiver(callback);
}

void reassignedFunctionValue(Callable callback) {
  Function target = accept;
  target = acceptsString;
  target(callback);
}

void scopedShadowing(Callable callback) {
  {
    void accept(String value) {}
    accept(callback);
  }
  accept(callback.call);
}

// A cyclic `extends` chain is invalid Dart but still parses; the lookup must
// terminate instead of walking the cycle forever.
class CyclicA extends CyclicB {}

class CyclicB extends CyclicA {}

void cyclicHierarchy(CyclicA value, Callable callback) {
  value.whatever(callback);
}

class GenericCallable {
  void call<T>(T value) {}
}

void explicitCompositeTearoffs(
  Callable first,
  Callable second,
  Callable? nullable,
  GenericCallable generic,
  bool condition,
) {
  void Function() conditional = condition ? first.call : second.call;
  void Function() coalesced = nullable?.call ?? second.call;
  void Function(int) instantiated = generic.call<int>;
  var spread = <void Function()>[...[first.call]];
  (void Function(), int) record = (first.call, 1);
}

Configure implicit-call-tearoffs

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "implicit-call-tearoffs": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/implicit-call-tearoffs: <reason>
  • initializers-ordering

    Requires field initializers to follow their containing type's field declaration order by default.

  • leading-newlines-in-multiline-stringsleading_newlines_in_multiline_strings

    Flags a multiline string spanning several lines whose text does not start with a line break right after the opening quotes.

  • library-annotationslibrary_annotationsrecommended

    Requires library-targeted metadata to attach to a library directive.

  • library-nameslibrary_namesrecommended

    Flags a library name that is not lowercase_with_underscores.

  • library-prefixeslibrary_prefixesrecommended

    Flags import prefixes that are not lower_case_with_underscores.

  • lines-longer-than-80-charslines_longer_than_80_chars

    Flags source lines longer than 80 characters.

  • map-keys-ordering

    Flags literal string map keys that violate the configured order.

  • matching-super-parametersmatching_super_parameters

    Flags positional super parameters named differently from the super constructor's corresponding parameter.