You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2020/10/25 19:55:52 UTC

[groovy] 02/02: remove recursion from ClassNodeUtils#getField and reuse in ASM classgen

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 6a2ca074983c2d3b765e46eb96c8127396ed7afe
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Oct 25 14:47:58 2020 -0500

    remove recursion from ClassNodeUtils#getField and reuse in ASM classgen
---
 .../apache/groovy/ast/tools/ClassNodeUtils.java    | 43 +++++++++++++---------
 .../groovy/classgen/AsmClassGenerator.java         | 16 +++-----
 2 files changed, 32 insertions(+), 27 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
index a18b23f..23edfd3 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
@@ -34,13 +34,17 @@ import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.transform.AbstractASTTransformation;
 
 import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Queue;
 import java.util.Set;
+import java.util.function.Predicate;
 
 import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.isGenerated;
 import static org.apache.groovy.ast.tools.AnnotatedNodeUtils.markAsGenerated;
@@ -388,27 +392,32 @@ public class ClassNodeUtils {
     }
 
     /**
-     * Return the (potentially inherited) field of the classnode.
-     *
-     * @param classNode the classnode
-     * @param fieldName the name of the field
-     * @return the field or null if not found
+     * Searches the class for a field that matches specified name.
      */
     public static FieldNode getField(final ClassNode classNode, final String fieldName) {
-        ClassNode node = classNode;
-        Set<String> visited = new HashSet<>();
-        while (node != null) {
-            FieldNode fn = node.getDeclaredField(fieldName);
-            if (fn != null) return fn;
-            ClassNode[] interfaces = node.getInterfaces();
-            for (ClassNode iNode : interfaces) {
-                if (visited.contains(iNode.getName())) continue;
-                FieldNode ifn = getField(iNode, fieldName);
-                visited.add(iNode.getName());
-                if (ifn != null) return ifn;
+        return getField(classNode, fieldName, fieldNode -> true);
+    }
+
+    /**
+     * Searches the class for a field that matches specified name and test.
+     */
+    public static FieldNode getField(final ClassNode classNode, final String fieldName, final Predicate<FieldNode> acceptability) {
+        Queue<ClassNode> todo = new ArrayDeque<>(Collections.singletonList(classNode));
+        Set<ClassNode> done = new HashSet<>();
+        ClassNode next;
+
+        while ((next = todo.poll()) != null) {
+            if (done.add(next)) {
+                FieldNode fieldNode = next.getDeclaredField(fieldName);
+                if (fieldNode != null && acceptability.test(fieldNode))
+                    return fieldNode;
+
+                Collections.addAll(todo, next.getInterfaces());
+                ClassNode superType = next.getSuperClass();
+                if (superType != null) todo.add(superType);
             }
-            node = node.getSuperClass();
         }
+
         return null;
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 43795f2..022d44b 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -124,6 +124,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 
+import static org.apache.groovy.ast.tools.ClassNodeUtils.getField;
 import static org.apache.groovy.ast.tools.ExpressionUtils.isThisOrSuper;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.attrX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
@@ -959,16 +960,11 @@ public class AsmClassGenerator extends ClassGenerator {
         return false;
     }
 
-    public static FieldNode getDeclaredFieldOfCurrentClassOrAccessibleFieldOfSuper(final ClassNode accessingNode, final ClassNode current, final String name, final boolean skipCurrent) {
-        if (!skipCurrent) {
-            FieldNode currentClassField = current.getDeclaredField(name);
-            if (isValidFieldNodeForByteCodeAccess(currentClassField, accessingNode)) return currentClassField;
-        }
-        for (ClassNode node = current.getSuperClass(); node != null; node = node.getSuperClass()) {
-            FieldNode fn = node.getDeclaredField(name);
-            if (isValidFieldNodeForByteCodeAccess(fn, accessingNode)) return fn;
-        }
-        return null;
+    public static FieldNode getDeclaredFieldOfCurrentClassOrAccessibleFieldOfSuper(final ClassNode accessingNode, final ClassNode current, final String fieldName, final boolean skipCurrent) {
+        return getField(current, fieldName, fieldNode ->
+            (!skipCurrent || !current.equals(fieldNode.getDeclaringClass()))
+                && isValidFieldNodeForByteCodeAccess(fieldNode, accessingNode)
+        );
     }
 
     private void visitAttributeOrProperty(final PropertyExpression pexp, final MethodCallerMultiAdapter adapter) {