This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_2_5_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 6fdc9f2096f4b52c45fefeaf4fa66f94a6ad0af3 Author: Eric Milles <[email protected]> AuthorDate: Wed Aug 24 12:22:33 2022 -0500 sync with 3_0_X --- .../org/codehaus/groovy/classgen/Verifier.java | 2 +- .../groovy/classgen/asm/WriterController.java | 301 ++++++++++----------- src/test/gls/innerClass/InnerClassTest.groovy | 122 ++++++++- 3 files changed, 261 insertions(+), 164 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java index c8c89bad48..ed40d7731c 100644 --- a/src/main/java/org/codehaus/groovy/classgen/Verifier.java +++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java @@ -408,7 +408,7 @@ public class Verifier implements GroovyClassVisitor, Opcodes { } protected void addGroovyObjectInterfaceAndMethods(ClassNode node, final String classInternalName) { - if (!node.isDerivedFromGroovyObject()) node.addInterface(ClassHelper.make(GroovyObject.class)); + if (!node.isDerivedFromGroovyObject()) node.addInterface(ClassHelper.GROOVY_OBJECT_TYPE); FieldNode metaClassField = getMetaClassField(node); boolean shouldAnnotate = classNode.getModule().getContext() != null; diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java index a89c9e1855..b70e923fe7 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java @@ -22,7 +22,6 @@ import org.codehaus.groovy.GroovyBugError; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ConstructorNode; -import org.codehaus.groovy.ast.InnerClassNode; import org.codehaus.groovy.ast.InterfaceHelperClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.classgen.AsmClassGenerator; @@ -44,8 +43,9 @@ import java.util.Map; import static org.apache.groovy.util.SystemUtil.getBooleanSafe; public class WriterController { - private static final String GROOVY_LOG_CLASSGEN = "groovy.log.classgen"; - private final boolean LOG_CLASSGEN = getBooleanSafe(GROOVY_LOG_CLASSGEN); + + private static final boolean LOG_CLASSGEN = getBooleanSafe("groovy.log.classgen"); + private AsmClassGenerator acg; private MethodVisitor methodVisitor; private CompileStack compileStack; @@ -62,39 +62,38 @@ public class WriterController { private String internalBaseClassName; private ClassNode outermostClass; private MethodNode methodNode; - private SourceUnit sourceUnit; private ConstructorNode constructorNode; private GeneratorContext context; private InterfaceHelperClassNode interfaceClassLoadingClass; public boolean optimizeForInt = true; private StatementWriter statementWriter; - private boolean fastPath = false; + private boolean fastPath; private TypeChooser typeChooser; private int bytecodeVersion = Opcodes.V1_5; private int lineNumber = -1; private int helperMethodIndex = 0; private List<String> superMethodNames = new ArrayList<String>(); - public void init(AsmClassGenerator asmClassGenerator, GeneratorContext gcon, ClassVisitor cv, ClassNode cn) { + public void init(final AsmClassGenerator asmClassGenerator, final GeneratorContext gcon, final ClassVisitor cv, final ClassNode cn) { CompilerConfiguration config = cn.getCompileUnit().getConfig(); Map<String,Boolean> optOptions = config.getOptimizationOptions(); - boolean invokedynamic=false; + boolean invokedynamic = false; if (optOptions.isEmpty()) { // IGNORE } else if (Boolean.FALSE.equals(optOptions.get("all"))) { - optimizeForInt=false; + this.optimizeForInt = false; // set other optimizations options to false here } else { - if (Boolean.TRUE.equals(optOptions.get(CompilerConfiguration.INVOKEDYNAMIC))) invokedynamic=true; - if (Boolean.FALSE.equals(optOptions.get("int"))) optimizeForInt=false; - if (invokedynamic) optimizeForInt=false; + if (Boolean.TRUE.equals(optOptions.get(CompilerConfiguration.INVOKEDYNAMIC))) invokedynamic = true; + if (Boolean.FALSE.equals(optOptions.get("int"))) this.optimizeForInt = false; + if (invokedynamic) this.optimizeForInt = false; // set other optimizations options to false here } this.classNode = cn; this.outermostClass = null; - this.internalClassName = BytecodeHelper.getClassInternalName(classNode); + this.internalClassName = BytecodeHelper.getClassInternalName(cn); - bytecodeVersion = chooseBytecodeVersion(invokedynamic, config.isPreviewFeatures(), config.getTargetBytecode()); + this.bytecodeVersion = chooseBytecodeVersion(invokedynamic, config.isPreviewFeatures(), config.getTargetBytecode()); if (invokedynamic) { this.invocationWriter = new InvokeDynamicWriter(this); @@ -107,9 +106,9 @@ public class WriterController { } this.unaryExpressionHelper = new UnaryExpressionHelper(this); - if (optimizeForInt) { + if (this.optimizeForInt) { this.fastPathBinaryExpHelper = new BinaryExpressionMultiTypeDispatcher(this); - // todo: replace with a real fast path unary expression helper when available + // TODO: replace with a real fast path unary expression helper when available this.fastPathUnaryExpressionHelper = new UnaryExpressionHelper(this); } else { this.fastPathBinaryExpHelper = this.binaryExpHelper; @@ -119,13 +118,12 @@ public class WriterController { this.operandStack = new OperandStack(this); this.assertionWriter = new AssertionWriter(this); this.closureWriter = new ClosureWriter(this); - this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass()); + this.internalBaseClassName = BytecodeHelper.getClassInternalName(cn.getSuperClass()); this.acg = asmClassGenerator; - this.sourceUnit = acg.getSourceUnit(); this.context = gcon; this.compileStack = new CompileStack(this); - this.cv = this.createClassVisitor(cv); - if (optimizeForInt) { + this.cv = createClassVisitor(cv); + if (this.optimizeForInt) { this.statementWriter = new OptimizingStatementWriter(this); } else { this.statementWriter = new StatementWriter(this); @@ -133,11 +131,8 @@ public class WriterController { this.typeChooser = new StatementMetaTypeChooser(); } - private ClassVisitor createClassVisitor(ClassVisitor cv) { - if (!LOG_CLASSGEN) { - return cv; - } - if (cv instanceof LoggableClassVisitor) { + private static ClassVisitor createClassVisitor(final ClassVisitor cv) { + if (!LOG_CLASSGEN || cv instanceof LoggableClassVisitor) { return cv; } return new LoggableClassVisitor(cv); @@ -145,64 +140,68 @@ public class WriterController { private static int chooseBytecodeVersion(final boolean invokedynamic, final boolean previewFeatures, final String targetBytecode) { Integer bytecodeVersion = CompilerConfiguration.JDK_TO_BYTECODE_VERSION_MAP.get(targetBytecode); + if (bytecodeVersion == null) { + throw new GroovyBugError("Bytecode version [" + targetBytecode + "] is not supported by the compiler"); + } - if (invokedynamic && bytecodeVersion < Opcodes.V1_7) { - return Opcodes.V1_7; + if (invokedynamic && bytecodeVersion <= Opcodes.V1_7) { + return Opcodes.V1_7; // invokedynamic added here + } else if (previewFeatures) { + return bytecodeVersion | Opcodes.V_PREVIEW; } else { - if (null != bytecodeVersion) { - return previewFeatures ? bytecodeVersion | Opcodes.V_PREVIEW : bytecodeVersion; - } + return bytecodeVersion; } - - throw new GroovyBugError("Bytecode version ["+targetBytecode+"] is not supported by the compiler"); } + //-------------------------------------------------------------------------- + public AsmClassGenerator getAcg() { return acg; } - public void setMethodVisitor(MethodVisitor methodVisitor) { - this.methodVisitor = methodVisitor; - } - - public MethodVisitor getMethodVisitor() { - return methodVisitor; + @Deprecated + public ClassVisitor getCv() { + return cv; } - public CompileStack getCompileStack() { - return compileStack; + public ClassVisitor getClassVisitor() { + return cv; } - public OperandStack getOperandStack() { - return operandStack; + public MethodVisitor getMethodVisitor() { + return methodVisitor; } - public ClassNode getClassNode() { - return classNode; + public void setMethodVisitor(final MethodVisitor methodVisitor) { + this.methodVisitor = methodVisitor; } - public CallSiteWriter getCallSiteWriter() { - return callSiteWriter; + public GeneratorContext getContext() { + return context; } - public ClassVisitor getClassVisitor() { - return cv; + public CompileStack getCompileStack() { + return compileStack; } - public ClosureWriter getClosureWriter() { - return closureWriter; + public OperandStack getOperandStack() { + return operandStack; } - public ClassVisitor getCv() { - return cv; + public SourceUnit getSourceUnit() { + return getAcg().getSourceUnit(); } - public String getInternalClassName() { - return internalClassName; + public TypeChooser getTypeChooser() { + return typeChooser; } - public InvocationWriter getInvocationWriter() { - return invocationWriter; + public UnaryExpressionHelper getUnaryExpressionHelper() { + if (fastPath) { + return fastPathUnaryExpressionHelper; + } else { + return unaryExpressionHelper; + } } public BinaryExpressionHelper getBinaryExpressionHelper() { @@ -213,89 +212,117 @@ public class WriterController { } } - public UnaryExpressionHelper getUnaryExpressionHelper() { - if (fastPath) { - return fastPathUnaryExpressionHelper; - } else { - return unaryExpressionHelper; - } - } + //-------------------------------------------------------------------------- public AssertionWriter getAssertionWriter() { return assertionWriter; } - public TypeChooser getTypeChooser() { - return typeChooser; + public CallSiteWriter getCallSiteWriter() { + return callSiteWriter; } - public String getInternalBaseClassName() { - return internalBaseClassName; + public ClosureWriter getClosureWriter() { + return closureWriter; + } + + public StatementWriter getStatementWriter() { + return statementWriter; + } + + public InvocationWriter getInvocationWriter() { + return invocationWriter; + } + + //-------------------------------------------------------------------------- + + public String getClassName() { + String className; + if (!classNode.isInterface() || interfaceClassLoadingClass == null) { + className = internalClassName; + } else { + className = BytecodeHelper.getClassInternalName(interfaceClassLoadingClass); + } + return className; + } + + public ClassNode getClassNode() { + return classNode; } public MethodNode getMethodNode() { return methodNode; } - public void setMethodNode(MethodNode mn) { - methodNode = mn; - constructorNode = null; + public void setMethodNode(final MethodNode methodNode) { + this.methodNode = methodNode; + this.constructorNode = null; } - public ConstructorNode getConstructorNode(){ + public ConstructorNode getConstructorNode() { return constructorNode; } - public void setConstructorNode(ConstructorNode cn) { - constructorNode = cn; - methodNode = null; + public void setConstructorNode(final ConstructorNode constructorNode) { + this.constructorNode = constructorNode; + this.methodNode = null; } - public boolean isNotClinit() { - return methodNode == null || !methodNode.getName().equals("<clinit>"); + public ClassNode getReturnType() { + if (methodNode != null) { + return methodNode.getReturnType(); + } else if (constructorNode != null) { + return constructorNode.getReturnType(); + } else { + throw new GroovyBugError("I spotted a return that is neither in a method nor in a constructor... I can not handle that"); + } } - public SourceUnit getSourceUnit() { - return sourceUnit; + public ClassNode getOutermostClass() { + if (outermostClass == null) { + List<ClassNode> outers = classNode.getOuterClasses(); + outermostClass = !outers.isEmpty() ? outers.get(outers.size() - 1) : classNode; + } + return outermostClass; } - public boolean isStaticContext() { - if (compileStack!=null && compileStack.getScope()!=null) { - return compileStack.getScope().isInStaticContext(); - } - if (!isInClosure()) return false; - if (constructorNode != null) return false; - return classNode.isStaticClass() || methodNode.isStatic(); + public String getInternalClassName() { + return internalClassName; } - public boolean isInClosure() { - return classNode.getOuterClass() != null - && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE; + public String getInternalBaseClassName() { + return internalBaseClassName; } - public boolean isInClosureConstructor() { - return constructorNode != null - && classNode.getOuterClass() != null - && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE; + public List<String> getSuperMethodNames() { + return superMethodNames; } - public boolean isNotExplicitThisInClosure(boolean implicitThis) { - return implicitThis || !isInClosure(); + public InterfaceHelperClassNode getInterfaceClassLoadingClass() { + return interfaceClassLoadingClass; + } + + public void setInterfaceClassLoadingClass(final InterfaceHelperClassNode ihc) { + interfaceClassLoadingClass = ihc; } + // + + public boolean isStaticContext() { + if (compileStack != null && compileStack.getScope() != null) { + return compileStack.getScope().isInStaticContext(); + } + if (!isInClosure()) return false; + if (isConstructor()) return false; + return classNode.isStaticClass() || isStaticMethod(); + } public boolean isStaticMethod() { return methodNode != null && methodNode.isStatic(); } - public ClassNode getReturnType() { - if (methodNode != null) { - return methodNode.getReturnType(); - } else if (constructorNode != null) { - return constructorNode.getReturnType(); - } else { - throw new GroovyBugError("I spotted a return that is neither in a method nor in a constructor... I can not handle that"); - } + public boolean isNotClinit() { + return methodNode == null || !methodNode.getName().equals("<clinit>"); } public boolean isStaticConstructor() { @@ -303,61 +330,35 @@ public class WriterController { } public boolean isConstructor() { - return constructorNode!=null; + return constructorNode != null; } - /** - * @return true if we are in a script body, where all variables declared are no longer - * local variables but are properties - */ - public boolean isInScriptBody() { - if (classNode.isScriptBody()) { - return true; - } else { - return classNode.isScript() && methodNode != null && methodNode.getName().equals("run"); - } - } - - public String getClassName() { - String className; - if (!classNode.isInterface() || interfaceClassLoadingClass == null) { - className = internalClassName; - } else { - className = BytecodeHelper.getClassInternalName(interfaceClassLoadingClass); - } - return className; - } - - public ClassNode getOutermostClass() { - if (outermostClass == null) { - outermostClass = classNode; - while (outermostClass instanceof InnerClassNode) { - outermostClass = outermostClass.getOuterClass(); - } - } - return outermostClass; + public boolean isInClosure() { + return classNode.getOuterClass() != null + && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE); } - public GeneratorContext getContext() { - return context; + public boolean isInClosureConstructor() { + return isConstructor() && isInClosure(); } - public void setInterfaceClassLoadingClass(InterfaceHelperClassNode ihc) { - interfaceClassLoadingClass = ihc; + @Deprecated + public boolean isNotExplicitThisInClosure(final boolean implicitThis) { + return implicitThis || !isInClosure(); } - public InterfaceHelperClassNode getInterfaceClassLoadingClass() { - return interfaceClassLoadingClass; + /** + * @return true if we are in a script body, where all variables declared are no longer + * local variables but are properties + */ + public boolean isInScriptBody() { + return classNode.isScriptBody() || (classNode.isScript() && methodNode != null && methodNode.getName().equals("run")); } public boolean shouldOptimizeForInt() { return optimizeForInt; } - public StatementWriter getStatementWriter() { - return statementWriter; - } - public void switchToFastPath() { fastPath = true; resetLineNumber(); @@ -372,27 +373,23 @@ public class WriterController { return fastPath; } - public int getBytecodeVersion() { - return bytecodeVersion; - } - public int getLineNumber() { return lineNumber; } - public void setLineNumber(int n) { - lineNumber = n; + public void setLineNumber(final int lineNumber) { + this.lineNumber = lineNumber; } public void resetLineNumber() { setLineNumber(-1); } - public int getNextHelperMethodIndex() { - return helperMethodIndex++; + public int getBytecodeVersion() { + return bytecodeVersion; } - public List<String> getSuperMethodNames() { - return superMethodNames; + public int getNextHelperMethodIndex() { + return helperMethodIndex += 1; } } diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy index af8a5f96dc..0d9e17d846 100644 --- a/src/test/gls/innerClass/InnerClassTest.groovy +++ b/src/test/gls/innerClass/InnerClassTest.groovy @@ -203,6 +203,48 @@ final class InnerClassTest { ''' } + @NotYetImplemented @Test // GROOVY-8423 + void testPrivateInnerClassHasPrivateModifier() { + assertScript ''' + import static java.lang.reflect.Modifier.* + + class A { + private class B {} + } + + int modifiers = A.B.modifiers + assert isPrivate(modifiers) + ''' + } + + @NotYetImplemented @Test // GROOVY-8423 + void testProtectedInnerClassHasProtectedModifier() { + assertScript ''' + import static java.lang.reflect.Modifier.* + + class A { + protected class B {} + } + + int modifiers = A.B.modifiers + assert isProtected(modifiers) + ''' + } + + @Test // GROOVY-8423 + void testPackagePrivateInnerClassHasNoAccessModifier() { + assertScript ''' + import static java.lang.reflect.Modifier.* + + class A { + @groovy.transform.PackageScope class B {} + } + + int modifiers = A.B.modifiers + assert !isPrivate(modifiers) && !isProtected(modifiers) && !isPublic(modifiers) + ''' + } + @Test void testStaticInnerClass() { assertScript ''' @@ -641,6 +683,19 @@ final class InnerClassTest { assert err =~ /Apparent variable 'count' was found in a static scope but doesn't refer to a local variable, static field or class./ } + @Test // GROOVY-8050 + void testUsageOfOuterField13() { + assertScript ''' + class Outer { + class Inner { + } + def p = 1 + } + def i = new Outer.Inner(new Outer()) + assert i.p == 1 + ''' + } + @Test void testUsageOfOuterSuperField() { assertScript ''' @@ -694,6 +749,29 @@ final class InnerClassTest { ''' } + @Test // GROOVY-9905 + void testUsageOfOuterSuperField3() { + assertScript ''' + abstract class A { + protected final f = 'foo' + abstract static class B {} + } + + class C extends A { + private class D extends A.B { // B is static inner + String toString() { + f + 'bar' // No such property: f for class: A + } + } + def m() { + new D().toString() + } + } + + assert new C().m() == 'foobar' + ''' + } + @Test void testUsageOfOuterField_WrongCallToSuper() { shouldFail ''' @@ -1170,30 +1248,30 @@ final class InnerClassTest { ''' } - @Test // GROOVY-5989 - void testResolveInnerOfSuperType1() { + @Test // GROOVY-5754 + void testResolveInnerOfSuperType() { assertScript ''' interface I { class C { } } class Outer implements I { - static class Inner extends C { } + static class Inner extends C {} } - new Outer() - new Outer.Inner() + print I.C ''' } - @Test // GROOVY-5754 + @Test // GROOVY-5989 void testResolveInnerOfSuperType2() { assertScript ''' interface I { class C { } } class Outer implements I { - static class Inner extends C {} + static class Inner extends C { } } - print I.C + new Outer() + new Outer.Inner() ''' } @@ -1483,13 +1561,12 @@ final class InnerClassTest { ''' } - @Test // GROOVY-9151 + @Test // GROOVY-5681, GROOVY-9151 void testEnclosingMethodIsSet2() { assertScript ''' import groovy.transform.ASTTest import org.codehaus.groovy.ast.expr.* import static org.codehaus.groovy.classgen.Verifier.* - import static org.codehaus.groovy.control.CompilePhase.* @ASTTest(phase=CLASS_GENERATION, value={ def init = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION) @@ -1516,7 +1593,6 @@ final class InnerClassTest { import org.codehaus.groovy.ast.expr.* import org.codehaus.groovy.ast.stmt.* import static org.codehaus.groovy.classgen.Verifier.* - import static org.codehaus.groovy.control.CompilePhase.* @ASTTest(phase=CLASS_GENERATION, value={ def init = node.parameters[0].getNodeMetaData(INITIAL_EXPRESSION) @@ -1687,6 +1763,30 @@ final class InnerClassTest { ''' } + @NotYetImplemented @Test // GROOVY-8274 + void testMissingMethodHandling() { + assertScript ''' + class A { + class B { + def methodMissing(String name, args) { + return name + } + } + + def test(Closure c) { + c.resolveStrategy = Closure.DELEGATE_ONLY + c.delegate = new B() + c.call() + } + } + + def x = new A().test { -> + hello() // missing + } + assert x == 'hello' + ''' + } + @Test // GROOVY-6831 void testNestedPropertyHandling() { assertScript '''
