[stable][analyzer] Prevents ExitDetector from crashing with dot
shorthands.
Issue description: When attempting to run `dart fix`, the `ExitDetector`
runs and crashes because it's missing visitor methods for the dot
shorthand AST nodes.
What is the fix: Added missing visitor methods for dot shorthands.
Why cherry-pick: `dart fix` with any dot shorthands will cause a crash.
Risk: Low, this fix has landed on the main channel and fixes the crash.
Issue link(s): https://github.com/dart-lang/sdk/issues/61963
Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/456162,
https://dart-review.googlesource.com/c/sdk/+/456163,
https://dart-review.googlesource.com/c/sdk/+/457781
Bug: https://github.com/dart-lang/sdk/issue/61963
Change-Id: Ie78a76a05bd41803738c136fdb9fe4daf86a86f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/461920
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10ae563..4788d9c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,9 +7,12 @@
(issue [dart-lang/sdk#61872][]).
- Fixes an issue with the analyzer not reporting an error when invoking an
instance method with a dot shorthand. (issue [dart-lang/sdk#61954][]).
+- Fixes a crash with the `ExitDetector` in the analyzer missing a few visitor
+ methods for dot shorthand AST nodes. (issue [dart-lang/sdk#61963])
[dart-lang/sdk#61872]: https://github.com/dart-lang/sdk/issues/61872
[dart-lang/sdk#61954]: https://github.com/dart-lang/sdk/issues/61954
+[dart-lang/sdk#61963]: https://github.com/dart-lang/sdk/issues/61963
## 3.10.0
diff --git a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
index cfe6cc4..3fae11c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/exit_detector.dart
@@ -171,6 +171,27 @@
}
@override
+ bool visitDotShorthandConstructorInvocation(
+ DotShorthandConstructorInvocation node,
+ ) {
+ return _nodeExits(node.argumentList);
+ }
+
+ @override
+ bool visitDotShorthandInvocation(DotShorthandInvocation node) {
+ var element = node.memberName.element;
+ if (_elementExits(element)) {
+ return true;
+ }
+ return _nodeExits(node.argumentList);
+ }
+
+ @override
+ bool visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+ return _elementExits(node.propertyName.element);
+ }
+
+ @override
bool visitEmptyStatement(EmptyStatement node) => false;
@override
diff --git a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
index 3138fdb..36bf165 100644
--- a/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
+++ b/pkg/analyzer/test/src/dart/resolver/exit_detector_test.dart
@@ -957,6 +957,94 @@
///
/// See [ExitDetectorParsedStatementTest] for tests that do not require the AST to be resolved.
mixin ExitDetectorResolvedStatementTestCases on PubPackageResolutionTest {
+ test_dotShorthandConstructorInvocation_namedArgumentThrows() async {
+ await _assertNthStatementExits(r'''
+class C {
+ C({int? i});
+}
+void f() {
+ C _ = .new(i: throw 42);
+}
+''', 0);
+ }
+
+ test_dotShorthandConstructorInvocation_noExit() async {
+ await _assertNthStatementDoesNotExit(r'''
+class C {
+ C(int _);
+}
+void f() {
+ C _ = .new(0);
+}
+''', 0);
+ }
+
+ test_dotShorthandConstructorInvocation_positionalArgumentThrows() async {
+ await _assertNthStatementExits(r'''
+class C {
+ C(int _);
+}
+void f() {
+ C _ = .new(throw 42);
+}
+''', 0);
+ }
+
+ test_dotShorthandInvocation_argumentThrows() async {
+ await _assertNthStatementExits(r'''
+class C {
+ static C create(int _) => C();
+}
+void f() {
+ C _ = .create(throw 42);
+}
+''', 0);
+ }
+
+ test_dotShorthandInvocation_methodReturnsNever() async {
+ await _assertNthStatementExits(r'''
+class C {
+ static Never create() => throw 42;
+}
+void f() {
+ C _ = .create();
+}
+''', 0);
+ }
+
+ test_dotShorthandInvocation_noExit() async {
+ await _assertNthStatementDoesNotExit(r'''
+class C {
+ static C create(int _) => C();
+}
+void f() {
+ C _ = .create(0);
+}
+''', 0);
+ }
+
+ test_dotShorthandPropertyAccess_getterReturnsNever() async {
+ await _assertNthStatementExits(r'''
+class C {
+ static Never get foo => throw 42;
+}
+void f() {
+ C _ = .foo;
+}
+''', 0);
+ }
+
+ test_dotShorthandPropertyAccess_noExit() async {
+ await _assertNthStatementDoesNotExit(r'''
+class C {
+ static C get foo => C();
+}
+void f() {
+ C _ = .foo;
+}
+''', 0);
+ }
+
test_forStatement_implicitTrue_breakWithLabel() async {
await _assertNthStatementDoesNotExit(r'''
void f() {