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 2021/12/15 16:41:26 UTC

[groovy] branch master updated: GROOVY-10300: prep work

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 3cf40b9  GROOVY-10300: prep work
3cf40b9 is described below

commit 3cf40b995c2e874d6d2c1014fb5eaf1586cc9112
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Dec 15 10:26:02 2021 -0600

    GROOVY-10300: prep work
---
 .../codehaus/groovy/control/ClassNodeResolver.java | 100 +++++++++++----------
 .../codehaus/groovy/control/CompilationUnit.java   |  38 +++-----
 .../codehaus/groovy/control/ResolveVisitor.java    |  69 +++++++-------
 3 files changed, 99 insertions(+), 108 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java b/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
index 5b5c38f..d56d021 100644
--- a/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
+++ b/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
@@ -98,7 +98,7 @@ public class ClassNodeResolver {
      * path can be avoided.
      * WARNING: This class is not to be used outside of ClassNodeResolver.
      */
-    protected static final ClassNode NO_CLASS = new ClassNode("NO_CLASS", Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE){
+    protected static final ClassNode NO_CLASS = new ClassNode("NO_CLASS", Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE) {
         @Override
         public void setRedirect(ClassNode cn) {
             throw new GroovyBugError("This is a dummy class node only! Never use it for real classes.");
@@ -119,14 +119,19 @@ public class ClassNodeResolver {
      * @param compilationUnit - the current CompilationUnit
      * @return the LookupResult
      */
-    public LookupResult resolveName(String name, CompilationUnit compilationUnit) {
-        ClassNode res = getFromClassCache(name);
-        if (res==NO_CLASS) return null;
-        if (res!=null) return new LookupResult(null,res);
-        LookupResult lr = findClassNode(name, compilationUnit);
-        if (lr != null) {
-            if (lr.isClassNode()) cacheClass(name, lr.getClassNode());
-            return lr;
+    public LookupResult resolveName(final String name, final CompilationUnit compilationUnit) {
+        ClassNode type = getFromClassCache(name);
+        if (type != null) {
+            if (type == NO_CLASS) return null;
+            return new LookupResult(null, type);
+        }
+
+        LookupResult result = findClassNode(name, compilationUnit);
+        if (result != null) {
+            if (result.isClassNode()) {
+                cacheClass(name, result.getClassNode());
+            }
+            return result;
         } else {
             cacheClass(name, NO_CLASS);
             return null;
@@ -138,7 +143,7 @@ public class ClassNodeResolver {
      * @param name - the name of the class
      * @param res - the ClassNode for that name
      */
-    public void cacheClass(String name, ClassNode res) {
+    public void cacheClass(final String name, final ClassNode res) {
         cachedClasses.put(name, res);
     }
 
@@ -147,7 +152,7 @@ public class ClassNodeResolver {
      * @param name - the name of the class
      * @return the result of the lookup, which may be null
      */
-    public ClassNode getFromClassCache(String name) {
+    public ClassNode getFromClassCache(final String name) {
         // We use here the class cache cachedClasses to prevent
         // calls to ClassLoader#loadClass. Disabling this cache will
         // cause a major performance hit.
@@ -166,8 +171,8 @@ public class ClassNodeResolver {
      * @param compilationUnit - the current compilation unit
      * @return the lookup result
      */
-    public LookupResult findClassNode(String name, CompilationUnit compilationUnit) {
-        return tryAsLoaderClassOrScript(name, compilationUnit);
+    public LookupResult findClassNode(final String name, final CompilationUnit compilationUnit) {
+        return compilationUnit == null ? null : tryAsLoaderClassOrScript(name, compilationUnit);
     }
 
     /**
@@ -180,41 +185,39 @@ public class ClassNodeResolver {
      * The latter is slower but is unavoidable for scripts executed in dynamic environments where
      * the referenced classes might only be available in the classloader, not on disk.
      */
-    private LookupResult tryAsLoaderClassOrScript(String name, CompilationUnit compilationUnit) {
+    private LookupResult tryAsLoaderClassOrScript(final String name, final CompilationUnit compilationUnit) {
         GroovyClassLoader loader = compilationUnit.getClassLoader();
-
         Map<String, Boolean> options = compilationUnit.configuration.getOptimizationOptions();
-        boolean useAsm = !Boolean.FALSE.equals(options.get("asmResolving"));
-        boolean useClassLoader = !Boolean.FALSE.equals(options.get("classLoaderResolving"));
 
-        LookupResult result = useAsm ? findDecompiled(name, compilationUnit, loader) : null;
-        if (result != null) {
-            return result;
+        if (!Boolean.FALSE.equals(options.get("asmResolving"))) {
+            LookupResult result = findDecompiled(name, compilationUnit, loader);
+            if (result != null) {
+                return result;
+            }
         }
 
-        if (!useClassLoader) {
-            return tryAsScript(name, compilationUnit, null);
+        if (!Boolean.FALSE.equals(options.get("classLoaderResolving"))) {
+            return findByClassLoading(name, compilationUnit, loader);
         }
 
-        return findByClassLoading(name, compilationUnit, loader);
+        return tryAsScript(name, compilationUnit, null);
     }
 
     /**
      * Search for classes using class loading
      */
-    private static LookupResult findByClassLoading(String name, CompilationUnit compilationUnit, GroovyClassLoader loader) {
-        Class cls;
+    private static LookupResult findByClassLoading(final String name, final CompilationUnit compilationUnit, final GroovyClassLoader loader) {
+        Class<?> cls;
         try {
             // NOTE: it's important to do no lookup against script files
             // here since the GroovyClassLoader would create a new CompilationUnit
             cls = loader.loadClass(name, false, true);
         } catch (ClassNotFoundException cnfe) {
-            LookupResult lr = tryAsScript(name, compilationUnit, null);
-            return lr;
+            return tryAsScript(name, compilationUnit, null);
         } catch (CompilationFailedException cfe) {
             throw new GroovyBugError("The lookup for " + name + " caused a failed compilation. There should not have been any compilation from this call.", cfe);
         }
-        //TODO: the case of a NoClassDefFoundError needs a bit more research
+        //TODO: The case of a NoClassDefFoundError needs a bit more research;
         // a simple recompilation is not possible it seems. The current class
         // we are searching for is there, so we should mark that somehow.
         // Basically the missing class needs to be completely compiled before
@@ -238,7 +241,7 @@ public class ClassNodeResolver {
     /**
      * Search for classes using ASM decompiler
      */
-    private LookupResult findDecompiled(String name, CompilationUnit compilationUnit, GroovyClassLoader loader) {
+    private LookupResult findDecompiled(final String name, final CompilationUnit compilationUnit, final GroovyClassLoader loader) {
         ClassNode node = ClassHelper.make(name);
         if (node.isResolved()) {
             return new LookupResult(null, node);
@@ -269,25 +272,28 @@ public class ClassNodeResolver {
         return null;
     }
 
-    private static boolean isFromAnotherClassLoader(GroovyClassLoader loader, String fileName) {
+    private static boolean isFromAnotherClassLoader(final GroovyClassLoader loader, final String fileName) {
         ClassLoader parent = loader.getParent();
         return parent != null && parent.getResource(fileName) != null;
     }
 
     /**
-     * try to find a script using the compilation unit class loader.
+     * Tries to find a script using the compilation unit class loader.
      */
-    private static LookupResult tryAsScript(String name, CompilationUnit compilationUnit, ClassNode oldClass) {
+    private static LookupResult tryAsScript(final String name, final CompilationUnit compilationUnit, final ClassNode oldClass) {
         LookupResult lr = null;
-        if (oldClass!=null) {
+        if (oldClass != null) {
             lr = new LookupResult(null, oldClass);
         }
+        if (name.startsWith("java.")) {
+            return lr;
+        }
+        int i = name.indexOf('$');
+        if (i != -1) {
+            return lr;
+        }
 
-        if (name.startsWith("java.")) return lr;
-        //TODO: don't ignore inner static classes completely
-        if (name.indexOf('$') != -1) return lr;
-
-        // try to find a script from classpath*/
+        // try to find a script from classpath
         GroovyClassLoader gcl = compilationUnit.getClassLoader();
         URL url = null;
         try {
@@ -295,33 +301,33 @@ public class ClassNodeResolver {
         } catch (MalformedURLException e) {
             // fall through and let the URL be null
         }
-        if (url != null && ( oldClass==null || isSourceNewer(url, oldClass))) {
-            SourceUnit su = compilationUnit.addSource(url);
-            return new LookupResult(su,null);
+        if (url != null && (oldClass == null || isSourceNewer(url, oldClass))) {
+            SourceUnit sourceUnit = compilationUnit.addSource(url);
+            lr = new LookupResult(sourceUnit, null);
         }
         return lr;
     }
 
     /**
-     * get the time stamp of a class
+     * Gets the time stamp of a class.
+     * <p>
      * NOTE: copied from GroovyClassLoader
      */
-    private static long getTimeStamp(ClassNode cls) {
+    private static long getTimeStamp(final ClassNode cls) {
         if (!(cls instanceof DecompiledClassNode)) {
             return Verifier.getTimestamp(cls.getTypeClass());
         }
-
         return ((DecompiledClassNode) cls).getCompilationTimeStamp();
     }
 
     /**
-     * returns true if the source in URL is newer than the class
+     * Returns true if the source in URL is newer than the class.
+     * <p>
      * NOTE: copied from GroovyClassLoader
      */
-    private static boolean isSourceNewer(URL source, ClassNode cls) {
+    private static boolean isSourceNewer(final URL source, final ClassNode cls) {
         try {
             long lastMod;
-
             // Special handling for file:// protocol, as getLastModified() often reports
             // incorrect results (-1)
             if (source.getProtocol().equals("file")) {
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 72391a4..52a8379 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -613,10 +613,8 @@ public class CompilationUnit extends ProcessingUnit {
      * Compiles the compilation unit from sources.
      */
     public void compile(int throughPhase) throws CompilationFailedException {
-        //
-        // To support delta compilations, we always restart
-        // the compiler.  The individual passes are responsible
-        // for not reprocessing old code.
+        // to support incremental compilation, always restart the compiler;
+        // individual passes are responsible for not re-processing old code
         gotoPhase(Phases.INITIALIZATION);
         throughPhase = Math.min(throughPhase, Phases.ALL);
 
@@ -636,12 +634,12 @@ public class CompilationUnit extends ProcessingUnit {
             completePhase();
             mark();
 
-            if (dequeued()) continue;
+            if (dequeued()) continue; // bring new sources into phase
 
             gotoPhase(phase + 1);
 
             if (phase == Phases.CLASS_GENERATION) {
-                sortClasses();
+                getAST().getModules().forEach(ModuleNode::sortClasses);
             }
         }
 
@@ -679,33 +677,25 @@ public class CompilationUnit extends ProcessingUnit {
         }
     }
 
-    private void sortClasses() {
-        for (ModuleNode module : getAST().getModules()) {
-            module.sortClasses();
-        }
-    }
-
     /**
-     * Dequeues any source units add through addSource and resets the compiler phase
-     * to initialization.
+     * Dequeues any source units added through addSource and resets the compiler
+     * phase to initialization.
      * <p>
-     * Note: this does not mean a file is recompiled. If a SourceUnit has already passed
-     * a phase it is skipped until a higher phase is reached.
+     * Note: this does not mean a file is recompiled. If a SourceUnit has already
+     * passed a phase it is skipped until a higher phase is reached.
      *
      * @return true if there was a queued source
      * @throws CompilationFailedException
      */
     protected boolean dequeued() throws CompilationFailedException {
-        boolean dequeue = !queuedSources.isEmpty();
-        while (!queuedSources.isEmpty()) {
-            SourceUnit unit = queuedSources.remove();
-            String name = unit.getName();
-            sources.put(name, unit);
-        }
-        if (dequeue) {
+        if (!queuedSources.isEmpty()) { SourceUnit unit;
+            while ((unit = queuedSources.poll()) != null) {
+                sources.put(unit.getName(), unit);
+            }
             gotoPhase(Phases.INITIALIZATION);
+            return true;
         }
-        return dequeue;
+        return false;
     }
 
     /**
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index 89f077b..7ab7359 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -97,10 +97,8 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     // note: BigInteger and BigDecimal are also imported by default
     // `java.util` is used much frequently than other two java packages(`java.io` and `java.net`), so place java.util before the two packages
     public static final String[] DEFAULT_IMPORTS = {"java.lang.", "java.util.", "java.io.", "java.net.", "groovy.lang.", "groovy.util."};
-    private static final String BIGINTEGER_STR = "BigInteger";
-    private static final String BIGDECIMAL_STR = "BigDecimal";
-    public static final String QUESTION_MARK = "?";
     public static final String[] EMPTY_STRING_ARRAY = new String[0];
+    public static final String QUESTION_MARK = "?";
 
     private ClassNode currentClass;
     private final CompilationUnit compilationUnit;
@@ -529,11 +527,11 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
             if (resolveFromDefaultImports(type, DEFAULT_IMPORTS)) {
                 return true;
             }
-            if (BIGINTEGER_STR.equals(typeName)) {
+            if ("BigInteger".equals(typeName)) {
                 type.setRedirect(ClassHelper.BigInteger_TYPE);
                 return true;
             }
-            if (BIGDECIMAL_STR.equals(typeName)) {
+            if ("BigDecimal".equals(typeName)) {
                 type.setRedirect(ClassHelper.BigDecimal_TYPE);
                 return true;
             }
@@ -624,7 +622,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 if (importNode != null && importNode != currImportNode) {
                     // static alias only for inner classes and must be at end of chain
                     ClassNode tmp = new ConstructedNestedClass(importNode.getType(), importNode.getFieldName());
-                    if (resolve(tmp, false, false, true) && (tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                    if (resolve(tmp, false, false, true) && Modifier.isStatic(tmp.getModifiers())) {
                         type.setRedirect(tmp.redirect());
                         return true;
                     }
@@ -706,17 +704,17 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 // check package this class is defined in. The usage of ConstructedClassWithPackage here
                 // means, that the module package will not be involved when the
                 // compiler tries to find an inner class.
-                ClassNode tmp =  new ConstructedClassWithPackage(module.getPackageName(), name);
+                ClassNode tmp = new ConstructedClassWithPackage(module.getPackageName(), name);
                 if (resolve(tmp, false, false, false)) {
                     ambiguousClass(type, tmp, name);
                     return true;
                 }
             }
             // check static imports for static inner types
-            for (ImportNode importNode : module.getStaticImports().values()) {
+            for (ImportNode importNode : module.getStaticImports().values()) { // this may be fully redundant with resolveAliasFromModule
                 if (importNode.getFieldName().equals(name)) {
                     ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
-                    if (resolve(tmp, false, false, true) && (tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                    if (resolve(tmp, false, false, true) && Modifier.isStatic(tmp.getModifiers())) {
                         type.setRedirect(tmp.redirect());
                         return true;
                     }
@@ -724,7 +722,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
             }
             for (ImportNode importNode : module.getStaticStarImports().values()) {
                 ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
-                if (resolve(tmp, false, false, true) && (tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                if (resolve(tmp, false, false, true) && Modifier.isStatic(tmp.getModifiers())) {
                     ambiguousClass(type, tmp, name);
                     return true;
                 }
@@ -733,7 +731,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
             for (ImportNode importNode : module.getStarImports()) {
                 if (importNode.getType() != null) {
                     ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
-                    if (resolve(tmp, false, false, true) && (tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                    if (resolve(tmp, false, false, true) && Modifier.isStatic(tmp.getModifiers())) {
                         ambiguousClass(type, tmp, name);
                         return true;
                     }
@@ -752,7 +750,6 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
 
     protected boolean resolveToOuter(final ClassNode type) {
         String name = type.getName();
-
         // We do not need to check instances of LowerCaseClass
         // to be a Class, because unless there was an import for
         // for this we do not lookup these cases. This was a decision
@@ -760,21 +757,17 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         // method again we set a NO_CLASS for this name
         if (type instanceof LowerCaseClass) {
             classNodeResolver.cacheClass(name, ClassNodeResolver.NO_CLASS);
-            return false;
-        }
-
-        if (currentClass.getModule().hasPackageName() && name.indexOf('.') == -1) return false;
-
-        ClassNodeResolver.LookupResult lr = classNodeResolver.resolveName(name, compilationUnit);
-        if (lr != null) {
-            if (lr.isSourceUnit()) {
-                currentClass.getCompileUnit().addClassNodeToCompile(type, lr.getSourceUnit());
-            } else {
-                type.setRedirect(lr.getClassNode());
+        } else if (!currentClass.getModule().hasPackageName() || name.indexOf('.') != -1) {
+            ClassNodeResolver.LookupResult lr = classNodeResolver.resolveName(name, compilationUnit);
+            if (lr != null) {
+                if (lr.isSourceUnit()) {
+                    currentClass.getCompileUnit().addClassNodeToCompile(type, lr.getSourceUnit());
+                } else {
+                    type.setRedirect(lr.getClassNode());
+                }
+                return true;
             }
-            return true;
         }
-
         return false;
     }
 
@@ -991,7 +984,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 addError("The class '" + type.getName() + "' needs to be an outer class of '" +
                         currentClass.getName() + "' when using '.this' or '.super'.", expression);
             }
-            if ((currentClass.getModifiers() & Opcodes.ACC_STATIC) == 0) return;
+            if (!Modifier.isStatic(currentClass.getModifiers())) return;
             if (currentScope != null && !currentScope.isInStaticContext()) return;
             addError("The usage of 'Class.this' and 'Class.super' within static nested class '" +
                     currentClass.getName() + "' is not allowed in a static context.", expression);
@@ -1268,19 +1261,8 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     @Override
     public void visitClass(final ClassNode node) {
         ClassNode oldNode = currentClass;
-
         currentClass = node;
 
-        if (node instanceof InnerClassNode) {
-            if (Modifier.isStatic(node.getModifiers())) {
-                genericParameterNames = new HashMap<>();
-            }
-        } else {
-            genericParameterNames = new HashMap<>();
-        }
-
-        resolveGenericsHeader(node.getGenericsTypes());
-
         ModuleNode module = node.getModule();
         if (!module.hasImportsResolved()) {
             for (ImportNode importNode : module.getImports()) {
@@ -1315,9 +1297,22 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 if (!resolve(type, true, true, true))
                     addError("unable to resolve class " + type.getName(), type);
             }
+
             module.setImportsResolved(true);
         }
 
+        //
+
+        if (node instanceof InnerClassNode) {
+            if (Modifier.isStatic(node.getModifiers())) {
+                genericParameterNames = new HashMap<>();
+            }
+        } else {
+            genericParameterNames = new HashMap<>();
+        }
+
+        resolveGenericsHeader(node.getGenericsTypes());
+
         ClassNode sn = node.getUnresolvedSuperClass();
         if (sn != null) {
             resolveOrFail(sn, "", node, true);