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);