Skip to content

Commit 5828f83

Browse files
srawlinsCommit Queue
authored andcommitted
linter: Support for inherited @awaitNotRequired annotations
Change-Id: I6c55f6423f6a44838674165ab311f31c64ffd399 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/424682 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 2877d78 commit 5828f83

File tree

2 files changed

+67
-24
lines changed

2 files changed

+67
-24
lines changed

pkg/linter/lib/src/extensions.dart

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -343,18 +343,31 @@ extension ElementExtension on Element2? {
343343

344344
extension ExpressionExtension on Expression {
345345
/// Returns whether `await` is not required for this expression.
346-
// TODO(srawlins): Handle inheritence in each of these cases; the
347-
// `@awaitNotRequired` annotation should be inherited.
348-
bool get isAwaitNotRequired => switch (this) {
349-
BinaryExpression(:var element) => element.hasAwaitNotRequired,
350-
MethodInvocation(:var methodName) => methodName.element.hasAwaitNotRequired,
351-
PrefixedIdentifier(:var identifier) =>
352-
identifier.element.hasAwaitNotRequired,
353-
PrefixExpression(:var element) => element.hasAwaitNotRequired,
354-
PropertyAccess(:var propertyName) =>
355-
propertyName.element.hasAwaitNotRequired,
356-
_ => false,
357-
};
346+
bool get isAwaitNotRequired {
347+
var element = switch (this) {
348+
BinaryExpression(:var element) => element,
349+
MethodInvocation(:var methodName) => methodName.element,
350+
PrefixedIdentifier(:var identifier) => identifier.element,
351+
PrefixExpression(:var element) => element,
352+
PropertyAccess(:var propertyName) => propertyName.element,
353+
_ => null,
354+
};
355+
if (element == null) return false;
356+
if (element.hasAwaitNotRequired) return true;
357+
358+
var elementName = element.name3;
359+
if (elementName == null) return false;
360+
361+
var enclosingElement = element.enclosingElement2;
362+
if (enclosingElement is! InterfaceElement2) return false;
363+
364+
var superTypes = enclosingElement.allSupertypes;
365+
var superMembers =
366+
element is MethodElement2
367+
? superTypes.map((t) => t.getMethod2(elementName))
368+
: superTypes.map((t) => t.getGetter2(elementName));
369+
return superMembers.any((e) => e.hasAwaitNotRequired);
370+
}
358371
}
359372

360373
extension ExpressionNullableExtension on Expression? {

pkg/linter/test/rules/unawaited_futures_test.dart

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,6 @@ class C {
181181
);
182182
}
183183

184-
// TODO(srawlins): Test that `@awaitNotRequired` is inherited.
185-
186184
test_functionCallInCascade_assignment() async {
187185
await assertNoDiagnostics(r'''
188186
void f() async {
@@ -199,11 +197,27 @@ class C {
199197
await assertNoDiagnostics(r'''
200198
import 'package:meta/meta.dart';
201199
void f() async {
202-
C()..doAsync();
200+
C()..m();
203201
}
204202
class C {
205203
@awaitNotRequired
206-
Future<void> doAsync() async {}
204+
Future<void> m() async {}
205+
}
206+
''');
207+
}
208+
209+
test_functionCallInCascade_awaitNotRequiredInherited() async {
210+
await assertNoDiagnostics(r'''
211+
import 'package:meta/meta.dart';
212+
void f() async {
213+
C()..m();
214+
}
215+
class C {
216+
@awaitNotRequired
217+
Future<void> m() async {}
218+
}
219+
class D {
220+
Future<void> m() => Future.value();
207221
}
208222
''');
209223
}
@@ -233,6 +247,20 @@ class C {
233247
}
234248

235249
test_instanceProperty_unawaited() async {
250+
await assertDiagnostics(
251+
r'''
252+
void f(C c) async {
253+
c.p;
254+
}
255+
abstract class C {
256+
Future<int> get p;
257+
}
258+
''',
259+
[lint(22, 4)],
260+
);
261+
}
262+
263+
test_instanceProperty_unawaited_awaitNotRequired() async {
236264
await assertNoDiagnostics(r'''
237265
import 'package:meta/meta.dart';
238266
void f(C c) async {
@@ -245,18 +273,20 @@ abstract class C {
245273
''');
246274
}
247275

248-
test_instanceProperty_unawaited_awaitNotRequired() async {
249-
await assertDiagnostics(
250-
r'''
251-
void f(C c) async {
252-
c.p;
276+
test_instanceProperty_unawaited_awaitNotRequiredInherited() async {
277+
await assertNoDiagnostics(r'''
278+
import 'package:meta/meta.dart';
279+
void f(D d) async {
280+
d.p;
253281
}
254282
abstract class C {
283+
@awaitNotRequired
255284
Future<int> get p;
256285
}
257-
''',
258-
[lint(22, 4)],
259-
);
286+
class D extends C {
287+
Future<int> p = Future.value(7);
288+
}
289+
''');
260290
}
261291

262292
test_parameter_unawaited() async {

0 commit comments

Comments
 (0)