Skip to content

Commit e22fdae

Browse files
authored
[use_build_context_synchronously] Fix for unprotected 'last' invocation. (#4279)
1 parent f9edf66 commit e22fdae

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

lib/src/rules/use_build_context_synchronously.dart

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:analyzer/dart/ast/token.dart';
77
import 'package:analyzer/dart/ast/visitor.dart';
88
import 'package:analyzer/dart/element/element.dart';
99
import 'package:analyzer/dart/element/type.dart';
10+
import 'package:collection/collection.dart';
1011

1112
import '../analyzer.dart';
1213
import '../util/flutter_utils.dart';
@@ -346,7 +347,9 @@ extension on Statement {
346347
bool get terminatesControl {
347348
var self = this;
348349
if (self is Block) {
349-
return self.statements.last.terminatesControl;
350+
// TODO(scheglov) Stop using package:collection when SDK 3.0.0
351+
var last = self.statements.lastOrNull;
352+
return last != null && last.terminatesControl;
350353
}
351354
// TODO(srawlins): Make ExitDetector 100% functional for our needs. The
352355
// basic (only?) difference is that it doesn't consider a `break` statement

test/rule_test_support.dart

+12-1
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,30 @@ typedef DiagnosticMatcher = bool Function(AnalysisError error);
3939
class AnalysisOptionsFileConfig {
4040
final List<String> experiments;
4141
final List<String> lints;
42+
final bool propagateLinterExceptions;
4243

4344
AnalysisOptionsFileConfig({
4445
this.experiments = const [],
4546
this.lints = const [],
47+
this.propagateLinterExceptions = false,
4648
});
4749

4850
String toContent() {
4951
var buffer = StringBuffer();
5052

51-
if (experiments.isNotEmpty) {
53+
if (experiments.isNotEmpty || propagateLinterExceptions) {
5254
buffer.writeln('analyzer:');
5355
buffer.writeln(' enable-experiment:');
5456
for (var experiment in experiments) {
5557
buffer.writeln(' - $experiment');
5658
}
59+
60+
if (propagateLinterExceptions) {
61+
buffer.writeln(' strong-mode:');
62+
buffer.writeln(
63+
' propagate-linter-exceptions: $propagateLinterExceptions',
64+
);
65+
}
5766
}
5867

5968
buffer.writeln('linter:');
@@ -378,6 +387,7 @@ class PubPackageResolutionTest extends _ContextResolutionTest {
378387
AnalysisOptionsFileConfig(
379388
experiments: experiments,
380389
lints: _lintRules,
390+
propagateLinterExceptions: true,
381391
),
382392
);
383393
writeTestPackageConfig(
@@ -456,6 +466,7 @@ export 'src/widgets/framework.dart';
456466
.writeAsStringSync(r'''
457467
abstract class BuildContext {
458468
Widget get widget;
469+
bool get mounted;
459470
}
460471
461472
class Navigator {

test/rules/use_build_context_synchronously_test.dart

+15
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,21 @@ Future<void> bar({required BuildContext context}) async {}
428428
]);
429429
}
430430

431+
test_noAwaitBefore_ifEmptyThen_methodInvocation() async {
432+
await assertNoDiagnostics(r'''
433+
import 'package:flutter/widgets.dart';
434+
435+
void f(BuildContext context) async {
436+
if (true) {}
437+
context.foo();
438+
}
439+
440+
extension on BuildContext {
441+
void foo() {}
442+
}
443+
''');
444+
}
445+
431446
/// https://github.com/dart-lang/linter/issues/3700
432447
test_propertyAccess_getter() async {
433448
await assertDiagnostics(r'''

0 commit comments

Comments
 (0)