diff --git a/test/rule_test_support.dart b/test/rule_test_support.dart index f6c718266..0ba42dba2 100644 --- a/test/rule_test_support.dart +++ b/test/rule_test_support.dart @@ -458,8 +458,14 @@ abstract class BuildContext { Widget get widget; } -class Widget { +class Navigator { + static NavigatorState of( + BuildContext context, {bool rootNavigator = false}) => NavigatorState(); } + +class NavigatorState {} + +class Widget {} '''); } } diff --git a/test/rules/use_build_context_synchronously_test.dart b/test/rules/use_build_context_synchronously_test.dart index 9e7a89bc4..a5522945d 100644 --- a/test/rules/use_build_context_synchronously_test.dart +++ b/test/rules/use_build_context_synchronously_test.dart @@ -24,6 +24,213 @@ class UseBuildContextSynchronouslyTest extends LintRuleTest { @override String get testPackageRootPath => '$workspaceRootPath/lib'; + test_awaitBeforeIfStatement_beforeReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + var b = await condition; + if (b) { + Navigator.of(context); + } +} +''', [ + lint(145, 21), + ]); + } + + test_awaitBeforeReferenceToContext_inClosure() async { + // todo (pq): what about closures? + await assertNoDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + await condition; + f1(() { + f2(context); + }); +} + +void f1(Function f) {} +void f2(BuildContext c) {} +'''); + } + + // https://github.com/dart-lang/linter/issues/3457 + test_awaitInIfCondition_aboveReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + if (await condition) { + Navigator.of(context); + } +} + +''', [ + lint(132, 21), + ]); + } + + test_awaitInIfCondition_beforeReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + if (await condition) return; + Navigator.of(context); +} +''', [ + lint(136, 21), + ]); + } + + test_awaitInIfReferencesContext_beforeReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo( + BuildContext context, Future Function(BuildContext) condition) async { + if (await condition(context)) { + Navigator.of(context); + } +} +''', [ + lint(169, 21), + ]); + } + + test_awaitInIfThen_afterReferenceToContext() async { + await assertNoDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + Navigator.of(context); + if (1 == 2) { + await condition; + return; + } +} +'''); + } + + test_awaitInIfThen_beforeReferenceToContext() async { + // TODO(srawlins): I think this should report a lint, since an `await` is + // encountered in the if-body. + await assertNoDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + if (1 == 2) { + await condition; + return; + } + Navigator.of(context); +} +'''); + } + + test_awaitInIfThenAndExitInElse_afterReferenceToContext() async { + await assertNoDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + Navigator.of(context); + if (1 == 2) { + await condition; + } else { + await condition; + return; + } +} +'''); + } + + test_awaitInIfThenAndExitInElse_beforeReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + if (1 == 2) { + await condition; + } else { + await condition; + return; + } + Navigator.of(context); +} +''', [ + lint(190, 21), + ]); + } + + test_awaitInWhileBody_afterReferenceToContext() async { + await assertNoDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + Navigator.of(context); + while (true) { + await condition; + break; + } +} +'''); + } + + test_awaitInWhileBody_beforeReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + while (true) { + await condition; + break; + } + Navigator.of(context); +} +''', [ + lint(158, 21), + ]); + } + + test_awaitThenExitInIfThenAndElse_afterReferenceToContext() async { + await assertNoDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + Navigator.of(context); + if (1 == 2) { + await condition; + return; + } else { + await condition; + return; + } +} +'''); + } + + test_awaitThenExitInIfThenAndElse_beforeReferenceToContext() async { + await assertDiagnostics(r''' +import 'package:flutter/widgets.dart'; + +void foo(BuildContext context, Future condition) async { + if (1 == 2) { + await condition; + return; + } else { + await condition; + return; + } + Navigator.of(context); +} +''', [ + // No lint. + error(WarningCode.DEAD_CODE, 202, 22), + ]); + } + /// https://github.com/dart-lang/linter/issues/3818 test_context_propertyAccess() async { await assertDiagnostics(r''' diff --git a/test_data/rules/use_build_context_synchronously.dart b/test_data/rules/use_build_context_synchronously.dart index b54d379cc..fb93a770e 100644 --- a/test_data/rules/use_build_context_synchronously.dart +++ b/test_data/rules/use_build_context_synchronously.dart @@ -353,79 +353,3 @@ void topLevel5(BuildContext context) async { default: //nothing. } } - -void topLevel6(BuildContext context) async { - Navigator.of(context).pushNamed('route1'); // OK - if (true) { - await Future.delayed(Duration()); - return; - } - Navigator.of(context).pushNamed('route2'); // OK -} - -void topLevel7(BuildContext context) async { - Navigator.of(context).pushNamed('route1'); // OK - if (true) { - await Future.delayed(Duration()); - return; - } else { - await Future.delayed(Duration()); - return; - } - Navigator.of(context).pushNamed('route2'); // OK -} - -void topLevel8(BuildContext context) async { - Navigator.of(context).pushNamed('route1'); // OK - if (true) { - await Future.delayed(Duration()); - } else { - await Future.delayed(Duration()); - return; - } - Navigator.of(context).pushNamed('route2'); // LINT -} - -void topLevel9(BuildContext context) async { - Navigator.of(context).pushNamed('route1'); // OK - while (true) { - await Future.delayed(Duration()); - break; - } - Navigator.of(context).pushNamed('route2'); // LINT -} - -void closure(BuildContext context) async { - await Future.delayed(Duration()); - - // todo (pq): what about closures? - func(() { - f(context); // TODO: LINT - }); -} - -// https://github.com/dart-lang/linter/issues/3457 -void awaitInIf1(BuildContext context, Future condition) async { - if (await condition) { - Navigator.of(context).pushNamed('routeName'); // LINT - } -} - -void awaitInIf2(BuildContext context, Future condition) async { - var b = await condition; - if (b) { - Navigator.of(context).pushNamed('routeName'); // LINT - } -} - -void awaitInIf3(BuildContext context, Future condition) async { - if (await condition) return; - Navigator.of(context).pushNamed('routeName'); // LINT -} - -void awaitInIf4( - BuildContext context, Future Function(BuildContext) condition) async { - if (await condition(context)) { // OK - Navigator.of(context).pushNamed('routeName'); // LINT - } -}