Skip to content

Commit

Permalink
GROOVY-10053: accept type parameter from context as method type argument
Browse files Browse the repository at this point in the history
3_0_X backport
  • Loading branch information
eric-milles committed Dec 9, 2023
1 parent e32dfaa commit d7a6f1f
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 225 deletions.
48 changes: 20 additions & 28 deletions src/main/java/org/codehaus/groovy/ast/ClassHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
import org.codehaus.groovy.classgen.asm.util.TypeUtil;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.GeneratedLambda;
import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
import org.codehaus.groovy.transform.trait.Traits;
import org.codehaus.groovy.util.ManagedConcurrentMap;
import org.codehaus.groovy.util.ReferenceBundle;
Expand All @@ -70,6 +69,8 @@
import java.util.Map;
import java.util.regex.Pattern;

import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;

/**
* Helper for {@link ClassNode} and classes handling them. Contains a set of
* pre-defined instances for the most used types and some code for cached node
Expand Down Expand Up @@ -209,7 +210,7 @@ public static ClassNode[] make(Class[] classes) {
* A new ClassNode object is only created if the class
* is not one of the predefined ones
*
* @param c class used to created the ClassNode
* @param c class used to create the ClassNode
* @return ClassNode instance created from the given class
*/
public static ClassNode make(Class c) {
Expand Down Expand Up @@ -487,39 +488,30 @@ private static boolean hasUsableImplementation(ClassNode c, MethodNode m) {
}

/**
* Returns a super class or interface for a given class depending on a given target.
* If the target is no super class or interface, then null will be returned.
* For a non-primitive array type, returns an array of the componentType's super class
* or interface if the target is also an array.
*
* @param clazz the start class
* @param goalClazz the goal class
* @return the next super class or interface
* Returns a super class or interface for a given class depending on supplied
* target. If the target is not a super class or interface, then null will be
* returned. For a non-primitive array type -- if the target is also an array
* -- returns an array of the component type's super class or interface.
*/
public static ClassNode getNextSuperClass(ClassNode clazz, ClassNode goalClazz) {
if (clazz.isArray()) {
if (!goalClazz.isArray()) return null;
ClassNode cn = getNextSuperClass(clazz.getComponentType(), goalClazz.getComponentType());
public static ClassNode getNextSuperClass(final ClassNode source, final ClassNode target) {
if (source.isArray()) {
if (!target.isArray()) return null;

ClassNode cn = getNextSuperClass(source.getComponentType(), target.getComponentType());
if (cn != null) cn = cn.makeArray();
return cn;
}

if (!goalClazz.isInterface()) {
if (clazz.isInterface()) {
if (OBJECT_TYPE.equals(clazz)) return null;
return OBJECT_TYPE;
} else {
return clazz.getUnresolvedSuperClass();
if (target.isInterface()) {
for (ClassNode face : source.getUnresolvedInterfaces()) {
if (implementsInterfaceOrIsSubclassOf(face,target)) {
return face;
}
}
} else if (source.isInterface()) {
return OBJECT_TYPE;
}

ClassNode[] interfaces = clazz.getUnresolvedInterfaces();
for (ClassNode anInterface : interfaces) {
if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(anInterface, goalClazz)) {
return anInterface;
}
}
//none of the interfaces here match, so continue with super class
return clazz.getUnresolvedSuperClass();
return source.getUnresolvedSuperClass();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@
* @see AsmDecompiler
*/
public class DecompiledClassNode extends ClassNode {

private final ClassStub classData;
private final AsmReferenceResolver resolver;
private volatile boolean supersInitialized;
private volatile boolean membersInitialized;

public DecompiledClassNode(final ClassStub classData, final AsmReferenceResolver resolver) {
super(classData.className, getFullModifiers(classData), null, null, MixinNode.EMPTY_ARRAY);
super(classData.className, getModifiers(classData), null, null, MixinNode.EMPTY_ARRAY);
this.classData = classData;
this.resolver = resolver;
isPrimaryNode = false;
Expand All @@ -54,13 +53,14 @@ public DecompiledClassNode(final ClassStub classData, final AsmReferenceResolver
/**
* Handle the case of inner classes returning the correct modifiers from
* the INNERCLASS reference since the top-level modifiers for inner classes
* wont include static or private/protected.
* won't include static or private/protected.
*/
private static int getFullModifiers(ClassStub data) {
return (data.innerClassModifiers == -1)
? data.accessModifiers : data.innerClassModifiers;
private static int getModifiers(ClassStub classData) {
return (classData.innerClassModifiers != -1 ? classData.innerClassModifiers : classData.accessModifiers);
}

//

public long getCompilationTimeStamp() {
if (classData.fields != null) {
for (FieldStub field : classData.fields) {
Expand All @@ -76,64 +76,40 @@ public long getCompilationTimeStamp() {
}

@Override
public GenericsType[] getGenericsTypes() {
lazyInitSupers();
return super.getGenericsTypes();
}

@Override
public boolean isUsingGenerics() {
lazyInitSupers();
return super.isUsingGenerics();
}

@Override
public List<FieldNode> getFields() {
lazyInitMembers();
return super.getFields();
public Class getTypeClass() {
return resolver.resolveJvmClass(getName());
}

@Override
public ClassNode[] getInterfaces() {
lazyInitSupers();
return super.getInterfaces();
public boolean isParameterized() {
return (classData.signature != null && classData.signature.charAt(0) == '<');
}

@Override
public List<MethodNode> getMethods() {
lazyInitMembers();
return super.getMethods();
public boolean isResolved() {
return true;
}

@Override
public List<ConstructorNode> getDeclaredConstructors() {
lazyInitMembers();
return super.getDeclaredConstructors();
public String setName(String name) {
throw new UnsupportedOperationException();
}

@Override
public FieldNode getDeclaredField(String name) {
lazyInitMembers();
return super.getDeclaredField(name);
public void setRedirect(ClassNode cn) {
throw new UnsupportedOperationException();
}

@Override
public List<MethodNode> getDeclaredMethods(String name) {
lazyInitMembers();
return super.getDeclaredMethods(name);
public void setUsingGenerics(boolean b) {
throw new UnsupportedOperationException();
}

@Override
public ClassNode getUnresolvedSuperClass(boolean useRedirect) {
lazyInitSupers();
return super.getUnresolvedSuperClass(useRedirect);
public void setGenericsPlaceHolder(boolean b) {
throw new UnsupportedOperationException();
}

@Override
public ClassNode[] getUnresolvedInterfaces(boolean useRedirect) {
lazyInitSupers();
return super.getUnresolvedInterfaces(useRedirect);
}
//--------------------------------------------------------------------------

@Override
public List<AnnotationNode> getAnnotations() {
Expand All @@ -148,38 +124,36 @@ public List<AnnotationNode> getAnnotations(ClassNode type) {
}

@Override
public void setRedirect(ClassNode cn) {
throw new UnsupportedOperationException();
public GenericsType[] getGenericsTypes() {
lazyInitSupers();
return super.getGenericsTypes();
}

@Override
public void setGenericsPlaceHolder(boolean b) {
throw new UnsupportedOperationException();
public ClassNode[] getInterfaces() {
lazyInitSupers();
return super.getInterfaces();
}

@Override
public void setUsingGenerics(boolean b) {
throw new UnsupportedOperationException();
public ClassNode[] getUnresolvedInterfaces(boolean useRedirect) {
lazyInitSupers();
return super.getUnresolvedInterfaces(useRedirect);
}

@Override
public String setName(String name) {
throw new UnsupportedOperationException();
}

public boolean isParameterized() {
return (classData.signature != null && classData.signature.charAt(0) == '<');
public ClassNode getUnresolvedSuperClass(boolean useRedirect) {
lazyInitSupers();
return super.getUnresolvedSuperClass(useRedirect);
}

@Override
public boolean isResolved() {
return true;
public boolean isUsingGenerics() {
lazyInitSupers();
return super.isUsingGenerics();
}

@Override
public Class getTypeClass() {
return resolver.resolveJvmClass(getName());
}
private volatile boolean supersInitialized;

private void lazyInitSupers() {
if (supersInitialized) return;
Expand All @@ -193,14 +167,48 @@ private void lazyInitSupers() {
}
}

//--------------------------------------------------------------------------

@Override
public List<ConstructorNode> getDeclaredConstructors() {
lazyInitMembers();
return super.getDeclaredConstructors();
}

@Override
public FieldNode getDeclaredField(final String name) {
lazyInitMembers();
return super.getDeclaredField(name);
}

@Override
public List<MethodNode> getDeclaredMethods(final String name) {
lazyInitMembers();
return super.getDeclaredMethods(name);
}

@Override
public List<FieldNode> getFields() {
lazyInitMembers();
return super.getFields();
}

@Override
public List<MethodNode> getMethods() {
lazyInitMembers();
return super.getMethods();
}

private volatile boolean membersInitialized;

private void lazyInitMembers() {
if (membersInitialized) return;

synchronized (lazyInitLock) {
if (!membersInitialized) {
if (classData.methods != null) {
for (MethodStub method : classData.methods) {
if (isConstructor(method)) {
if ("<init>".equals(method.methodName)) {
addConstructor(createConstructor(method));
} else {
addMethod(createMethodNode(method));
Expand Down Expand Up @@ -249,10 +257,6 @@ private ConstructorNode createConstructor(final MethodStub method) {
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) {
Expand Down
Loading

0 comments on commit d7a6f1f

Please sign in to comment.