-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add lint implicit_call_tearoffs (#3592)
In an effort to simplify the language we will consider removing the implicit `call` tearoff which can coerce an instance of any class which defines a `call` method into a `Function` type. Authors should explicitly add the `.call` so there is less magic.
- Loading branch information
Showing
7 changed files
with
204 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
|
||
import '../analyzer.dart'; | ||
|
||
const _desc = | ||
r'Explicitly tear-off `call` methods when using an object as a Function.'; | ||
|
||
const _details = r''' | ||
**DO** | ||
Explicitly tear off `.call` methods from objects when assigning to a Function | ||
type. There is less magic with an explicit tear off. Future language versions | ||
may remove the implicit call tear off. | ||
**BAD:** | ||
```dart | ||
class Callable { | ||
void call() {} | ||
} | ||
void callIt(void Function() f) { | ||
f(); | ||
} | ||
callIt(Callable()); | ||
``` | ||
**GOOD:** | ||
```dart | ||
class Callable { | ||
void call() {} | ||
} | ||
void callIt(void Function() f) { | ||
f(); | ||
} | ||
callIt(Callable().call); | ||
``` | ||
'''; | ||
|
||
class ImplicitCallTearoffs extends LintRule { | ||
ImplicitCallTearoffs() | ||
: super( | ||
name: 'implicit_call_tearoffs', | ||
description: _desc, | ||
details: _details, | ||
group: Group.style, | ||
maturity: Maturity.experimental, | ||
); | ||
|
||
@override | ||
void registerNodeProcessors( | ||
NodeLintRegistry registry, LinterContext context) { | ||
var visitor = _Visitor(this); | ||
registry.addImplicitCallReference(this, visitor); | ||
} | ||
} | ||
|
||
class _Visitor extends SimpleAstVisitor<void> { | ||
final LintRule rule; | ||
|
||
_Visitor(this.rule); | ||
|
||
@override | ||
void visitImplicitCallReference(ImplicitCallReference node) { | ||
rule.reportLint(node); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file | ||
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
// test w/ `dart test -N implicit_call_tearoffs` | ||
|
||
class C { | ||
void call() {} | ||
void other() {} | ||
} | ||
|
||
class C2 { | ||
void call<T>(T arg) {} | ||
} | ||
|
||
void callIt(void Function() f) { | ||
f(); | ||
} | ||
|
||
void callIt2(void Function(int) f) { | ||
f(0); | ||
} | ||
|
||
void Function() r1() => C(); // LINT | ||
void Function() r2() => C().call; // OK | ||
void Function() r3(C c) => c; // LINT | ||
void Function() r4(C c) => c.call; // OK | ||
|
||
void Function() r5(C? c1, C c2) { | ||
return c1 ?? c2; // LINT | ||
} | ||
|
||
void Function() r6(C? c1, C c2) { | ||
return c1?.call ?? c2.call; // OK | ||
} | ||
|
||
void Function() r7() { | ||
return C()..other(); // LINT | ||
} | ||
|
||
void Function() r8() { | ||
return (C()..other()).call; // OK | ||
} | ||
|
||
List<void Function()> r9(C c) { | ||
return [c]; // LINT | ||
} | ||
|
||
List<void Function()> r10(C c) { | ||
return [c.call]; // OK | ||
} | ||
|
||
void Function(int) r11(C2 c) => c; // LINT | ||
void Function(int) r12(C2 c) => c.call; // OK | ||
|
||
void main() { | ||
callIt(C()); // LINT | ||
callIt(C().call); // OK | ||
Function f1 = C(); // LINT | ||
Function f2 = C().call; // OK | ||
void Function() f3 = C(); // LINT | ||
void Function() f4 = C().call; // OK | ||
|
||
final c = C(); | ||
callIt(c); // LINT | ||
callIt(c.call); // OK | ||
Function f5 = c; // LINT | ||
Function f6 = c.call; // OK | ||
void Function() f7 = c; // LINT | ||
void Function() f8 = c.call; // OK | ||
|
||
<void Function()>[ | ||
C(), // LINT | ||
C().call, //OK | ||
c, // LINT | ||
c.call, // OK | ||
]; | ||
|
||
callIt2(C2()); // LINT | ||
callIt2(C2().call); // OK | ||
callIt2(C2()<int>); // LINT | ||
callIt2(C2().call<int>); // OK | ||
Function f9 = C2(); // LINT | ||
Function f10 = C2().call; // OK | ||
Function f11 = C2()<int>; // LINT | ||
Function f12 = C2().call<int>; // OK | ||
void Function<T>(T) f13 = C2(); // LINT | ||
void Function<T>(T) f14 = C2().call; // OK | ||
void Function(int) f15 = C2(); // LINT | ||
void Function(int) f16 = C2().call; // OK | ||
void Function(int) f17 = C2()<int>; // LINT | ||
void Function(int) f18 = C2().call<int>; // OK | ||
|
||
final c2 = C2(); | ||
callIt2(c2); // LINT | ||
callIt2(c2.call); // OK | ||
callIt2(c2<int>); // LINT | ||
callIt2(c2.call<int>); // OK | ||
Function f19 = c2; // LINT | ||
Function f20 = c2.call; // OK | ||
Function f21 = c2<int>; // LINT | ||
Function f22 = c2.call<int>; // OK | ||
void Function<T>(T) f23 = c2; // LINT | ||
void Function<T>(T) f24 = c2.call; // OK | ||
void Function(int) f25 = c2; // LINT | ||
void Function(int) f26 = c2.call; // OK | ||
void Function(int) f27 = c2<int>; // LINT | ||
void Function(int) f28 = c2.call<int>; // OK | ||
|
||
<void Function(int)>[ | ||
C2(), // LINT | ||
C2().call, //OK | ||
C2()<int>, // LINT | ||
C2().call<int>, //OK | ||
c2, // LINT | ||
c2.call, // OK | ||
c2<int>, // LINT | ||
c2.call<int>, // OK | ||
]; | ||
|
||
C2()<int>; // LINT | ||
c2<int>; // LINT | ||
} |