diff --git a/base/org.codehaus.groovy25/.checkstyle b/base/org.codehaus.groovy25/.checkstyle
index 6ea484c705..a210537437 100644
--- a/base/org.codehaus.groovy25/.checkstyle
+++ b/base/org.codehaus.groovy25/.checkstyle
@@ -68,6 +68,7 @@
+
diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/MethodNode.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/MethodNode.java
index 266c8eda37..636d2e4b52 100644
--- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/MethodNode.java
+++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/ast/MethodNode.java
@@ -31,9 +31,9 @@
* Represents a method declaration.
*/
public class MethodNode extends AnnotatedNode implements Opcodes {
-
+ /* GRECLIPSE edit
public static final String SCRIPT_BODY_METHOD_KEY = "org.codehaus.groovy.ast.MethodNode.isScriptBody";
-
+ */
private String name;
private int modifiers;
private boolean syntheticPublic;
@@ -190,11 +190,11 @@ public boolean isScriptBody() {
/* GRECLIPSE edit
return getNodeMetaData(SCRIPT_BODY_METHOD_KEY) != null;
*/
- return getDeclaringClass() != null &&
- getDeclaringClass().isScript() &&
- getName().equals("run") &&
- (parameters == null || parameters.length == 0) &&
- (returnType != null && returnType.getName().equals("java.lang.Object"));
+ return getName().equals("run")
+ && getDeclaringClass() != null
+ && getDeclaringClass().isScript()
+ && (parameters == null || parameters.length == 0)
+ && (returnType != null && returnType.getName().equals(ClassHelper.OBJECT));
// GRECLIPSE end
}
@@ -203,7 +203,9 @@ public boolean isScriptBody() {
* @see ModuleNode#createStatementsClass()
*/
public void setIsScriptBody() {
+ /* GRECLIPSE edit
setNodeMetaData(SCRIPT_BODY_METHOD_KEY, Boolean.TRUE);
+ */
}
public String toString() {
diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/AnnotationVisitor.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/AnnotationVisitor.java
index a5cb3cabb1..847f85a579 100644
--- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/AnnotationVisitor.java
+++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/AnnotationVisitor.java
@@ -142,7 +142,8 @@ private boolean checkIfMandatoryAnnotationValuesPassed(AnnotationNode node) {
/* GRECLIPSE edit
if (mn.getCode() == null && !attributes.containsKey(methodName)) {
*/
- if (!mn.hasAnnotationDefault() && !attributes.containsKey(methodName)) {
+ if (!mn.hasAnnotationDefault() && !attributes.containsKey(methodName) && !"dataVariableNames".equals(methodName)) {
+ // TODO: https://github.com/spockframework/spock/issues/1549 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// GRECLIPSE end
addError("No explicit/default value found for annotation attribute '" + methodName + "'", node);
ok = false;
diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/vmplugin/v5/Java5.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/vmplugin/v5/Java5.java
new file mode 100644
index 0000000000..c4a9cce8e1
--- /dev/null
+++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/vmplugin/v5/Java5.java
@@ -0,0 +1,552 @@
+/*
+ * 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.vmplugin.v5;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.MalformedParameterizedTypeException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.List;
+
+/**
+ * java 5 based functions
+ */
+public class Java5 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];
+
+ @Override
+ public int getVersion() {
+ return 5;
+ }
+
+ public Class[] getPluginDefaultGroovyMethods() {
+ return new Class[]{PluginDefaultGroovyMethods.class};
+ }
+
+ public Class[] getPluginStaticGroovyMethods() {
+ return EMPTY_CLASS_ARRAY;
+ }
+
+ public void setAdditionalClassInformation(ClassNode cn) {
+ setGenericsTypes(cn);
+ }
+
+ private void setGenericsTypes(ClassNode cn) {
+ TypeVariable[] tvs = cn.getTypeClass().getTypeParameters();
+ GenericsType[] gts = configureTypeVariable(tvs);
+ cn.setGenericsTypes(gts);
+ }
+
+ private GenericsType[] configureTypeVariable(TypeVariable[] tvs) {
+ if (tvs.length == 0) return null;
+ GenericsType[] gts = new GenericsType[tvs.length];
+ for (int i = 0; i < tvs.length; i++) {
+ gts[i] = configureTypeVariableDefinition(tvs[i]);
+ }
+ return gts;
+ }
+
+ private GenericsType configureTypeVariableDefinition(TypeVariable tv) {
+ return configureTypeVariableDefinition(configureTypeVariableReference(tv.getName()), configureTypes(tv.getBounds()));
+ }
+
+ public static GenericsType configureTypeVariableDefinition(ClassNode base, ClassNode[] cBounds) {
+ ClassNode redirect = base.redirect();
+ base.setRedirect(null);
+ GenericsType gt;
+ if (cBounds == null || cBounds.length == 0) {
+ gt = new GenericsType(base);
+ } else {
+ gt = new GenericsType(base, cBounds, null);
+ gt.setName(base.getName());
+ gt.setPlaceholder(true);
+ }
+ base.setRedirect(redirect);
+ return gt;
+ }
+
+ private ClassNode[] configureTypes(Type[] types) {
+ if (types.length == 0) return null;
+ ClassNode[] nodes = new ClassNode[types.length];
+ for (int i = 0; i < types.length; i++) {
+ nodes[i] = configureType(types[i]);
+ }
+ return nodes;
+ }
+
+ private ClassNode configureType(Type type) {
+ if (type instanceof WildcardType) {
+ return configureWildcardType((WildcardType) type);
+ } else if (type instanceof ParameterizedType) {
+ return configureParameterizedType((ParameterizedType) type);
+ } else if (type instanceof GenericArrayType) {
+ return configureGenericArray((GenericArrayType) type);
+ } else if (type instanceof TypeVariable) {
+ return configureTypeVariableReference(((TypeVariable) type).getName());
+ } else if (type instanceof Class) {
+ return configureClass((Class) type);
+ } else if (type==null) {
+ throw new GroovyBugError("Type is null. Most probably you let a transform reuse existing ClassNodes with generics information, that is now used in a wrong context.");
+ } else {
+ throw new GroovyBugError("unknown type: " + type + " := " + type.getClass());
+ }
+ }
+
+ private static ClassNode configureClass(Class c) {
+ if (c.isPrimitive()) {
+ return ClassHelper.make(c);
+ } else {
+ return ClassHelper.makeWithoutCaching(c, false);
+ }
+ }
+
+ private ClassNode configureGenericArray(GenericArrayType genericArrayType) {
+ Type component = genericArrayType.getGenericComponentType();
+ ClassNode node = configureType(component);
+ return node.makeArray();
+ }
+
+ private ClassNode configureWildcardType(WildcardType wildcardType) {
+ ClassNode base = ClassHelper.makeWithoutCaching("?");
+ base.setRedirect(ClassHelper.OBJECT_TYPE);
+
+ ClassNode[] lowers = configureTypes(wildcardType.getLowerBounds());
+ ClassNode[] uppers = configureTypes(wildcardType.getUpperBounds());
+ // beware of [Object] upper bounds; often it's > or super T>
+ if (lowers != null || wildcardType.toString().equals("?")) {
+ uppers = null;
+ }
+
+ GenericsType t = new GenericsType(base, uppers, lowers != null ? lowers[0] : null);
+ t.setWildcard(true);
+
+ ClassNode ref = ClassHelper.makeWithoutCaching(Object.class, false);
+ ref.setGenericsTypes(new GenericsType[]{t});
+ return ref;
+ }
+
+ private ClassNode configureParameterizedType(ParameterizedType parameterizedType) {
+ ClassNode base = configureType(parameterizedType.getRawType());
+ GenericsType[] gts = configureTypeArguments(parameterizedType.getActualTypeArguments());
+ base.setGenericsTypes(gts);
+ return base;
+ }
+
+ public static ClassNode configureTypeVariableReference(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.setRedirect(ClassHelper.OBJECT_TYPE);
+ return cn;
+ }
+
+ private GenericsType[] configureTypeArguments(Type[] ta) {
+ if (ta.length == 0) return null;
+ GenericsType[] gts = new GenericsType[ta.length];
+ for (int i = 0; i < ta.length; i++) {
+ ClassNode t = configureType(ta[i]);
+ if (ta[i] instanceof WildcardType) {
+ GenericsType[] gen = t.getGenericsTypes();
+ gts[i] = gen[0];
+ } else {
+ gts[i] = new GenericsType(t);
+ }
+ }
+ return gts;
+ }
+
+ private void setAnnotationMetaData(Annotation[] annotations, AnnotatedNode an) {
+ for (Annotation annotation : annotations) {
+ AnnotationNode node = new AnnotationNode(ClassHelper.make(annotation.annotationType()));
+ configureAnnotation(node, annotation);
+ an.addAnnotation(node);
+ }
+ }
+
+ @Deprecated
+ public void configureAnnotationFromDefinition(AnnotationNode definition, AnnotationNode root) {
+ VMPlugin plugin = VMPluginFactory.getPlugin();
+ plugin.configureAnnotationNodeFromDefinition(definition, root);
+ }
+
+ public void configureAnnotationNodeFromDefinition(AnnotationNode definition, AnnotationNode root) {
+ ClassNode type = definition.getClassNode();
+ if ("java.lang.annotation.Retention".equals(type.getName())) {
+ Expression exp = definition.getMember("value");
+ if (!(exp instanceof PropertyExpression)) return;
+ PropertyExpression pe = (PropertyExpression) exp;
+ String name = pe.getPropertyAsString();
+ RetentionPolicy policy = RetentionPolicy.valueOf(name);
+ setRetentionPolicy(policy, root);
+ } else if ("java.lang.annotation.Target".equals(type.getName())) {
+ Expression exp = definition.getMember("value");
+ if (!(exp instanceof ListExpression)) return;
+ ListExpression le = (ListExpression) exp;
+ int bitmap = 0;
+ for (Expression e : le.getExpressions()) {
+ if (!(e instanceof PropertyExpression)) return;
+ PropertyExpression element = (PropertyExpression) e;
+ String name = element.getPropertyAsString();
+ ElementType value = ElementType.valueOf(name);
+ bitmap |= getElementCode(value);
+ }
+ root.setAllowedTargets(bitmap);
+ }
+ }
+
+ public void configureAnnotation(AnnotationNode node) {
+ ClassNode type = node.getClassNode();
+ VMPlugin plugin = VMPluginFactory.getPlugin();
+ List annotations = type.getAnnotations();
+ for (AnnotationNode an : annotations) {
+ plugin.configureAnnotationNodeFromDefinition(an, node);
+ }
+ if (!node.getClassNode().getName().equals("java.lang.annotation.Retention")) {
+ plugin.configureAnnotationNodeFromDefinition(node, node);
+ }
+ }
+
+ private void configureAnnotation(AnnotationNode node, Annotation annotation) {
+ Class type = annotation.annotationType();
+ if (type == Retention.class) {
+ Retention r = (Retention) annotation;
+ RetentionPolicy value = r.value();
+ setRetentionPolicy(value, node);
+ node.setMember("value", new PropertyExpression(
+ new ClassExpression(ClassHelper.makeWithoutCaching(RetentionPolicy.class, false)),
+ value.toString()));
+ } else if (type == Target.class) {
+ Target t = (Target) annotation;
+ ElementType[] elements = t.value();
+ ListExpression elementExprs = new ListExpression();
+ for (ElementType element : elements) {
+ elementExprs.addExpression(new PropertyExpression(
+ new ClassExpression(ClassHelper.ELEMENT_TYPE_TYPE), element.name()));
+ }
+ node.setMember("value", elementExprs);
+ } else {
+ Method[] declaredMethods;
+ try {
+ declaredMethods = type.getDeclaredMethods();
+ } catch (SecurityException se) {
+ declaredMethods = EMPTY_METHOD_ARRAY;
+ }
+ for (Method declaredMethod : declaredMethods) {
+ try {
+ Object value = declaredMethod.invoke(annotation);
+ Expression valueExpression = annotationValueToExpression(value);
+ if (valueExpression == null)
+ continue;
+ node.setMember(declaredMethod.getName(), valueExpression);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ }
+ }
+ }
+ }
+
+ private Expression annotationValueToExpression (Object value) {
+ if (value == null || value instanceof String || value instanceof Number || value instanceof Character || value instanceof Boolean)
+ return new ConstantExpression(value);
+
+ if (value instanceof Class)
+ return new ClassExpression(ClassHelper.makeWithoutCaching((Class>)value));
+
+ if (value instanceof Enum )
+ return new PropertyExpression(new ClassExpression(ClassHelper.makeWithoutCaching(value.getClass())), value.toString());
+
+ if (value instanceof Annotation) { // GROOVY-9871
+ ClassNode type = ClassHelper.makeWithoutCaching(((Annotation) value).annotationType());
+ AnnotationNode node = new AnnotationNode(type);
+ configureAnnotation(node, (Annotation) value);
+ return new AnnotationConstantExpression(node);
+ }
+
+ if (value.getClass().isArray()) {
+ ListExpression values = new ListExpression();
+ for (int i = 0, n = Array.getLength(value); i < n; i += 1)
+ values.addExpression(annotationValueToExpression(Array.get(value, i)));
+ return values;
+ }
+
+ return null;
+ }
+
+ private static void setRetentionPolicy(RetentionPolicy value, AnnotationNode node) {
+ switch (value) {
+ case RUNTIME:
+ node.setRuntimeRetention(true);
+ break;
+ case SOURCE:
+ node.setSourceRetention(true);
+ break;
+ case CLASS:
+ node.setClassRetention(true);
+ break;
+ default:
+ throw new GroovyBugError("unsupported Retention " + value);
+ }
+ }
+
+ @SuppressWarnings("incomplete-switch")
+ protected int getElementCode(ElementType value) {
+ switch (value) {
+ case TYPE:
+ return AnnotationNode.TYPE_TARGET;
+ case CONSTRUCTOR:
+ return AnnotationNode.CONSTRUCTOR_TARGET;
+ case METHOD:
+ return AnnotationNode.METHOD_TARGET;
+ case FIELD:
+ return AnnotationNode.FIELD_TARGET;
+ case PARAMETER:
+ return AnnotationNode.PARAMETER_TARGET;
+ case LOCAL_VARIABLE:
+ return AnnotationNode.LOCAL_VARIABLE_TARGET;
+ case ANNOTATION_TYPE:
+ return AnnotationNode.ANNOTATION_TARGET;
+ case PACKAGE:
+ return AnnotationNode.PACKAGE_TARGET;
+ }
+ if ("MODULE".equals(value.name())) {
+ return AnnotationNode.TYPE_TARGET;
+ } else {
+ throw new GroovyBugError("unsupported Target " + value);
+ }
+ }
+
+ private static void setMethodDefaultValue(MethodNode mn, Method m) {
+ // GRECLIPSE add -- GROOVY-10862
+ if (m.getDefaultValue() == null) return;
+ // GRECLIPSE end
+ mn.setCode(new ReturnStatement(new ConstantExpression(m.getDefaultValue())));
+ mn.setAnnotationDefault(true);
+ }
+
+ public void configureClassNode(CompileUnit compileUnit, ClassNode classNode) {
+ try {
+ 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);
+ setAnnotationMetaData(f.getAnnotations(), fn);
+ classNode.addField(fn);
+ }
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method m : methods) {
+ ClassNode ret = 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);
+ setAnnotationMetaData(m.getAnnotations(), mn);
+ mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters()));
+ 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);
+ }
+
+ Class sc = clazz.getSuperclass();
+ if (sc != null) classNode.setUnresolvedSuperClass(makeClassNode(compileUnit, clazz.getGenericSuperclass(), sc));
+ makeInterfaceTypes(compileUnit, classNode, clazz);
+ setAnnotationMetaData(classNode.getTypeClass().getAnnotations(), classNode);
+
+ PackageNode packageNode = classNode.getPackage();
+ if (packageNode != null) {
+ setAnnotationMetaData(classNode.getTypeClass().getPackage().getAnnotations(), packageNode);
+ }
+ } catch (NoClassDefFoundError e) {
+ throw new NoClassDefFoundError("Unable to load class "+classNode.toString(false)+" due to missing dependency "+e.getMessage());
+ } catch (MalformedParameterizedTypeException e) {
+ throw new RuntimeException("Unable to configure class node for class "+classNode.toString(false)+" due to malformed parameterized types", e);
+ }
+ }
+
+ /**
+ * Synthetic parameters such as those added for inner class constructors may
+ * not be included in the parameter annotations array. This is the case when
+ * at least one parameter of an inner class constructor has an annotation with
+ * a RUNTIME retention (this occurs for JDK8 and below). This method will
+ * normalize the annotations array so that it contains the same number of
+ * elements as the array returned from {@link Constructor#getParameterTypes()}.
+ *
+ * If adjustment is required, the adjusted array will be prepended with a
+ * zero-length element. If no adjustment is required, the original array
+ * from {@link Constructor#getParameterAnnotations()} will be returned.
+ *
+ * @param constructor the Constructor for which to return parameter annotations
+ * @return array of arrays containing the annotations on the parameters of the given Constructor
+ */
+ private Annotation[][] getConstructorParameterAnnotations(Constructor> constructor) {
+ /*
+ * TODO: Remove after JDK9 is the minimum JDK supported
+ *
+ * JDK9+ correctly accounts for the synthetic parameter and when it becomes
+ * the minimum version this method should no longer be required.
+ */
+ int parameterCount = constructor.getParameterTypes().length;
+ Annotation[][] annotations = constructor.getParameterAnnotations();
+ int diff = parameterCount - annotations.length;
+ if (diff > 0) {
+ // May happen on JDK8 and below. We add elements to the front of the array to account for the synthetic params:
+ // - for an inner class we expect one param to account for the synthetic outer reference
+ // - for an enum we expect two params to account for the synthetic name and ordinal
+ if ((!constructor.getDeclaringClass().isEnum() && diff > 1) || diff > 2) {
+ throw new GroovyBugError(
+ "Constructor parameter annotations length [" + annotations.length + "] " +
+ "does not match the parameter length: " + constructor
+ );
+ }
+ Annotation[][] adjusted = new Annotation[parameterCount][];
+ for (int i = 0; i < diff; i++) {
+ adjusted[i] = EMPTY_ANNOTATION_ARRAY;
+ }
+ System.arraycopy(annotations, 0, adjusted, diff, annotations.length);
+ return adjusted;
+ }
+ return annotations;
+ }
+
+ private void makeInterfaceTypes(CompileUnit cu, ClassNode classNode, Class clazz) {
+ Type[] interfaceTypes = clazz.getGenericInterfaces();
+ if (interfaceTypes.length == 0) {
+ classNode.setInterfaces(ClassNode.EMPTY_ARRAY);
+ } else {
+ ClassNode[] ret = new ClassNode[interfaceTypes.length];
+ for (int i = 0; i < interfaceTypes.length; i++) {
+ Type type = interfaceTypes[i];
+ while (!(type instanceof Class)) {
+ ParameterizedType pt = (ParameterizedType) type;
+ Type t2 = pt.getRawType();
+ if (t2==type) {
+ throw new GroovyBugError("Cannot transform generic signature of "+clazz+
+ " with generic interface "+interfaceTypes[i]+" to a class.");
+ }
+ type = t2;
+ }
+ ret[i] = makeClassNode(cu, interfaceTypes[i], (Class) type);
+ }
+ classNode.setInterfaces(ret);
+ }
+ }
+
+ private ClassNode[] makeClassNodes(CompileUnit cu, Type[] types, Class[] cls) {
+ ClassNode[] nodes = new ClassNode[types.length];
+ for (int i = 0; i < nodes.length; i++) {
+ nodes[i] = makeClassNode(cu, types[i], cls[i]);
+ }
+ return nodes;
+ }
+
+ private ClassNode makeClassNode(CompileUnit cu, Type t, Class c) {
+ ClassNode back = null;
+ if (cu != null) back = cu.getClass(c.getName());
+ if (back == null) back = ClassHelper.make(c);
+ if (!(t instanceof Class)) {
+ ClassNode front = configureType(t);
+ front.setRedirect(back);
+ return front;
+ }
+ return back.getPlainNodeReference();
+ }
+
+ private Parameter[] makeParameters(CompileUnit cu, Type[] types, Class[] cls, Annotation[][] parameterAnnotations, Member member) {
+ Parameter[] params = Parameter.EMPTY_ARRAY;
+ int n = types.length;
+ if (n > 0) {
+ params = new Parameter[n];
+ String[] names = new String[n];
+ 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]));
+ }
+ }
+ return params;
+ }
+
+ protected void fillParameterNames(String[] names, Member member) {
+ for (int i = 0, n = names.length; i < n; i += 1) {
+ names[i] = (i < ARGS.length ? ARGS[i] : "arg" + i);
+ }
+ }
+
+ // arbitrary choice of first ten; maintaining this array prevents many thousands of "argN" string/char[] instances
+ private static final String[] ARGS = {"arg0", "arg1", "arg2", "arg3", "arg4", "arg5", "arg6", "arg7", "arg8", "arg9"};
+
+ public void invalidateCallSites() {
+ }
+
+ @Override
+ public Object getInvokeSpecialHandle(Method m, Object receiver){
+ throw new GroovyBugError("getInvokeSpecialHandle requires at least JDK 7 wot private access to Lookup");
+ }
+
+ @Override
+ public Object invokeHandle(Object handle, Object[] args) throws Throwable {
+ throw new GroovyBugError("invokeHandle requires at least JDK 7");
+ }
+}
diff --git a/base/org.codehaus.groovy30/.checkstyle b/base/org.codehaus.groovy30/.checkstyle
index 787c900c5c..23b9353119 100644
--- a/base/org.codehaus.groovy30/.checkstyle
+++ b/base/org.codehaus.groovy30/.checkstyle
@@ -70,6 +70,7 @@
+
diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/MethodNode.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/MethodNode.java
index 88fccd5f6f..705c020b3f 100644
--- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/MethodNode.java
+++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/ast/MethodNode.java
@@ -241,12 +241,12 @@ public boolean isScriptBody() {
/* GRECLIPSE edit
return Boolean.TRUE.equals(getNodeMetaData("org.codehaus.groovy.ast.MethodNode.isScriptBody"));
*/
- return getDeclaringClass() != null &&
- getDeclaringClass().isScript() &&
- getName().equals("run") &&
- (parameters == null || parameters.length == 0) &&
- (returnType != null && returnType.getName().equals("java.lang.Object"));
- // GRECLIPSE: end
+ return getName().equals("run")
+ && getDeclaringClass() != null
+ && getDeclaringClass().isScript()
+ && (parameters == null || parameters.length == 0)
+ && (returnType != null && returnType.getName().equals(ClassHelper.OBJECT));
+ // GRECLIPSE end
}
/**
@@ -255,7 +255,9 @@ public boolean isScriptBody() {
* @see ModuleNode#createStatementsClass()
*/
public void setIsScriptBody() {
+ /* GRECLIPSE edit
setNodeMetaData("org.codehaus.groovy.ast.MethodNode.isScriptBody", Boolean.TRUE);
+ */
}
public boolean isStaticConstructor() {
diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/AnnotationVisitor.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/AnnotationVisitor.java
index 8e27d69eb4..d1e62c4e63 100644
--- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/AnnotationVisitor.java
+++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/AnnotationVisitor.java
@@ -140,11 +140,11 @@ private boolean checkIfMandatoryAnnotationValuesPassed(AnnotationNode node) {
ClassNode classNode = node.getClassNode();
for (MethodNode mn : classNode.getMethods()) {
String methodName = mn.getName();
- // if the annotation attribute has a default, getCode() returns a ReturnStatement with the default value
/* GRECLIPSE edit
if (mn.getCode() == null && !attributes.containsKey(methodName)) {
*/
- if (!mn.hasAnnotationDefault() && !attributes.containsKey(methodName)) {
+ if (!mn.hasAnnotationDefault() && !node.getMembers().containsKey(methodName) && !"dataVariableNames".equals(methodName)) {
+ // TODO: https://github.com/spockframework/spock/issues/1549 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// GRECLIPSE end
addError("No explicit/default value found for annotation attribute '" + methodName + "'", node);
ok = false;
diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
index 614ce4be98..36257e99af 100644
--- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
+++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
@@ -118,9 +118,9 @@ public void writeMethodReferenceExpression(final MethodReferenceExpression metho
classExpression.setSourcePosition(typeOrTargetRef);
typeOrTargetRef = classExpression;
}
-
+ /* GRECLIPSE edit -- GROOVY-10861
methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
-
+ */
if (!isClassExpression) {
if (isConstructorReference) {
// TODO: move the checking code to the parser
@@ -143,7 +143,10 @@ public void writeMethodReferenceExpression(final MethodReferenceExpression metho
} else {
referenceKind = Opcodes.H_INVOKEVIRTUAL;
}
-
+ // GRECLIPSE add
+ synchronized (methodRefMethod) { try {
+ methodRefMethod.putNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE, parametersWithExactType);
+ // GRECLIPSE end
controller.getMethodVisitor().visitInvokeDynamicInsn(
abstractMethod.getName(),
createAbstractMethodDesc(functionalInterfaceType, typeOrTargetRef),
@@ -156,7 +159,11 @@ public void writeMethodReferenceExpression(final MethodReferenceExpression metho
false
)
);
-
+ // GRECLIPSE add
+ } finally {
+ methodRefMethod.removeNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE);
+ }}
+ // GRECLIPSE end
if (isClassExpression) {
controller.getOperandStack().push(functionalInterfaceType);
} else {
diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/vmplugin/v8/Java8.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/vmplugin/v8/Java8.java
new file mode 100644
index 0000000000..0e2c11263e
--- /dev/null
+++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/vmplugin/v8/Java8.java
@@ -0,0 +1,734 @@
+/*
+ * 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.vmplugin.v8;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.reflection.ReflectionUtils;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.MalformedParameterizedTypeException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.ReflectPermission;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.List;
+
+/**
+ * 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) {
+ ClassNode redirect = base.redirect();
+ base.setRedirect(null);
+ GenericsType gt;
+ if (cBounds == null || cBounds.length == 0) {
+ gt = new GenericsType(base);
+ } else {
+ gt = new GenericsType(base, cBounds, 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.setRedirect(ClassHelper.OBJECT_TYPE);
+ return cn;
+ }
+
+ private static void setRetentionPolicy(final RetentionPolicy value, final AnnotationNode node) {
+ switch (value) {
+ case RUNTIME:
+ node.setRuntimeRetention(true);
+ break;
+ case SOURCE:
+ node.setSourceRetention(true);
+ break;
+ case CLASS:
+ node.setClassRetention(true);
+ break;
+ default:
+ throw new GroovyBugError("unsupported Retention " + value);
+ }
+ }
+
+ private static void setMethodDefaultValue(final MethodNode mn, final Method m) {
+ // GRECLIPSE add -- GROOVY-10862
+ if (m.getDefaultValue() == null) return;
+ // GRECLIPSE end
+ ConstantExpression cExp = new ConstantExpression(m.getDefaultValue());
+ mn.setCode(new ReturnStatement(cExp));
+ mn.setAnnotationDefault(true);
+ }
+
+ @Override
+ public Class>[] getPluginDefaultGroovyMethods() {
+ return new Class[]{PluginDefaultGroovyMethods.class};
+ }
+
+ @Override
+ public Class>[] getPluginStaticGroovyMethods() {
+ return EMPTY_CLASS_ARRAY;
+ }
+
+ @Override
+ public int getVersion() {
+ return 8;
+ }
+
+ protected int getElementCode(final ElementType value) {
+ switch (value) {
+ case TYPE:
+ return AnnotationNode.TYPE_TARGET;
+ case CONSTRUCTOR:
+ return AnnotationNode.CONSTRUCTOR_TARGET;
+ case METHOD:
+ return AnnotationNode.METHOD_TARGET;
+ case FIELD:
+ return AnnotationNode.FIELD_TARGET;
+ case PARAMETER:
+ return AnnotationNode.PARAMETER_TARGET;
+ case LOCAL_VARIABLE:
+ return AnnotationNode.LOCAL_VARIABLE_TARGET;
+ case ANNOTATION_TYPE:
+ return AnnotationNode.ANNOTATION_TARGET;
+ case PACKAGE:
+ return AnnotationNode.PACKAGE_TARGET;
+ case TYPE_PARAMETER:
+ return AnnotationNode.TYPE_PARAMETER_TARGET;
+ case TYPE_USE:
+ return AnnotationNode.TYPE_USE_TARGET;
+ default:
+ // falls through
+ }
+ if ("MODULE".equals(value.name())) { // JDK 9+
+ return AnnotationNode.TYPE_TARGET;
+ } else {
+ throw new GroovyBugError("unsupported Target " + 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()));
+ }
+
+ private ClassNode[] configureTypes(final Type[] types) {
+ final int n = types.length;
+ if (n == 0) return null;
+ ClassNode[] nodes = new ClassNode[n];
+ for (int i = 0; i < n; i += 1) {
+ nodes[i] = configureType(types[i]);
+ }
+ return nodes;
+ }
+
+ private ClassNode configureType(final Type type) {
+ if (type instanceof WildcardType) {
+ return configureWildcardType((WildcardType) type);
+ } else if (type instanceof ParameterizedType) {
+ return configureParameterizedType((ParameterizedType) type);
+ } else if (type instanceof GenericArrayType) {
+ return configureGenericArray((GenericArrayType) type);
+ } else if (type instanceof TypeVariable) {
+ return configureTypeVariableReference(((TypeVariable) type).getName());
+ } else if (type instanceof Class) {
+ return configureClass((Class>) type);
+ } else if (type == null) {
+ throw new GroovyBugError("Type is null. Most probably you let a transform reuse existing ClassNodes with generics information, that is now used in a wrong context.");
+ } else {
+ throw new GroovyBugError("unknown type: " + type + " := " + type.getClass());
+ }
+ }
+
+ private ClassNode configureGenericArray(final GenericArrayType genericArrayType) {
+ Type component = genericArrayType.getGenericComponentType();
+ ClassNode node = configureType(component);
+ return node.makeArray();
+ }
+
+ private ClassNode configureWildcardType(final WildcardType wildcardType) {
+ ClassNode base = ClassHelper.makeWithoutCaching("?");
+ base.setRedirect(ClassHelper.OBJECT_TYPE);
+
+ ClassNode[] lowers = configureTypes(wildcardType.getLowerBounds());
+ ClassNode[] uppers = configureTypes(wildcardType.getUpperBounds());
+ // beware of [Object] upper bounds; often it's > or super T>
+ if (lowers != null || wildcardType.getTypeName().equals("?")) {
+ uppers = null;
+ }
+
+ GenericsType gt = new GenericsType(base, uppers, lowers != null ? lowers[0] : null);
+ gt.setWildcard(true);
+
+ ClassNode wt = ClassHelper.makeWithoutCaching(Object.class, false);
+ wt.setGenericsTypes(new GenericsType[]{gt});
+ return wt;
+ }
+
+ private ClassNode configureParameterizedType(final ParameterizedType parameterizedType) {
+ ClassNode base = configureType(parameterizedType.getRawType());
+ GenericsType[] gts = configureTypeArguments(parameterizedType.getActualTypeArguments());
+ base.setGenericsTypes(gts);
+ return base;
+ }
+
+ private GenericsType[] configureTypeArguments(final Type[] ta) {
+ final int n = ta.length;
+ if (n == 0) return null;
+ GenericsType[] gts = new GenericsType[n];
+ for (int i = 0; i < n; i += 1) {
+ ClassNode t = configureType(ta[i]);
+ if (ta[i] instanceof WildcardType) {
+ GenericsType[] gen = t.getGenericsTypes();
+ gts[i] = gen[0];
+ } else {
+ gts[i] = new GenericsType(t);
+ }
+ }
+ return gts;
+ }
+
+ //
+
+ @Override
+ public void configureAnnotation(final AnnotationNode node) {
+ ClassNode type = node.getClassNode();
+ VMPlugin plugin = VMPluginFactory.getPlugin();
+ List annotations = type.getAnnotations();
+ for (AnnotationNode an : annotations) {
+ plugin.configureAnnotationNodeFromDefinition(an, node);
+ }
+ if (!node.getClassNode().getName().equals("java.lang.annotation.Retention")) {
+ plugin.configureAnnotationNodeFromDefinition(node, node);
+ }
+ }
+
+ private void configureAnnotation(final AnnotationNode node, final Annotation annotation) {
+ Class> type = annotation.annotationType();
+ if (type == Retention.class) {
+ Retention r = (Retention) annotation;
+ RetentionPolicy value = r.value();
+ setRetentionPolicy(value, node);
+ node.setMember("value", new PropertyExpression(
+ new ClassExpression(ClassHelper.makeWithoutCaching(RetentionPolicy.class, false)),
+ value.toString()));
+ } else if (type == Target.class) {
+ Target t = (Target) annotation;
+ ElementType[] elements = t.value();
+ ListExpression elementExprs = new ListExpression();
+ for (ElementType element : elements) {
+ elementExprs.addExpression(new PropertyExpression(
+ new ClassExpression(ClassHelper.ELEMENT_TYPE_TYPE), element.name()));
+ }
+ node.setMember("value", elementExprs);
+ } else {
+ Method[] declaredMethods;
+ try {
+ declaredMethods = type.getDeclaredMethods();
+ } catch (SecurityException se) {
+ declaredMethods = EMPTY_METHOD_ARRAY;
+ }
+ for (Method declaredMethod : declaredMethods) {
+ try {
+ Object value = declaredMethod.invoke(annotation);
+ Expression valueExpression = toAnnotationValueExpression(value);
+ if (valueExpression != null) node.setMember(declaredMethod.getName(), valueExpression);
+
+ } catch (IllegalAccessException | InvocationTargetException ignore) {
+ }
+ }
+ }
+ }
+
+ private void setAnnotationMetaData(final Annotation[] annotations, final AnnotatedNode target) {
+ for (Annotation annotation : annotations) {
+ target.addAnnotation(toAnnotationNode(annotation));
+ }
+ }
+
+ private AnnotationNode toAnnotationNode(final Annotation annotation) {
+ ClassNode type = ClassHelper.make(annotation.annotationType());
+ AnnotationNode node = new AnnotationNode(type);
+ configureAnnotation(node, annotation);
+ return node;
+ }
+
+ private Expression toAnnotationValueExpression(final Object value) {
+ if (value == null || value instanceof String || value instanceof Number || value instanceof Character || value instanceof Boolean)
+ return new ConstantExpression(value);
+
+ if (value instanceof Class)
+ return new ClassExpression(ClassHelper.makeWithoutCaching((Class>)value));
+
+ if (value instanceof Annotation)
+ return new AnnotationConstantExpression(toAnnotationNode((Annotation)value));
+
+ if (value instanceof Enum)
+ return new PropertyExpression(new ClassExpression(ClassHelper.makeWithoutCaching(value.getClass())), value.toString());
+
+ if (value.getClass().isArray()) {
+ ListExpression list = new ListExpression();
+ for (int i = 0, n = Array.getLength(value); i < n; i += 1)
+ list.addExpression(toAnnotationValueExpression(Array.get(value, i)));
+ return list;
+ }
+
+ return null;
+ }
+
+ //
+
+ @Override
+ public void configureAnnotationNodeFromDefinition(final AnnotationNode definition, final AnnotationNode root) {
+ ClassNode type = definition.getClassNode();
+ final String typeName = type.getName();
+ if ("java.lang.annotation.Retention".equals(typeName)) {
+ Expression exp = definition.getMember("value");
+ if (!(exp instanceof PropertyExpression)) return;
+ PropertyExpression pe = (PropertyExpression) exp;
+ String name = pe.getPropertyAsString();
+ RetentionPolicy policy = RetentionPolicy.valueOf(name);
+ setRetentionPolicy(policy, root);
+ } 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()) {
+ if (!(e instanceof PropertyExpression)) return;
+ PropertyExpression element = (PropertyExpression) e;
+ String name = element.getPropertyAsString();
+ ElementType value = ElementType.valueOf(name);
+ bitmap |= getElementCode(value);
+ }
+ root.setAllowedTargets(bitmap);
+ }
+ }
+
+ @Override
+ public void configureClassNode(final CompileUnit compileUnit, final ClassNode classNode) {
+ try {
+ 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);
+ setAnnotationMetaData(f.getAnnotations(), fn);
+ classNode.addField(fn);
+ }
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method m : methods) {
+ ClassNode ret = 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);
+ setAnnotationMetaData(m.getAnnotations(), mn);
+ mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters()));
+ 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);
+ }
+
+ Class> sc = clazz.getSuperclass();
+ if (sc != null) classNode.setUnresolvedSuperClass(makeClassNode(compileUnit, clazz.getGenericSuperclass(), sc));
+ makeInterfaceTypes(compileUnit, classNode, clazz);
+ setAnnotationMetaData(clazz.getAnnotations(), classNode);
+
+ PackageNode packageNode = classNode.getPackage();
+ if (packageNode != null) {
+ setAnnotationMetaData(clazz.getPackage().getAnnotations(), packageNode);
+ }
+ } catch (NoClassDefFoundError e) {
+ throw new NoClassDefFoundError("Unable to load class " + classNode.toString(false) + " due to missing dependency " + e.getMessage());
+ } catch (MalformedParameterizedTypeException e) {
+ throw new RuntimeException("Unable to configure class node for class " + classNode.toString(false) + " due to malformed parameterized types", e);
+ }
+ }
+
+ /**
+ * Synthetic parameters such as those added for inner class constructors may
+ * not be included in the parameter annotations array. This is the case when
+ * at least one parameter of an inner class constructor has an annotation with
+ * a RUNTIME retention (this occurs for JDK8 and below). This method will
+ * normalize the annotations array so that it contains the same number of
+ * elements as the array returned from {@link Constructor#getParameterTypes()}.
+ *
+ * If adjustment is required, the adjusted array will be prepended with a
+ * zero-length element. If no adjustment is required, the original array
+ * from {@link Constructor#getParameterAnnotations()} will be returned.
+ *
+ * @param constructor the Constructor for which to return parameter annotations
+ * @return array of arrays containing the annotations on the parameters of the given Constructor
+ */
+ private Annotation[][] getConstructorParameterAnnotations(final Constructor> constructor) {
+ /*
+ * TODO: Remove after JDK9 is the minimum JDK supported
+ *
+ * JDK9+ correctly accounts for the synthetic parameter and when it becomes
+ * the minimum version this method should no longer be required.
+ */
+ int parameterCount = constructor.getParameterTypes().length;
+ Annotation[][] annotations = constructor.getParameterAnnotations();
+ int diff = parameterCount - annotations.length;
+ if (diff > 0) {
+ // May happen on JDK8 and below. We add elements to the front of the array to account for the synthetic params:
+ // - for an inner class we expect one param to account for the synthetic outer reference
+ // - for an enum we expect two params to account for the synthetic name and ordinal
+ if ((!constructor.getDeclaringClass().isEnum() && diff > 1) || diff > 2) {
+ throw new GroovyBugError(
+ "Constructor parameter annotations length [" + annotations.length + "] " +
+ "does not match the parameter length: " + constructor
+ );
+ }
+ Annotation[][] adjusted = new Annotation[parameterCount][];
+ for (int i = 0; i < diff; i += 1) {
+ adjusted[i] = EMPTY_ANNOTATION_ARRAY;
+ }
+ System.arraycopy(annotations, 0, adjusted, diff, annotations.length);
+ return adjusted;
+ }
+ return annotations;
+ }
+
+ private void makeInterfaceTypes(final CompileUnit cu, final ClassNode classNode, final Class> clazz) {
+ Type[] interfaceTypes = clazz.getGenericInterfaces();
+ final int n = interfaceTypes.length;
+ if (n == 0) {
+ classNode.setInterfaces(ClassNode.EMPTY_ARRAY);
+ } else {
+ ClassNode[] ret = new ClassNode[n];
+ for (int i = 0; i < n; i += 1) {
+ Type type = interfaceTypes[i];
+ while (!(type instanceof Class)) {
+ ParameterizedType pt = (ParameterizedType) type;
+ Type t2 = pt.getRawType();
+ if (t2 == type) {
+ throw new GroovyBugError("Cannot transform generic signature of " + clazz + " with generic interface " + interfaceTypes[i] + " to a class.");
+ }
+ type = t2;
+ }
+ ret[i] = makeClassNode(cu, interfaceTypes[i], (Class>) type);
+ }
+ classNode.setInterfaces(ret);
+ }
+ }
+
+ private ClassNode[] makeClassNodes(final CompileUnit cu, final Type[] types, final Class>[] cls) {
+ final int n = types.length;
+ ClassNode[] nodes = new ClassNode[n];
+ for (int i = 0; i < n; i += 1) {
+ nodes[i] = makeClassNode(cu, types[i], cls[i]);
+ }
+ return nodes;
+ }
+
+ private ClassNode makeClassNode(final CompileUnit cu, Type t, final Class> c) {
+ ClassNode back = null;
+ if (cu != null) back = cu.getClass(c.getName());
+ if (back == null) back = ClassHelper.make(c);
+ if (!(t instanceof Class)) {
+ ClassNode front = configureType(t);
+ front.setRedirect(back);
+ return front;
+ }
+ return back.getPlainNodeReference();
+ }
+
+ @Deprecated
+ protected Parameter[] processParameters(final CompileUnit compileUnit, final Method m) {
+ java.lang.reflect.Parameter[] parameters = m.getParameters();
+ Type[] types = m.getGenericParameterTypes();
+ Parameter[] params = Parameter.EMPTY_ARRAY;
+ if (types.length > 0) {
+ params = new Parameter[types.length];
+ for (int i = 0; i < params.length; i++) {
+ java.lang.reflect.Parameter p = parameters[i];
+ String name = p.isNamePresent() ? p.getName() : "param" + i;
+ params[i] = makeParameter(compileUnit, types[i], m.getParameterTypes()[i], m.getParameterAnnotations()[i], name);
+ }
+ }
+ return params;
+ }
+
+ @Deprecated
+ protected Parameter makeParameter(final CompileUnit cu, final Type type, final Class> cl, final Annotation[] annotations, final String name) {
+ ClassNode cn = makeClassNode(cu, type, cl);
+ Parameter parameter = new Parameter(cn, name);
+ setAnnotationMetaData(annotations, parameter);
+ return parameter;
+ }
+
+ private Parameter[] makeParameters(final CompileUnit cu, final Type[] types, final Class>[] cls, final Annotation[][] parameterAnnotations, final Member member) {
+ Parameter[] params = Parameter.EMPTY_ARRAY;
+ int n = types.length;
+ if (n > 0) {
+ params = new Parameter[n];
+ String[] names = new String[n];
+ 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]));
+ }
+ }
+ return params;
+ }
+
+ protected void fillParameterNames(final String[] names, final Member member) {
+ try {
+ java.lang.reflect.Parameter[] parameters = ((java.lang.reflect.Executable) member).getParameters();
+ for (int i = 0, n = names.length; i < n; i += 1) {
+ names[i] = parameters[i].getName();
+ }
+ } catch (RuntimeException e) {
+ throw new GroovyBugError(e);
+ }
+ }
+
+ /**
+ * The following scenarios can not set accessible, i.e. the return value is false
+ * 1) SecurityException occurred
+ * 2) the accessible object is a Constructor object for the Class class
+ *
+ * @param accessibleObject the accessible object to check
+ * @param callerClass the callerClass to invoke {@code setAccessible}
+ * @return the check result
+ */
+ @Override
+ public boolean checkCanSetAccessible(final AccessibleObject accessibleObject, final Class> callerClass) {
+ SecurityManager sm = System.getSecurityManager();
+ try {
+ if (sm != null) {
+ sm.checkPermission(ACCESS_PERMISSION);
+ }
+ } catch (SecurityException e) {
+ return false;
+ }
+
+ if (accessibleObject instanceof Constructor) {
+ Constructor> c = (Constructor>) accessibleObject;
+ if (c.getDeclaringClass() == Class.class) {
+ return false; // Cannot make a java.lang.Class constructor accessible
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean checkAccessible(final Class> callerClass, final Class> declaringClass, final int memberModifiers, final boolean allowIllegalAccess) {
+ return true;
+ }
+
+ @Override
+ public boolean trySetAccessible(final AccessibleObject ao) {
+ try {
+ ao.setAccessible(true);
+ return true;
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Throwable t) {
+ return false;
+ }
+ }
+
+ @Override
+ public MetaMethod transformMetaMethod(final MetaClass metaClass, final MetaMethod metaMethod, final Class> caller) {
+ return metaMethod;
+ }
+
+ @Override
+ public MetaMethod transformMetaMethod(final MetaClass metaClass, final MetaMethod metaMethod) {
+ return transformMetaMethod(metaClass, metaMethod, null);
+ }
+
+ @Override
+ public void invalidateCallSites() {
+ IndyInterface.invalidateSwitchPoints();
+ }
+
+ @Override
+ public Object getInvokeSpecialHandle(final Method method, final Object receiver) {
+ final Class> receiverType = receiver.getClass();
+ try {
+ return of(receiverType).unreflectSpecial(method, receiverType).bindTo(receiver);
+ } catch (ReflectiveOperationException e) {
+ return getInvokeSpecialHandleFallback(method, receiver);
+ }
+ }
+
+ private Object getInvokeSpecialHandleFallback(final Method method, final Object receiver) {
+ if (getLookupConstructor() == null) {
+ throw new GroovyBugError("getInvokeSpecialHandle requires at least JDK 7 for private access to Lookup");
+ }
+ if (!method.isAccessible()) {
+ AccessController.doPrivileged((PrivilegedAction