You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2019/12/22 08:57:19 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-9352: Static compilation fails with NoClassDefFoundError

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new dc4678d  GROOVY-9352: Static compilation fails with NoClassDefFoundError
dc4678d is described below

commit dc4678dbf8ab11a0f4487c594fb17a488466df5d
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Dec 22 16:56:11 2019 +0800

    GROOVY-9352: Static compilation fails with NoClassDefFoundError
---
 .../org/codehaus/groovy/ast/ConstructorNode.java   |   1 +
 .../java/org/codehaus/groovy/ast/FieldNode.java    |   2 +
 .../java/org/codehaus/groovy/ast/MethodNode.java   |   8 +-
 .../groovy/ast/decompiled/DecompiledClassNode.java |  60 ++-
 .../groovy/ast/decompiled/LazyConstructorNode.java | 448 +++++++++++++++++++++
 .../groovy/ast/decompiled/LazyFieldNode.java       | 403 ++++++++++++++++++
 .../groovy/ast/decompiled/LazyMethodNode.java      | 444 ++++++++++++++++++++
 .../test/groovy/groovy/ant/Groovy9352Test.groovy   |  99 +++++
 8 files changed, 1457 insertions(+), 8 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java b/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java
index da9a87f..af1eef9 100644
--- a/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java
@@ -27,6 +27,7 @@ import org.codehaus.groovy.ast.stmt.Statement;
  * Represents a constructor declaration
  */
 public class ConstructorNode extends MethodNode {
+    protected ConstructorNode() {}
 
     public ConstructorNode(int modifiers, Statement code) {
         this(modifiers, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
diff --git a/src/main/java/org/codehaus/groovy/ast/FieldNode.java b/src/main/java/org/codehaus/groovy/ast/FieldNode.java
index cae3dcf..db29623 100644
--- a/src/main/java/org/codehaus/groovy/ast/FieldNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/FieldNode.java
@@ -43,6 +43,8 @@ public class FieldNode extends AnnotatedNode implements Opcodes, Variable {
         return new FieldNode(name, ACC_PUBLIC | ACC_STATIC, fldType, ClassHelper.make(theClass), null);
     }
 
+    protected FieldNode() {}
+
     public FieldNode(String name, int modifiers, ClassNode type, ClassNode owner, Expression initialValueExpression) {
         this.name = name;
         this.modifiers = modifiers;
diff --git a/src/main/java/org/codehaus/groovy/ast/MethodNode.java b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
index fc1c05e..534057f 100644
--- a/src/main/java/org/codehaus/groovy/ast/MethodNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
@@ -31,7 +31,7 @@ import java.util.List;
 public class MethodNode extends AnnotatedNode implements Opcodes {
 
     public static final String SCRIPT_BODY_METHOD_KEY = "org.codehaus.groovy.ast.MethodNode.isScriptBody";
-    private final String name;
+    private String name;
     private int modifiers;
     private boolean syntheticPublic;
     private ClassNode returnType;
@@ -40,8 +40,8 @@ public class MethodNode extends AnnotatedNode implements Opcodes {
     private Statement code;
     private boolean dynamicReturnType;
     private VariableScope variableScope;
-    private final ClassNode[] exceptions;
-    private final boolean staticConstructor;
+    private ClassNode[] exceptions;
+    private boolean staticConstructor;
 
     // type spec for generics
     private GenericsType[] genericsTypes = null;
@@ -50,6 +50,8 @@ public class MethodNode extends AnnotatedNode implements Opcodes {
     // cached data
     String typeDescriptor;
 
+    protected MethodNode() {}
+
     public MethodNode(String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
         this.name = name;
         this.modifiers = modifiers;
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
index 8207070..c18f0d0 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
@@ -18,6 +18,7 @@
  */
 package org.codehaus.groovy.ast.decompiled;
 
+import org.apache.groovy.internal.util.Supplier;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassNode;
@@ -27,6 +28,7 @@ import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.MixinNode;
 import org.codehaus.groovy.classgen.Verifier;
+import org.objectweb.asm.Opcodes;
 
 import java.lang.reflect.Modifier;
 import java.util.List;
@@ -191,18 +193,17 @@ public class DecompiledClassNode extends ClassNode {
             if (!membersInitialized) {
                 if (classData.methods != null) {
                     for (MethodStub method : classData.methods) {
-                        MethodNode node = addAnnotations(method, MemberSignatureParser.createMethodNode(resolver, method));
-                        if (node instanceof ConstructorNode) {
-                            addConstructor((ConstructorNode) node);
+                        if (isConstructor(method)) {
+                            addConstructor(createConstructor(method));
                         } else {
-                            addMethod(node);
+                            addMethod(createMethodNode(method));
                         }
                     }
                 }
 
                 if (classData.fields != null) {
                     for (FieldStub field : classData.fields) {
-                        addField(addAnnotations(field, MemberSignatureParser.createFieldNode(field, resolver, this)));
+                        addField(createFieldNode(field));
                     }
                 }
 
@@ -211,6 +212,55 @@ public class DecompiledClassNode extends ClassNode {
         }
     }
 
+    private FieldNode createFieldNode(final FieldStub field) {
+        Supplier<FieldNode> fieldNodeSupplier = new Supplier<FieldNode>() {
+            @Override
+            public FieldNode get() {
+                return addAnnotations(field, MemberSignatureParser.createFieldNode(field, resolver, DecompiledClassNode.this));
+            }
+        };
+
+        if ((field.accessModifiers & Opcodes.ACC_PRIVATE) != 0) {
+            return new LazyFieldNode(fieldNodeSupplier, field.fieldName);
+        }
+
+        return fieldNodeSupplier.get();
+    }
+
+    private MethodNode createMethodNode(final MethodStub method) {
+        Supplier<MethodNode> methodNodeSupplier = new Supplier<MethodNode>() {
+            @Override
+            public MethodNode get() {
+                return addAnnotations(method, MemberSignatureParser.createMethodNode(resolver, method));
+            }
+        };
+
+        if ((method.accessModifiers & Opcodes.ACC_PRIVATE) != 0) {
+            return new LazyMethodNode(methodNodeSupplier, method.methodName);
+        }
+
+        return methodNodeSupplier.get();
+    }
+
+    private ConstructorNode createConstructor(final MethodStub method) {
+        Supplier<ConstructorNode> constructorNodeSupplier = new Supplier<ConstructorNode>() {
+            @Override
+            public ConstructorNode get() {
+                return (ConstructorNode) addAnnotations(method, MemberSignatureParser.createMethodNode(resolver, method));
+            }
+        };
+
+        if ((method.accessModifiers & Opcodes.ACC_PRIVATE) != 0) {
+            return new LazyConstructorNode(constructorNodeSupplier);
+        }
+
+        return constructorNodeSupplier.get();
+    }
+
+    private boolean isConstructor(MethodStub method) {
+        return "<init>".equals(method.methodName);
+    }
+
     private <T extends AnnotatedNode> T addAnnotations(MemberStub stub, T node) {
         List<AnnotationStub> annotations = stub.annotations;
         if (annotations != null) {
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/LazyConstructorNode.java b/src/main/java/org/codehaus/groovy/ast/decompiled/LazyConstructorNode.java
new file mode 100644
index 0000000..62418ce
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/LazyConstructorNode.java
@@ -0,0 +1,448 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.decompiled;
+
+import org.apache.groovy.internal.util.Supplier;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.util.ListHashMap;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents lazy constructor node, which will be initialized only when accessed
+ *
+ * @since 2.5.9
+ */
+public class LazyConstructorNode extends ConstructorNode {
+    private final Supplier<ConstructorNode> constructorNodeSupplier;
+    private ConstructorNode delegate;
+    private boolean initialized;
+
+    public LazyConstructorNode(Supplier<ConstructorNode> constructorNodeSupplier) {
+        this.constructorNodeSupplier = constructorNodeSupplier;
+    }
+
+    private void init() {
+        if (initialized) return;
+        delegate = constructorNodeSupplier.get();
+
+        ClassNode declaringClass = super.getDeclaringClass();
+        if (null != declaringClass) delegate.setDeclaringClass(declaringClass);
+
+        initialized = true;
+    }
+
+    @Override
+    public boolean firstStatementIsSpecialConstructorCall() {
+        init();
+        return delegate.firstStatementIsSpecialConstructorCall();
+    }
+
+    @Override
+    public String getTypeDescriptor() {
+        init();
+        return delegate.getTypeDescriptor();
+    }
+
+    @Override
+    public boolean isVoidMethod() {
+        init();
+        return delegate.isVoidMethod();
+    }
+
+    @Override
+    public Statement getCode() {
+        init();
+        return delegate.getCode();
+    }
+
+    @Override
+    public void setCode(Statement code) {
+        init();
+        delegate.setCode(code);
+    }
+
+    @Override
+    public int getModifiers() {
+        init();
+        return delegate.getModifiers();
+    }
+
+    @Override
+    public void setModifiers(int modifiers) {
+        init();
+        delegate.setModifiers(modifiers);
+    }
+
+    @Override
+    public String getName() {
+        init();
+        return delegate.getName();
+    }
+
+    @Override
+    public Parameter[] getParameters() {
+        init();
+        return delegate.getParameters();
+    }
+
+    @Override
+    public void setParameters(Parameter[] parameters) {
+        init();
+        delegate.setParameters(parameters);
+    }
+
+    @Override
+    public ClassNode getReturnType() {
+        init();
+        return delegate.getReturnType();
+    }
+
+    @Override
+    public VariableScope getVariableScope() {
+        init();
+        return delegate.getVariableScope();
+    }
+
+    @Override
+    public void setVariableScope(VariableScope variableScope) {
+        init();
+        delegate.setVariableScope(variableScope);
+    }
+
+    @Override
+    public boolean isDynamicReturnType() {
+        init();
+        return delegate.isDynamicReturnType();
+    }
+
+    @Override
+    public boolean isAbstract() {
+        init();
+        return delegate.isAbstract();
+    }
+
+    @Override
+    public boolean isStatic() {
+        init();
+        return delegate.isStatic();
+    }
+
+    @Override
+    public boolean isPublic() {
+        init();
+        return delegate.isPublic();
+    }
+
+    @Override
+    public boolean isPrivate() {
+        init();
+        return delegate.isPrivate();
+    }
+
+    @Override
+    public boolean isFinal() {
+        init();
+        return delegate.isFinal();
+    }
+
+    @Override
+    public boolean isProtected() {
+        init();
+        return delegate.isProtected();
+    }
+
+    @Override
+    public boolean isPackageScope() {
+        init();
+        return delegate.isPackageScope();
+    }
+
+    @Override
+    public boolean hasDefaultValue() {
+        init();
+        return delegate.hasDefaultValue();
+    }
+
+    @Override
+    public boolean isScriptBody() {
+        init();
+        return delegate.isScriptBody();
+    }
+
+    @Override
+    public void setIsScriptBody() {
+        init();
+        delegate.setIsScriptBody();
+    }
+
+    @Override
+    public String toString() {
+        init();
+        return delegate.toString();
+    }
+
+    @Override
+    public void setReturnType(ClassNode returnType) {
+        init();
+        delegate.setReturnType(returnType);
+    }
+
+    @Override
+    public ClassNode[] getExceptions() {
+        init();
+        return delegate.getExceptions();
+    }
+
+    @Override
+    public Statement getFirstStatement() {
+        init();
+        return delegate.getFirstStatement();
+    }
+
+    @Override
+    public GenericsType[] getGenericsTypes() {
+        init();
+        return delegate.getGenericsTypes();
+    }
+
+    @Override
+    public void setGenericsTypes(GenericsType[] genericsTypes) {
+        init();
+        delegate.setGenericsTypes(genericsTypes);
+    }
+
+    @Override
+    public void setAnnotationDefault(boolean b) {
+        init();
+        delegate.setAnnotationDefault(b);
+    }
+
+    @Override
+    public boolean hasAnnotationDefault() {
+        init();
+        return delegate.hasAnnotationDefault();
+    }
+
+    @Override
+    public boolean isStaticConstructor() {
+        init();
+        return delegate.isStaticConstructor();
+    }
+
+    @Override
+    public boolean isSyntheticPublic() {
+        init();
+        return delegate.isSyntheticPublic();
+    }
+
+    @Override
+    public void setSyntheticPublic(boolean syntheticPublic) {
+        init();
+        delegate.setSyntheticPublic(syntheticPublic);
+    }
+
+    @Override
+    public String getText() {
+        init();
+        return delegate.getText();
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations() {
+        init();
+        return delegate.getAnnotations();
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations(ClassNode type) {
+        init();
+        return delegate.getAnnotations(type);
+    }
+
+    @Override
+    public void addAnnotation(AnnotationNode value) {
+        init();
+        delegate.addAnnotation(value);
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        init();
+        delegate.addAnnotations(annotations);
+    }
+
+    @Override
+    public boolean isSynthetic() {
+        init();
+        return delegate.isSynthetic();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        init();
+        delegate.setSynthetic(synthetic);
+    }
+
+    @Override
+    public ClassNode getDeclaringClass() {
+        init();
+        return delegate.getDeclaringClass();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        super.setDeclaringClass(declaringClass);
+    }
+
+    @Override
+    public boolean hasNoRealSourcePosition() {
+        init();
+        return delegate.hasNoRealSourcePosition();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean value) {
+        init();
+        delegate.setHasNoRealSourcePosition(value);
+    }
+
+    @Override
+    public void visit(GroovyCodeVisitor visitor) {
+        init();
+        delegate.visit(visitor);
+    }
+
+    @Override
+    public int getLineNumber() {
+        init();
+        return delegate.getLineNumber();
+    }
+
+    @Override
+    public void setLineNumber(int lineNumber) {
+        init();
+        delegate.setLineNumber(lineNumber);
+    }
+
+    @Override
+    public int getColumnNumber() {
+        init();
+        return delegate.getColumnNumber();
+    }
+
+    @Override
+    public void setColumnNumber(int columnNumber) {
+        init();
+        delegate.setColumnNumber(columnNumber);
+    }
+
+    @Override
+    public int getLastLineNumber() {
+        init();
+        return delegate.getLastLineNumber();
+    }
+
+    @Override
+    public void setLastLineNumber(int lastLineNumber) {
+        init();
+        delegate.setLastLineNumber(lastLineNumber);
+    }
+
+    @Override
+    public int getLastColumnNumber() {
+        init();
+        return delegate.getLastColumnNumber();
+    }
+
+    @Override
+    public void setLastColumnNumber(int lastColumnNumber) {
+        init();
+        delegate.setLastColumnNumber(lastColumnNumber);
+    }
+
+    @Override
+    public void setSourcePosition(ASTNode node) {
+        init();
+        delegate.setSourcePosition(node);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        init();
+        return delegate.getNodeMetaData(key);
+    }
+
+    @Override
+    public void copyNodeMetaData(ASTNode other) {
+        init();
+        delegate.copyNodeMetaData(other);
+    }
+
+    @Override
+    public void setNodeMetaData(Object key, Object value) {
+        init();
+        delegate.setNodeMetaData(key, value);
+    }
+
+    @Override
+    public Object putNodeMetaData(Object key, Object value) {
+        init();
+        return delegate.putNodeMetaData(key, value);
+    }
+
+    @Override
+    public void removeNodeMetaData(Object key) {
+        init();
+        delegate.removeNodeMetaData(key);
+    }
+
+    @Override
+    public Map<?, ?> getNodeMetaData() {
+        init();
+        return delegate.getNodeMetaData();
+    }
+
+    @Override
+    public ListHashMap getMetaDataMap() {
+        init();
+        return delegate.getMetaDataMap();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        init();
+        return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+        init();
+        return delegate.hashCode();
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/LazyFieldNode.java b/src/main/java/org/codehaus/groovy/ast/decompiled/LazyFieldNode.java
new file mode 100644
index 0000000..d279c14
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/LazyFieldNode.java
@@ -0,0 +1,403 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.decompiled;
+
+import org.apache.groovy.internal.util.Supplier;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.util.ListHashMap;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents lazy field node, which will be initialized only when accessed
+ *
+ * @since 2.5.9
+ */
+public class LazyFieldNode extends FieldNode {
+    private final Supplier<FieldNode> fieldNodeSupplier;
+    private FieldNode delegate;
+    private boolean initialized;
+
+    private String name;
+
+    public LazyFieldNode(Supplier<FieldNode> fieldNodeSupplier, String name) {
+        this.fieldNodeSupplier = fieldNodeSupplier;
+        this.name = name;
+    }
+
+    private void init() {
+        if (initialized) return;
+        delegate = fieldNodeSupplier.get();
+
+        ClassNode declaringClass = super.getDeclaringClass();
+        if (null != declaringClass) delegate.setDeclaringClass(declaringClass);
+
+        ClassNode owner = super.getOwner();
+        if (null != owner) delegate.setOwner(owner);
+
+        initialized = true;
+    }
+
+    @Override
+    public Expression getInitialExpression() {
+        init();
+        return delegate.getInitialExpression();
+    }
+
+    @Override
+    public int getModifiers() {
+        init();
+        return delegate.getModifiers();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public ClassNode getType() {
+        init();
+        return delegate.getType();
+    }
+
+    @Override
+    public void setType(ClassNode type) {
+        init();
+        delegate.setType(type);
+    }
+
+    @Override
+    public ClassNode getOwner() {
+        init();
+        return delegate.getOwner();
+    }
+
+    @Override
+    public boolean isHolder() {
+        init();
+        return delegate.isHolder();
+    }
+
+    @Override
+    public void setHolder(boolean holder) {
+        init();
+        delegate.setHolder(holder);
+    }
+
+    @Override
+    public boolean isDynamicTyped() {
+        init();
+        return delegate.isDynamicTyped();
+    }
+
+    @Override
+    public void setModifiers(int modifiers) {
+        init();
+        delegate.setModifiers(modifiers);
+    }
+
+    @Override
+    public boolean isStatic() {
+        init();
+        return delegate.isStatic();
+    }
+
+    @Override
+    public boolean isEnum() {
+        init();
+        return delegate.isEnum();
+    }
+
+    @Override
+    public boolean isFinal() {
+        init();
+        return delegate.isFinal();
+    }
+
+    @Override
+    public boolean isVolatile() {
+        init();
+        return delegate.isVolatile();
+    }
+
+    @Override
+    public boolean isPublic() {
+        init();
+        return delegate.isPublic();
+    }
+
+    @Override
+    public boolean isProtected() {
+        init();
+        return delegate.isProtected();
+    }
+
+    @Override
+    public boolean isPrivate() {
+        init();
+        return delegate.isPrivate();
+    }
+
+    @Override
+    public void setOwner(ClassNode owner) {
+        super.setOwner(owner);
+    }
+
+    @Override
+    public boolean hasInitialExpression() {
+        init();
+        return delegate.hasInitialExpression();
+    }
+
+    @Override
+    public boolean isInStaticContext() {
+        init();
+        return delegate.isInStaticContext();
+    }
+
+    @Override
+    public Expression getInitialValueExpression() {
+        init();
+        return delegate.getInitialValueExpression();
+    }
+
+    @Override
+    public void setInitialValueExpression(Expression initialValueExpression) {
+        init();
+        delegate.setInitialValueExpression(initialValueExpression);
+    }
+
+    @Override
+    @Deprecated
+    public boolean isClosureSharedVariable() {
+        init();
+        return delegate.isClosureSharedVariable();
+    }
+
+    @Override
+    @Deprecated
+    public void setClosureSharedVariable(boolean inClosure) {
+        init();
+        delegate.setClosureSharedVariable(inClosure);
+    }
+
+    @Override
+    public ClassNode getOriginType() {
+        init();
+        return delegate.getOriginType();
+    }
+
+    @Override
+    public void setOriginType(ClassNode cn) {
+        init();
+        delegate.setOriginType(cn);
+    }
+
+    @Override
+    public void rename(String name) {
+        init();
+        delegate.rename(name);
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations() {
+        init();
+        return delegate.getAnnotations();
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations(ClassNode type) {
+        init();
+        return delegate.getAnnotations(type);
+    }
+
+    @Override
+    public void addAnnotation(AnnotationNode value) {
+        init();
+        delegate.addAnnotation(value);
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        init();
+        delegate.addAnnotations(annotations);
+    }
+
+    @Override
+    public boolean isSynthetic() {
+        init();
+        return delegate.isSynthetic();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        init();
+        delegate.setSynthetic(synthetic);
+    }
+
+    @Override
+    public ClassNode getDeclaringClass() {
+        init();
+        return delegate.getDeclaringClass();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        super.setDeclaringClass(declaringClass);
+    }
+
+    @Override
+    public boolean hasNoRealSourcePosition() {
+        init();
+        return delegate.hasNoRealSourcePosition();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean value) {
+        init();
+        delegate.setHasNoRealSourcePosition(value);
+    }
+
+    @Override
+    public void visit(GroovyCodeVisitor visitor) {
+        init();
+        delegate.visit(visitor);
+    }
+
+    @Override
+    public String getText() {
+        init();
+        return delegate.getText();
+    }
+
+    @Override
+    public int getLineNumber() {
+        init();
+        return delegate.getLineNumber();
+    }
+
+    @Override
+    public void setLineNumber(int lineNumber) {
+        init();
+        delegate.setLineNumber(lineNumber);
+    }
+
+    @Override
+    public int getColumnNumber() {
+        init();
+        return delegate.getColumnNumber();
+    }
+
+    @Override
+    public void setColumnNumber(int columnNumber) {
+        init();
+        delegate.setColumnNumber(columnNumber);
+    }
+
+    @Override
+    public int getLastLineNumber() {
+        init();
+        return delegate.getLastLineNumber();
+    }
+
+    @Override
+    public void setLastLineNumber(int lastLineNumber) {
+        init();
+        delegate.setLastLineNumber(lastLineNumber);
+    }
+
+    @Override
+    public int getLastColumnNumber() {
+        init();
+        return delegate.getLastColumnNumber();
+    }
+
+    @Override
+    public void setLastColumnNumber(int lastColumnNumber) {
+        init();
+        delegate.setLastColumnNumber(lastColumnNumber);
+    }
+
+    @Override
+    public void setSourcePosition(ASTNode node) {
+        init();
+        delegate.setSourcePosition(node);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        init();
+        return delegate.getNodeMetaData(key);
+    }
+
+    @Override
+    public void copyNodeMetaData(ASTNode other) {
+        init();
+        delegate.copyNodeMetaData(other);
+    }
+
+    @Override
+    public void setNodeMetaData(Object key, Object value) {
+        init();
+        delegate.setNodeMetaData(key, value);
+    }
+
+    @Override
+    public Object putNodeMetaData(Object key, Object value) {
+        init();
+        return delegate.putNodeMetaData(key, value);
+    }
+
+    @Override
+    public void removeNodeMetaData(Object key) {
+        init();
+        delegate.removeNodeMetaData(key);
+    }
+
+    @Override
+    public Map<?, ?> getNodeMetaData() {
+        init();
+        return delegate.getNodeMetaData();
+    }
+
+    @Override
+    public ListHashMap getMetaDataMap() {
+        init();
+        return delegate.getMetaDataMap();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        init();
+        return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+        init();
+        return delegate.hashCode();
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/LazyMethodNode.java b/src/main/java/org/codehaus/groovy/ast/decompiled/LazyMethodNode.java
new file mode 100644
index 0000000..1da3e94
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/LazyMethodNode.java
@@ -0,0 +1,444 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.decompiled;
+
+import org.apache.groovy.internal.util.Supplier;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.util.ListHashMap;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents lazy method node, which will be initialized only when accessed
+ *
+ * @since 2.5.9
+ */
+public class LazyMethodNode extends MethodNode {
+    private final Supplier<MethodNode> methodNodeSupplier;
+    private MethodNode delegate;
+    private boolean initialized;
+
+    private String name;
+
+    public LazyMethodNode(Supplier<MethodNode> methodNodeSupplier, String name) {
+        this.methodNodeSupplier = methodNodeSupplier;
+        this.name = name;
+    }
+
+    private void init() {
+        if (initialized) return;
+        delegate = methodNodeSupplier.get();
+
+        ClassNode declaringClass = super.getDeclaringClass();
+        if (null != declaringClass) delegate.setDeclaringClass(declaringClass);
+
+        initialized = true;
+    }
+
+    @Override
+    public String getTypeDescriptor() {
+        init();
+        return delegate.getTypeDescriptor();
+    }
+
+    @Override
+    public boolean isVoidMethod() {
+        init();
+        return delegate.isVoidMethod();
+    }
+
+    @Override
+    public Statement getCode() {
+        init();
+        return delegate.getCode();
+    }
+
+    @Override
+    public void setCode(Statement code) {
+        init();
+        delegate.setCode(code);
+    }
+
+    @Override
+    public int getModifiers() {
+        init();
+        return delegate.getModifiers();
+    }
+
+    @Override
+    public void setModifiers(int modifiers) {
+        init();
+        delegate.setModifiers(modifiers);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Parameter[] getParameters() {
+        init();
+        return delegate.getParameters();
+    }
+
+    @Override
+    public void setParameters(Parameter[] parameters) {
+        init();
+        delegate.setParameters(parameters);
+    }
+
+    @Override
+    public ClassNode getReturnType() {
+        init();
+        return delegate.getReturnType();
+    }
+
+    @Override
+    public VariableScope getVariableScope() {
+        init();
+        return delegate.getVariableScope();
+    }
+
+    @Override
+    public void setVariableScope(VariableScope variableScope) {
+        init();
+        delegate.setVariableScope(variableScope);
+    }
+
+    @Override
+    public boolean isDynamicReturnType() {
+        init();
+        return delegate.isDynamicReturnType();
+    }
+
+    @Override
+    public boolean isAbstract() {
+        init();
+        return delegate.isAbstract();
+    }
+
+    @Override
+    public boolean isStatic() {
+        init();
+        return delegate.isStatic();
+    }
+
+    @Override
+    public boolean isPublic() {
+        init();
+        return delegate.isPublic();
+    }
+
+    @Override
+    public boolean isPrivate() {
+        init();
+        return delegate.isPrivate();
+    }
+
+    @Override
+    public boolean isFinal() {
+        init();
+        return delegate.isFinal();
+    }
+
+    @Override
+    public boolean isProtected() {
+        init();
+        return delegate.isProtected();
+    }
+
+    @Override
+    public boolean isPackageScope() {
+        init();
+        return delegate.isPackageScope();
+    }
+
+    @Override
+    public boolean hasDefaultValue() {
+        init();
+        return delegate.hasDefaultValue();
+    }
+
+    @Override
+    public boolean isScriptBody() {
+        init();
+        return delegate.isScriptBody();
+    }
+
+    @Override
+    public void setIsScriptBody() {
+        init();
+        delegate.setIsScriptBody();
+    }
+
+    @Override
+    public String toString() {
+        init();
+        return delegate.toString();
+    }
+
+    @Override
+    public void setReturnType(ClassNode returnType) {
+        init();
+        delegate.setReturnType(returnType);
+    }
+
+    @Override
+    public ClassNode[] getExceptions() {
+        init();
+        return delegate.getExceptions();
+    }
+
+    @Override
+    public Statement getFirstStatement() {
+        init();
+        return delegate.getFirstStatement();
+    }
+
+    @Override
+    public GenericsType[] getGenericsTypes() {
+        init();
+        return delegate.getGenericsTypes();
+    }
+
+    @Override
+    public void setGenericsTypes(GenericsType[] genericsTypes) {
+        init();
+        delegate.setGenericsTypes(genericsTypes);
+    }
+
+    @Override
+    public void setAnnotationDefault(boolean b) {
+        init();
+        delegate.setAnnotationDefault(b);
+    }
+
+    @Override
+    public boolean hasAnnotationDefault() {
+        init();
+        return delegate.hasAnnotationDefault();
+    }
+
+    @Override
+    public boolean isStaticConstructor() {
+        init();
+        return delegate.isStaticConstructor();
+    }
+
+    @Override
+    public boolean isSyntheticPublic() {
+        init();
+        return delegate.isSyntheticPublic();
+    }
+
+    @Override
+    public void setSyntheticPublic(boolean syntheticPublic) {
+        init();
+        delegate.setSyntheticPublic(syntheticPublic);
+    }
+
+    @Override
+    public String getText() {
+        init();
+        return delegate.getText();
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations() {
+        init();
+        return delegate.getAnnotations();
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations(ClassNode type) {
+        init();
+        return delegate.getAnnotations(type);
+    }
+
+    @Override
+    public void addAnnotation(AnnotationNode value) {
+        init();
+        delegate.addAnnotation(value);
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        init();
+        delegate.addAnnotations(annotations);
+    }
+
+    @Override
+    public boolean isSynthetic() {
+        init();
+        return delegate.isSynthetic();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        init();
+        delegate.setSynthetic(synthetic);
+    }
+
+    @Override
+    public ClassNode getDeclaringClass() {
+        init();
+        return delegate.getDeclaringClass();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        super.setDeclaringClass(declaringClass);
+    }
+
+    @Override
+    public boolean hasNoRealSourcePosition() {
+        init();
+        return delegate.hasNoRealSourcePosition();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean value) {
+        init();
+        delegate.setHasNoRealSourcePosition(value);
+    }
+
+    @Override
+    public void visit(GroovyCodeVisitor visitor) {
+        init();
+        delegate.visit(visitor);
+    }
+
+    @Override
+    public int getLineNumber() {
+        init();
+        return delegate.getLineNumber();
+    }
+
+    @Override
+    public void setLineNumber(int lineNumber) {
+        init();
+        delegate.setLineNumber(lineNumber);
+    }
+
+    @Override
+    public int getColumnNumber() {
+        init();
+        return delegate.getColumnNumber();
+    }
+
+    @Override
+    public void setColumnNumber(int columnNumber) {
+        init();
+        delegate.setColumnNumber(columnNumber);
+    }
+
+    @Override
+    public int getLastLineNumber() {
+        init();
+        return delegate.getLastLineNumber();
+    }
+
+    @Override
+    public void setLastLineNumber(int lastLineNumber) {
+        init();
+        delegate.setLastLineNumber(lastLineNumber);
+    }
+
+    @Override
+    public int getLastColumnNumber() {
+        init();
+        return delegate.getLastColumnNumber();
+    }
+
+    @Override
+    public void setLastColumnNumber(int lastColumnNumber) {
+        init();
+        delegate.setLastColumnNumber(lastColumnNumber);
+    }
+
+    @Override
+    public void setSourcePosition(ASTNode node) {
+        init();
+        delegate.setSourcePosition(node);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        init();
+        return delegate.getNodeMetaData(key);
+    }
+
+    @Override
+    public void copyNodeMetaData(ASTNode other) {
+        init();
+        delegate.copyNodeMetaData(other);
+    }
+
+    @Override
+    public void setNodeMetaData(Object key, Object value) {
+        init();
+        delegate.setNodeMetaData(key, value);
+    }
+
+    @Override
+    public Object putNodeMetaData(Object key, Object value) {
+        init();
+        return delegate.putNodeMetaData(key, value);
+    }
+
+    @Override
+    public void removeNodeMetaData(Object key) {
+        init();
+        delegate.removeNodeMetaData(key);
+    }
+
+    @Override
+    public Map<?, ?> getNodeMetaData() {
+        init();
+        return delegate.getNodeMetaData();
+    }
+
+    @Override
+    public ListHashMap getMetaDataMap() {
+        init();
+        return delegate.getMetaDataMap();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        init();
+        return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+        init();
+        return delegate.hashCode();
+    }
+}
diff --git a/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy9352Test.groovy b/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy9352Test.groovy
new file mode 100644
index 0000000..4eddd70
--- /dev/null
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy9352Test.groovy
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.ant
+
+class Groovy9352Test extends AntTestCase {
+    void test() {
+        doInTmpDir { ant, baseDir ->
+            baseDir.src {
+                p1 {
+                    'Consumer.groovy'('''
+                        package p1
+                        import groovy.transform.CompileStatic
+                        import p2.Producer
+                        
+                        @CompileStatic
+                        class Consumer {
+                           void doSomething(Producer producer) {
+                              // this shouldn't trigger a compile error
+                              producer.foo()
+                           }
+                        
+                        }
+                    ''')
+                }
+                p2 {
+                    'Producer.java'('''
+                        package p2;
+                        import java.util.List;
+                        import java.util.ArrayList;
+                        
+                        public class Producer {
+                           public void foo() {}
+                        
+                           // the following members are private, they shouldn't leak into the public API
+                           private Gson gson;
+                           private Gson gson2 = new SubGson();
+                           private List<Gson> gsonList;
+                           private List<? extends Gson> gsonList2 = new ArrayList<SubGson>();
+                           
+                           private Producer(Gson p) {}
+                           private Producer(int p) throws Gson {}
+                           private Producer() { gson = new Gson(); }
+                           
+                           private void bar(Gson p) {}
+                           private Gson bar() { return null;}
+                           private void bar(int p) throws Gson {}
+                           private Object bar(float p) { return new Gson(); }
+                        }
+                    ''')
+                    'Gson.java'('''
+                        package p2;
+                        class Gson extends Exception {
+                        }
+                    ''')
+                    'SubGson.java'('''
+                        package p2;
+                        class SubGson extends Gson {
+                        }
+                    ''')
+                }
+            }
+
+            ant.mkdir(dir: 'build')
+            ant.taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc')
+
+            // 1) compile the Java source code only
+            ant.groovyc(srcdir: 'src', destdir: 'build', includes: 'p2/*' /*, keepStubs: true*/) {
+                javac()
+            }
+
+            // 2) delete `Gson` and `SubGson` related files: "Gson.java", "Gson.class", "SubGson.java" and "SubGson.class"
+            assert new File(ant.project.baseDir,"src/p2/Gson.java").delete()
+            assert new File(ant.project.baseDir,"build/p2/Gson.class").delete()
+            assert new File(ant.project.baseDir,"src/p2/SubGson.java").delete()
+            assert new File(ant.project.baseDir,"build/p2/SubGson.class").delete()
+
+            // 3) compile the Groovy source code
+            ant.groovyc(srcdir: 'src', destdir: 'build', includes: 'p1/*'){
+                classpath { pathelement(path: 'build') }
+            }
+        }
+    }
+}