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

commit 23d9322e9521a94185c9ea23ce49401f0e5c5f69
Author: Eric Milles <[email protected]>
AuthorDate: Tue Feb 24 11:14:36 2026 -0600

    `VariableScopeVisitor#findClassMember`: one pass for all interfaces
---
 .../groovy/classgen/VariableScopeVisitor.java      | 43 ++++++++++++++++------
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java 
b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index ddb524d184..4a9307a4db 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -63,15 +63,17 @@ import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.syntax.Types;
 
 import java.util.Deque;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
-import static java.lang.reflect.Modifier.isFinal;
 import static java.lang.reflect.Modifier.isStatic;
+import static java.util.Collections.addAll;
 import static org.apache.groovy.ast.tools.MethodNodeUtils.getPropertyName;
 import static 
org.apache.groovy.ast.tools.MethodNodeUtils.withDefaultArgumentMethods;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllProperties;
@@ -194,21 +196,28 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
 
     private Variable findClassMember(final ClassNode node, final String name) {
         final boolean abstractType = node.isAbstract();
+        Deque<ClassNode> interfaces = new LinkedList<>();
 
         for (ClassNode cn = node; cn != null && !ClassHelper.isObjectType(cn); 
cn = cn.getSuperClass()) {
             for (FieldNode fn : cn.getFields()) {
-                if (name.equals(fn.getName())) return fn;
+                if (name.equals(fn.getName())) {
+                    return fn;
+                }
             }
 
             for (PropertyNode pn : cn.getProperties()) {
-                if (name.equals(pn.getName())) return pn;
+                if (name.equals(pn.getName())) {
+                    return pn;
+                }
             }
 
             for (MethodNode mn : withDefaultArgumentMethods(cn.getMethods())) 
{ // GROOVY-11827
                 if ((abstractType || !mn.isAbstract()) && 
name.equals(getPropertyName(mn))) {
                     // check for super property before returning a 
pseudo-property
                     for (PropertyNode pn : 
getAllProperties(cn.getSuperClass())) {
-                        if (name.equals(pn.getName())) return pn;
+                        if (name.equals(pn.getName())) {
+                            return pn;
+                        }
                     }
 
                     FieldNode fn = new FieldNode(name, mn.getModifiers() & 
0xF, ClassHelper.dynamicType(), cn, null);
@@ -223,11 +232,23 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
                 }
             }
 
-            for (ClassNode in : cn.getAllInterfaces()) {
-                FieldNode fn = in.getDeclaredField(name);
-                if (fn != null) return fn;
-                PropertyNode pn = in.getProperty(name);
-                if (pn != null) return pn;
+            addAll(interfaces, cn.getInterfaces());
+        }
+
+        Set<ClassNode> done = new HashSet<>();
+        while (!interfaces.isEmpty()) {
+            ClassNode i = interfaces.remove();
+            if (done.add(i)) {
+                FieldNode fn = i.getDeclaredField(name);
+                if (fn != null) {
+                    return fn;
+                }
+                PropertyNode pn = i.getProperty(name);
+                if (pn != null) {
+                    return pn;
+                }
+
+                addAll(interfaces, i.getInterfaces());
             }
         }
 
@@ -346,7 +367,7 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
         BiConsumer<VariableExpression, ASTNode> checkForFinal = (expr, node) 
-> {
             Variable variable = expr.getAccessedVariable();
             if (variable != null) {
-                if (isFinal(variable.getModifiers()) && variable instanceof 
Parameter) {
+                if (variable.isFinal() && variable instanceof Parameter) {
                     addError("Cannot assign a value to final variable '" + 
variable.getName() + "'", node);
                 }
                 // TODO: handle local variables
@@ -382,7 +403,7 @@ public class VariableScopeVisitor extends 
ClassCodeVisitorSupport {
         if (variable.isInStaticContext()) {
             if (inConstructor && currentClass.isEnum() && variable instanceof 
FieldNode
                     && currentClass.equals(((FieldNode) 
variable).getDeclaringClass())) { // GROOVY-7025
-                if (!isFinal(variable.getModifiers()) || 
!(ClassHelper.isStaticConstantInitializerType(variable.getOriginType())
+                if (!variable.isFinal() || 
!(ClassHelper.isStaticConstantInitializerType(variable.getOriginType())
                         || 
"String".equals(variable.getOriginType().getName()))) { // TODO: String 
requires constant initializer
                     addError("Cannot refer to the static enum field '" + 
variable.getName() + "' within an initializer", expression);
                 }

Reply via email to