This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new ae138bc5e1 GROOVY-11229: limit scope of `instanceof` variable
ae138bc5e1 is described below

commit ae138bc5e1478fa20263e295021b8c656b88ea11
Author: Eric Milles <[email protected]>
AuthorDate: Sat Mar 29 08:24:54 2025 -0500

    GROOVY-11229: limit scope of `instanceof` variable
---
 .../groovy/classgen/VariableScopeVisitor.java      |  58 ++++++++++++
 src/test/groovy/InstanceofTest.groovy              | 100 +++++++++++++++++++++
 2 files changed, 158 insertions(+)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index 34105073e8..33d1efea23 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -48,11 +48,17 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
 import org.codehaus.groovy.control.PlaceholderVisitor;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.syntax.Types;
@@ -480,6 +486,13 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
 
     // statements:
 
+    @Override
+    public void visitAssertStatement(final AssertStatement statement) {
+        pushState();
+        super.visitAssertStatement(statement);
+        popState();
+    }
+
     @Override
     public void visitBlockStatement(final BlockStatement statement) {
         pushState();
@@ -498,6 +511,25 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
         popState();
     }
 
+    @Override
+    public void visitDoWhileLoop(final DoWhileStatement statement) {
+        pushState();
+        visitStatement(statement);
+        statement.getLoopBlock().visit(this);
+        pushState();
+        statement.getBooleanExpression().visit(this);
+        popState();
+        popState();
+    }
+
+    @Override
+    public void visitExpressionStatement(final ExpressionStatement statement) {
+        boolean declaresVariable = statement.getExpression() instanceof 
DeclarationExpression;
+        if (!declaresVariable) pushState(); // GROOVY-11229: instanceof 
variable in expression
+        super.visitExpressionStatement(statement);
+        if (!declaresVariable) popState();
+    }
+
     @Override
     public void visitForLoop(final ForStatement statement) {
         pushState();
@@ -511,15 +543,39 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
 
     @Override
     public void visitIfElse(final IfStatement statement) {
+        pushState();
+        visitStatement(statement);
         statement.getBooleanExpression().visit(this);
         pushState();
         statement.getIfBlock().visit(this);
         popState();
+        popState();
         pushState();
         statement.getElseBlock().visit(this);
         popState();
     }
 
+    @Override
+    public void visitReturnStatement(final ReturnStatement statement) {
+        pushState();
+        super.visitReturnStatement(statement);
+        popState();
+    }
+
+    @Override
+    public void visitSwitch(final SwitchStatement statement) {
+        pushState();
+        super.visitSwitch(statement);
+        popState();
+    }
+
+    @Override
+    public void visitWhileLoop(final WhileStatement statement) {
+        pushState();
+        super.visitWhileLoop(statement);
+        popState();
+    }
+
     // expressions:
 
     @Override
@@ -627,9 +683,11 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
 
     @Override
     public void visitDeclarationExpression(final DeclarationExpression 
expression) {
+        pushState(); // GROOVY-11229
         visitAnnotations(expression);
         // visit right side first to prevent the use of a variable before its 
declaration
         expression.getRightExpression().visit(this);
+        popState();
 
         if (expression.isMultipleAssignmentDeclaration()) {
             TupleExpression list = expression.getTupleExpression();
diff --git a/src/test/groovy/InstanceofTest.groovy 
b/src/test/groovy/InstanceofTest.groovy
index 5564441836..e095a230c6 100644
--- a/src/test/groovy/InstanceofTest.groovy
+++ b/src/test/groovy/InstanceofTest.groovy
@@ -91,5 +91,105 @@ final class InstanceofTest {
         } else {
             assert n.intValue() == 12345
         }
+        assert (n instanceof Integer i && i.intValue() == 12345)
+    }
+
+    // GROOVY-11229
+    @Test
+    void testVariableScope() {
+        def shell = GroovyShell.withConfig {
+            ast groovy.transform.TypeChecked
+        }
+
+        def err = shouldFail shell, '''
+            Number n = 12345
+            if (n instanceof Integer i) {
+            }
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 5, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            if (n instanceof Integer i) ; else {
+                i.toString()
+            }
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 4, column 17/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            while (n instanceof Integer i) {
+                n = i.doubleValue()
+            }
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 6, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            do {
+                n = n.doubleValue()
+            } while (n instanceof Integer i)
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 6, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            do {
+                i.toString()
+            } while (n instanceof Integer i && (n = i.doubleValue()))
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 4, column 17/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            switch (n instanceof Integer i) {
+              case true:
+                i.toString()
+              case false:
+                i.toString()
+            }
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 9, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            return (n instanceof Integer i && i.intValue() == 12345)
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 4, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            assert (n instanceof Integer i && i.intValue() == 12345)
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 4, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            print(n instanceof Integer i && i.doubleValue())
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 4, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345;
+            {
+                print(n instanceof Integer i && i.doubleValue())
+            }
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 6, column 13/
+
+        err = shouldFail shell, '''
+            Number n = 12345
+            boolean b = (n instanceof Integer i && i.intValue())
+            i.toString()
+        '''
+        assert err =~ /The variable .i. is undeclared\.\s+@ line 4, column 13/
     }
 }

Reply via email to