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/21 21:07:55 UTC

[groovy] branch master updated: GROOVY-9352: Static compilation fails with NoClassDefFoundError (#1129)

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

sunlan 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 d8ad0c5  GROOVY-9352: Static compilation fails with NoClassDefFoundError (#1129)
d8ad0c5 is described below

commit d8ad0c54ab072c31fd349c1bd998c4c3b4babc0e
Author: Daniel.Sun <su...@apache.org>
AuthorDate: Sun Dec 22 05:07:44 2019 +0800

    GROOVY-9352: Static compilation fails with NoClassDefFoundError (#1129)
---
 .../org/codehaus/groovy/ast/ConstructorNode.java   |   1 +
 .../java/org/codehaus/groovy/ast/FieldNode.java    |   2 +
 .../codehaus/groovy/ast/LazyConstructorNode.java   | 471 +++++++++++++++++++++
 .../org/codehaus/groovy/ast/LazyFieldNode.java     | 423 ++++++++++++++++++
 .../org/codehaus/groovy/ast/LazyMethodNode.java    | 467 ++++++++++++++++++++
 .../java/org/codehaus/groovy/ast/MethodNode.java   |   8 +-
 .../groovy/ast/decompiled/DecompiledClassNode.java |  48 ++-
 .../test/groovy/groovy/ant/Groovy9352Test.groovy   |  97 +++++
 8 files changed, 1509 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 cc266e5..28208cd 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/LazyConstructorNode.java b/src/main/java/org/codehaus/groovy/ast/LazyConstructorNode.java
new file mode 100644
index 0000000..e1c5cfb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/LazyConstructorNode.java
@@ -0,0 +1,471 @@
+/*
+ *  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;
+
+import groovy.lang.groovydoc.Groovydoc;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Represents lazy constructor node, which will be initialized only when accessed
+ *
+ * @since 3.0.0
+ */
+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 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 boolean hasDefaultValue() {
+        init();
+        return delegate.hasDefaultValue();
+    }
+
+    @Override
+    public ClassNode getReturnType() {
+        init();
+        return delegate.getReturnType();
+    }
+
+    @Override
+    public void setReturnType(ClassNode returnType) {
+        init();
+        delegate.setReturnType(returnType);
+    }
+
+    @Override
+    public boolean isDynamicReturnType() {
+        init();
+        return delegate.isDynamicReturnType();
+    }
+
+    @Override
+    public boolean isVoidMethod() {
+        init();
+        return delegate.isVoidMethod();
+    }
+
+    @Override
+    public VariableScope getVariableScope() {
+        init();
+        return delegate.getVariableScope();
+    }
+
+    @Override
+    public void setVariableScope(VariableScope variableScope) {
+        init();
+        delegate.setVariableScope(variableScope);
+    }
+
+    @Override
+    public boolean isAbstract() {
+        init();
+        return delegate.isAbstract();
+    }
+
+    @Override
+    public boolean isDefault() {
+        init();
+        return delegate.isDefault();
+    }
+
+    @Override
+    public boolean isFinal() {
+        init();
+        return delegate.isFinal();
+    }
+
+    @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 isProtected() {
+        init();
+        return delegate.isProtected();
+    }
+
+    @Override
+    public boolean isPackageScope() {
+        init();
+        return delegate.isPackageScope();
+    }
+
+    @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 boolean hasAnnotationDefault() {
+        init();
+        return delegate.hasAnnotationDefault();
+    }
+
+    @Override
+    public void setAnnotationDefault(boolean hasDefaultValue) {
+        init();
+        delegate.setAnnotationDefault(hasDefaultValue);
+    }
+
+    @Override
+    public boolean isScriptBody() {
+        init();
+        return delegate.isScriptBody();
+    }
+
+    @Override
+    public void setIsScriptBody() {
+        init();
+        delegate.setIsScriptBody();
+    }
+
+    @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 String toString() {
+        init();
+        return delegate.toString();
+    }
+
+    @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 annotation) {
+        init();
+        delegate.addAnnotation(annotation);
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        init();
+        delegate.addAnnotations(annotations);
+    }
+
+    @Override
+    public ClassNode getDeclaringClass() {
+        init();
+        return delegate.getDeclaringClass();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        super.setDeclaringClass(declaringClass);
+    }
+
+    @Override
+    public Groovydoc getGroovydoc() {
+        init();
+        return delegate.getGroovydoc();
+    }
+
+    @Override
+    public AnnotatedNode getInstance() {
+        init();
+        return delegate.getInstance();
+    }
+
+    @Override
+    public boolean hasNoRealSourcePosition() {
+        init();
+        return delegate.hasNoRealSourcePosition();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean hasNoRealSourcePosition) {
+        init();
+        delegate.setHasNoRealSourcePosition(hasNoRealSourcePosition);
+    }
+
+    @Override
+    public boolean isSynthetic() {
+        init();
+        return delegate.isSynthetic();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        init();
+        delegate.setSynthetic(synthetic);
+    }
+
+    @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 void copyNodeMetaData(ASTNode other) {
+        init();
+        delegate.copyNodeMetaData(other);
+    }
+
+    @Override
+    public Map<?, ?> getMetaDataMap() {
+        init();
+        return delegate.getMetaDataMap();
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        init();
+        delegate.setMetaDataMap(metaDataMap);
+    }
+
+    @Override
+    public int hashCode() {
+        init();
+        return delegate.hashCode();
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        init();
+        return delegate.getNodeMetaData(key);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key, Function<?, ? extends T> valFn) {
+        init();
+        return delegate.getNodeMetaData(key, valFn);
+    }
+
+    @Override
+    public void copyNodeMetaData(NodeMetaDataHandler 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();
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/LazyFieldNode.java b/src/main/java/org/codehaus/groovy/ast/LazyFieldNode.java
new file mode 100644
index 0000000..56681c8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/LazyFieldNode.java
@@ -0,0 +1,423 @@
+/*
+ *  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;
+
+import groovy.lang.groovydoc.Groovydoc;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Represents lazy field node, which will be initialized only when accessed
+ *
+ * @since 3.0.0
+ */
+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 annotation) {
+        init();
+        delegate.addAnnotation(annotation);
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        init();
+        delegate.addAnnotations(annotations);
+    }
+
+    @Override
+    public ClassNode getDeclaringClass() {
+        init();
+        return delegate.getDeclaringClass();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        super.setDeclaringClass(declaringClass);
+    }
+
+    @Override
+    public Groovydoc getGroovydoc() {
+        init();
+        return delegate.getGroovydoc();
+    }
+
+    @Override
+    public AnnotatedNode getInstance() {
+        init();
+        return delegate.getInstance();
+    }
+
+    @Override
+    public boolean hasNoRealSourcePosition() {
+        init();
+        return delegate.hasNoRealSourcePosition();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean hasNoRealSourcePosition) {
+        init();
+        delegate.setHasNoRealSourcePosition(hasNoRealSourcePosition);
+    }
+
+    @Override
+    public boolean isSynthetic() {
+        init();
+        return delegate.isSynthetic();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        init();
+        delegate.setSynthetic(synthetic);
+    }
+
+    @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 void copyNodeMetaData(ASTNode other) {
+        init();
+        delegate.copyNodeMetaData(other);
+    }
+
+    @Override
+    public Map<?, ?> getMetaDataMap() {
+        init();
+        return delegate.getMetaDataMap();
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        init();
+        delegate.setMetaDataMap(metaDataMap);
+    }
+
+    @Override
+    public int hashCode() {
+        init();
+        return delegate.hashCode();
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        init();
+        return delegate.getNodeMetaData(key);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key, Function<?, ? extends T> valFn) {
+        init();
+        return delegate.getNodeMetaData(key, valFn);
+    }
+
+    @Override
+    public void copyNodeMetaData(NodeMetaDataHandler 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();
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/LazyMethodNode.java b/src/main/java/org/codehaus/groovy/ast/LazyMethodNode.java
new file mode 100644
index 0000000..49649f4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/LazyMethodNode.java
@@ -0,0 +1,467 @@
+/*
+ *  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;
+
+import groovy.lang.groovydoc.Groovydoc;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Represents lazy method node, which will be initialized only when accessed
+ *
+ * @since 3.0.0
+ */
+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 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 boolean hasDefaultValue() {
+        init();
+        return delegate.hasDefaultValue();
+    }
+
+    @Override
+    public ClassNode getReturnType() {
+        init();
+        return delegate.getReturnType();
+    }
+
+    @Override
+    public void setReturnType(ClassNode returnType) {
+        init();
+        delegate.setReturnType(returnType);
+    }
+
+    @Override
+    public boolean isDynamicReturnType() {
+        init();
+        return delegate.isDynamicReturnType();
+    }
+
+    @Override
+    public boolean isVoidMethod() {
+        init();
+        return delegate.isVoidMethod();
+    }
+
+    @Override
+    public VariableScope getVariableScope() {
+        init();
+        return delegate.getVariableScope();
+    }
+
+    @Override
+    public void setVariableScope(VariableScope variableScope) {
+        init();
+        delegate.setVariableScope(variableScope);
+    }
+
+    @Override
+    public boolean isAbstract() {
+        init();
+        return delegate.isAbstract();
+    }
+
+    @Override
+    public boolean isDefault() {
+        init();
+        return delegate.isDefault();
+    }
+
+    @Override
+    public boolean isFinal() {
+        init();
+        return delegate.isFinal();
+    }
+
+    @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 isProtected() {
+        init();
+        return delegate.isProtected();
+    }
+
+    @Override
+    public boolean isPackageScope() {
+        init();
+        return delegate.isPackageScope();
+    }
+
+    @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 boolean hasAnnotationDefault() {
+        init();
+        return delegate.hasAnnotationDefault();
+    }
+
+    @Override
+    public void setAnnotationDefault(boolean hasDefaultValue) {
+        init();
+        delegate.setAnnotationDefault(hasDefaultValue);
+    }
+
+    @Override
+    public boolean isScriptBody() {
+        init();
+        return delegate.isScriptBody();
+    }
+
+    @Override
+    public void setIsScriptBody() {
+        init();
+        delegate.setIsScriptBody();
+    }
+
+    @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 String toString() {
+        init();
+        return delegate.toString();
+    }
+
+    @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 annotation) {
+        init();
+        delegate.addAnnotation(annotation);
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        init();
+        delegate.addAnnotations(annotations);
+    }
+
+    @Override
+    public ClassNode getDeclaringClass() {
+        init();
+        return delegate.getDeclaringClass();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        super.setDeclaringClass(declaringClass);
+    }
+
+    @Override
+    public Groovydoc getGroovydoc() {
+        init();
+        return delegate.getGroovydoc();
+    }
+
+    @Override
+    public AnnotatedNode getInstance() {
+        init();
+        return delegate.getInstance();
+    }
+
+    @Override
+    public boolean hasNoRealSourcePosition() {
+        init();
+        return delegate.hasNoRealSourcePosition();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean hasNoRealSourcePosition) {
+        init();
+        delegate.setHasNoRealSourcePosition(hasNoRealSourcePosition);
+    }
+
+    @Override
+    public boolean isSynthetic() {
+        init();
+        return delegate.isSynthetic();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        init();
+        delegate.setSynthetic(synthetic);
+    }
+
+    @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 void copyNodeMetaData(ASTNode other) {
+        init();
+        delegate.copyNodeMetaData(other);
+    }
+
+    @Override
+    public Map<?, ?> getMetaDataMap() {
+        init();
+        return delegate.getMetaDataMap();
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        init();
+        delegate.setMetaDataMap(metaDataMap);
+    }
+
+    @Override
+    public int hashCode() {
+        init();
+        return delegate.hashCode();
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        init();
+        return delegate.getNodeMetaData(key);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key, Function<?, ? extends T> valFn) {
+        init();
+        return delegate.getNodeMetaData(key, valFn);
+    }
+
+    @Override
+    public void copyNodeMetaData(NodeMetaDataHandler 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();
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/ast/MethodNode.java b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
index a9da877..216989b 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.Optional;
  */
 public class MethodNode extends AnnotatedNode implements Opcodes {
 
-    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;
@@ -49,6 +49,8 @@ public class MethodNode extends AnnotatedNode implements Opcodes {
     // cached data
     private 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..f6f15e8 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
@@ -24,12 +24,17 @@ import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.LazyConstructorNode;
+import org.codehaus.groovy.ast.LazyFieldNode;
+import org.codehaus.groovy.ast.LazyMethodNode;
 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;
+import java.util.function.Supplier;
 
 /**
  * A {@link ClassNode} kind representing the classes coming from *.class files decompiled using ASM.
@@ -191,18 +196,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 +215,40 @@ public class DecompiledClassNode extends ClassNode {
         }
     }
 
+    private FieldNode createFieldNode(final FieldStub field) {
+        Supplier<FieldNode> fieldNodeSupplier = () -> addAnnotations(field, MemberSignatureParser.createFieldNode(field, resolver, 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 = () -> 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 = () -> (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/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..566f86e
--- /dev/null
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy9352Test.groovy
@@ -0,0 +1,97 @@
+/*
+ *  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/*')
+        }
+    }
+}