Issue 48502. Report RETHROW_OUTSIDE_CATCH when new executable inside catch.

Bug: https://github.com/dart-lang/sdk/issues/48502
Change-Id: Iddab4ff30eca7da4891916ac051ad9a827a252e3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/235170
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index c923c69..01ff198 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -74,6 +74,9 @@
   /// for the kind of the function body, e.g. not `Future` for `async`.
   bool hasLegalReturnType = true;
 
+  /// The number of enclosing [CatchClause] in this executable.
+  int catchClauseLevel = 0;
+
   EnclosingExecutableContext(this.element,
       {bool? isAsynchronous, this.catchErrorOnErrorReturnType})
       : isAsynchronous =
@@ -164,11 +167,6 @@
   /// The manager for the inheritance mappings.
   final InheritanceManager3 _inheritanceManager;
 
-  /// A flag indicating whether the visitor is currently within a catch clause.
-  ///
-  /// See [visitCatchClause].
-  bool _isInCatchClause = false;
-
   /// A flag indicating whether the visitor is currently within a comment.
   bool _isInComment = false;
 
@@ -250,7 +248,6 @@
         _duplicateDefinitionVerifier = DuplicateDefinitionVerifier(
             _inheritanceManager, _currentLibrary, errorReporter) {
     _isInSystemLibrary = _currentLibrary.source.uri.isScheme('dart');
-    _isInCatchClause = false;
     _isInStaticVariableDeclaration = false;
     _isInConstructorInitializer = false;
     _intType = _typeProvider.intType;
@@ -409,13 +406,12 @@
   @override
   void visitCatchClause(CatchClause node) {
     _duplicateDefinitionVerifier.checkCatchClause(node);
-    bool previousIsInCatchClause = _isInCatchClause;
     try {
-      _isInCatchClause = true;
+      _enclosingExecutable.catchClauseLevel++;
       _checkForTypeAnnotationDeferredClass(node.exceptionType);
       super.visitCatchClause(node);
     } finally {
-      _isInCatchClause = previousIsInCatchClause;
+      _enclosingExecutable.catchClauseLevel--;
     }
   }
 
@@ -4112,7 +4108,7 @@
   ///
   /// See [CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH].
   void _checkForRethrowOutsideCatch(RethrowExpression expression) {
-    if (!_isInCatchClause) {
+    if (_enclosingExecutable.catchClauseLevel == 0) {
       errorReporter.reportErrorForNode(
           CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, expression);
     }
diff --git a/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart b/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart
index ee8c262..717c3a4 100644
--- a/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart
@@ -17,9 +17,37 @@
 class RethrowOutsideCatchTest extends PubPackageResolutionTest {
   test_insideCatch() async {
     await assertNoErrorsInCode(r'''
-class A {
-  void m() {
-    try {} catch (e) {rethrow;}
+void f() {
+  try {} catch (e) {
+    rethrow;
+  }
+}
+''');
+  }
+
+  test_insideCatch_insideClosure() async {
+    await assertErrorsInCode(r'''
+void f() {
+  try {} catch (e) {
+    () {
+      rethrow;
+    };
+  }
+}
+''', [
+      error(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, 47, 7),
+    ]);
+  }
+
+  test_insideCatch_insideClosure_insideCatch() async {
+    await assertNoErrorsInCode(r'''
+void f() {
+  try {} catch (e1) {
+    () {
+      try {} catch (e2) {
+        rethrow;
+      }
+    };
   }
 }
 ''');
@@ -27,11 +55,11 @@
 
   test_withoutCatch() async {
     await assertErrorsInCode(r'''
-f() {
+void f() {
   rethrow;
 }
 ''', [
-      error(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, 8, 7),
+      error(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, 13, 7),
     ]);
   }
 }