Skip to content

Commit

Permalink
GROOVY-10756: fix erasure (like ResolveVisitor#resolveGenericsHeader)
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Aug 24, 2023
1 parent 38d5c99 commit fe1e89c
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 153 deletions.
119 changes: 57 additions & 62 deletions src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,52 +70,55 @@
import java.security.PrivilegedAction;
import java.util.List;

import static org.codehaus.groovy.runtime.MetaClassHelper.EMPTY_CLASS_ARRAY;

/**
* Java 8 based functions.
*
* @since 2.5.0
*/
public class Java8 implements VMPlugin {

private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class[0];
private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
private static final Permission ACCESS_PERMISSION = new ReflectPermission("suppressAccessChecks");

public static GenericsType configureTypeVariableDefinition(final ClassNode base, final ClassNode[] cBounds) {
public static GenericsType configureTypeVariableDefinition(final ClassNode base, final ClassNode[] bounds) {
ClassNode redirect = base.redirect();
base.setRedirect(null);
GenericsType gt;
if (cBounds == null || cBounds.length == 0) {
if (bounds == null || bounds.length == 0) {
gt = new GenericsType(base);
} else {
gt = new GenericsType(base, cBounds, null);
// GROOVY-10756: fix erasure -- ResolveVisitor#resolveGenericsHeader
if (!ClassHelper.OBJECT_TYPE.equals(bounds[0])) redirect = bounds[0];
gt = new GenericsType(base, bounds, null);
gt.setName(base.getName());
gt.setPlaceholder(true);
}
base.setRedirect(redirect);
return gt;
}

private static ClassNode configureClass(final Class<?> c) {
if (c.isPrimitive()) {
return ClassHelper.make(c);
} else {
return ClassHelper.makeWithoutCaching(c, false);
}
}

public static ClassNode configureTypeVariableReference(final String name) {
ClassNode cn = ClassHelper.makeWithoutCaching(name);
cn.setGenericsPlaceHolder(true);
ClassNode cn2 = ClassHelper.makeWithoutCaching(name);
cn2.setGenericsPlaceHolder(true);
GenericsType[] gts = new GenericsType[]{new GenericsType(cn2)};
cn.setGenericsTypes(gts);

cn.setGenericsTypes(new GenericsType[]{new GenericsType(cn2)});
cn.setRedirect(ClassHelper.OBJECT_TYPE);
return cn;
}

private static ClassNode configureClass(final Class<?> c) {
if (c.isPrimitive()) {
return ClassHelper.make(c);
} else {
return ClassHelper.makeWithoutCaching(c, false);
}
}

private static void setRetentionPolicy(final RetentionPolicy value, final AnnotationNode node) {
switch (value) {
case RUNTIME:
Expand All @@ -132,11 +135,7 @@ private static void setRetentionPolicy(final RetentionPolicy value, final Annota
}
}

private static void setMethodDefaultValue(final MethodNode mn, final Method m) {
ConstantExpression cExp = new ConstantExpression(m.getDefaultValue());
mn.setCode(new ReturnStatement(cExp));
mn.setAnnotationDefault(true);
}
//--------------------------------------------------------------------------

@Override
public Class<?>[] getPluginDefaultGroovyMethods() {
Expand Down Expand Up @@ -187,27 +186,7 @@ protected int getElementCode(final ElementType value) {

@Override
public void setAdditionalClassInformation(final ClassNode cn) {
setGenericsTypes(cn);
}

private void setGenericsTypes(final ClassNode cn) {
TypeVariable[] tvs = cn.getTypeClass().getTypeParameters();
GenericsType[] gts = configureTypeVariable(tvs);
cn.setGenericsTypes(gts);
}

private GenericsType[] configureTypeVariable(final TypeVariable[] tvs) {
final int n = tvs.length;
if (n == 0) return null;
GenericsType[] gts = new GenericsType[n];
for (int i = 0; i < n; i += 1) {
gts[i] = configureTypeVariableDefinition(tvs[i]);
}
return gts;
}

private GenericsType configureTypeVariableDefinition(final TypeVariable tv) {
return configureTypeVariableDefinition(configureTypeVariableReference(tv.getName()), configureTypes(tv.getBounds()));
cn.setGenericsTypes(configureTypeParameters(cn.getTypeClass().getTypeParameters()));
}

private ClassNode[] configureTypes(final Type[] types) {
Expand All @@ -228,7 +207,7 @@ private ClassNode configureType(final Type type) {
} else if (type instanceof GenericArrayType) {
return configureGenericArray((GenericArrayType) type);
} else if (type instanceof TypeVariable) {
return configureTypeVariableReference(((TypeVariable) type).getName());
return configureTypeVariableReference(((TypeVariable<?>) type).getName());
} else if (type instanceof Class) {
return configureClass((Class<?>) type);
} else if (type == null) {
Expand Down Expand Up @@ -286,6 +265,18 @@ private GenericsType[] configureTypeArguments(final Type[] ta) {
return gts;
}

private GenericsType[] configureTypeParameters(final TypeVariable<?>[] tp) {
final int n = tp.length;
if (n == 0) return null;
GenericsType[] gt = new GenericsType[n];
for (int i = 0; i < n; i += 1) {
ClassNode t = configureTypeVariableReference(tp[i].getName());
ClassNode[] bounds = configureTypes(tp[i].getBounds());
gt[i] = configureTypeVariableDefinition(t, bounds);
}
return gt;
}

//

@Override
Expand Down Expand Up @@ -378,8 +369,7 @@ private Expression toAnnotationValueExpression(final Object value) {

@Override
public void configureAnnotationNodeFromDefinition(final AnnotationNode definition, final AnnotationNode root) {
ClassNode type = definition.getClassNode();
final String typeName = type.getName();
String typeName = definition.getClassNode().getName();
if ("java.lang.annotation.Retention".equals(typeName)) {
Expression exp = definition.getMember("value");
if (!(exp instanceof PropertyExpression)) return;
Expand All @@ -390,16 +380,16 @@ public void configureAnnotationNodeFromDefinition(final AnnotationNode definitio
} else if ("java.lang.annotation.Target".equals(typeName)) {
Expression exp = definition.getMember("value");
if (!(exp instanceof ListExpression)) return;
ListExpression le = (ListExpression) exp;
int bitmap = 0;
for (Expression e : le.getExpressions()) {
ListExpression list = (ListExpression) exp;
int targets = 0;
for (Expression e : list.getExpressions()) {
if (!(e instanceof PropertyExpression)) return;
PropertyExpression element = (PropertyExpression) e;
String name = element.getPropertyAsString();
ElementType value = ElementType.valueOf(name);
bitmap |= getElementCode(value);
ElementType type = ElementType.valueOf(name);
targets |= getElementCode(type);
}
root.setAllowedTargets(bitmap);
root.setAllowedTargets(targets);
}
}

Expand All @@ -409,29 +399,32 @@ public void configureClassNode(final CompileUnit compileUnit, final ClassNode cl
Class<?> clazz = classNode.getTypeClass();
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
ClassNode ret = makeClassNode(compileUnit, f.getGenericType(), f.getType());
FieldNode fn = new FieldNode(f.getName(), f.getModifiers(), ret, classNode, null);
ClassNode rt = makeClassNode(compileUnit, f.getGenericType(), f.getType());
FieldNode fn = new FieldNode(f.getName(), f.getModifiers(), rt, classNode, null);
setAnnotationMetaData(f.getAnnotations(), fn);
classNode.addField(fn);
}
Method[] methods = clazz.getDeclaredMethods();
for (Method m : methods) {
ClassNode ret = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType());
ClassNode rt = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType());
Parameter[] params = makeParameters(compileUnit, m.getGenericParameterTypes(), m.getParameterTypes(), m.getParameterAnnotations(), m);
ClassNode[] exceptions = makeClassNodes(compileUnit, m.getGenericExceptionTypes(), m.getExceptionTypes());
MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ret, params, exceptions, null);
mn.setSynthetic(m.isSynthetic());
setMethodDefaultValue(mn, m);
MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), rt, params, exceptions, null);
setAnnotationMetaData(m.getAnnotations(), mn);
mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters()));
if (true) { // TODO: GROOVY-10862
mn.setAnnotationDefault(true);
mn.setCode(new ReturnStatement(new ConstantExpression(m.getDefaultValue())));
}
mn.setGenericsTypes(configureTypeParameters(m.getTypeParameters()));
mn.setSynthetic(m.isSynthetic());
classNode.addMethod(mn);
}
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> ctor : constructors) {
Parameter[] params = makeParameters(compileUnit, ctor.getGenericParameterTypes(), ctor.getParameterTypes(), getConstructorParameterAnnotations(ctor), ctor);
ClassNode[] exceptions = makeClassNodes(compileUnit, ctor.getGenericExceptionTypes(), ctor.getExceptionTypes());
ConstructorNode cn = classNode.addConstructor(ctor.getModifiers(), params, exceptions, null);
setAnnotationMetaData(ctor.getAnnotations(), cn);
for (Constructor<?> c : constructors) {
Parameter[] params = makeParameters(compileUnit, c.getGenericParameterTypes(), c.getParameterTypes(), getConstructorParameterAnnotations(c), c);
ClassNode[] exceptions = makeClassNodes(compileUnit, c.getGenericExceptionTypes(), c.getExceptionTypes());
ConstructorNode cn = classNode.addConstructor(c.getModifiers(), params, exceptions, null);
setAnnotationMetaData(c.getAnnotations(), cn);
}

Class<?> sc = clazz.getSuperclass();
Expand Down Expand Up @@ -572,7 +565,7 @@ private Parameter[] makeParameters(final CompileUnit cu, final Type[] types, fin
fillParameterNames(names, member);
for (int i = 0; i < n; i += 1) {
setAnnotationMetaData(parameterAnnotations[i],
params[i] = new Parameter(makeClassNode(cu, types[i], cls[i]), names[i]));
params[i] = new Parameter(makeClassNode(cu, types[i], cls[i]), names[i]));
}
}
return params;
Expand All @@ -589,6 +582,8 @@ protected void fillParameterNames(final String[] names, final Member member) {
}
}

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

/**
* The following scenarios can not set accessible, i.e. the return value is false
* 1) SecurityException occurred
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,11 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
def file = Pogo10756.files[0]
file?.name
"""

assertScript """import ${Pogo10756.name.replace('$','.')}
def files = Pogo10756.files
files*.name
"""
}

static class Pogo10756 {
Expand Down
Loading

0 comments on commit fe1e89c

Please sign in to comment.