private Expression transformInlineConstants(Expression exp) { if (exp instanceof PropertyExpression) { PropertyExpression pe = (PropertyExpression) exp; if (pe.getObjectExpression() instanceof ClassExpression) { ClassExpression ce = (ClassExpression) pe.getObjectExpression(); ClassNode type = ce.getType(); if (type.isEnum()) return exp; Expression constant = findConstant(type.getField(pe.getPropertyAsString())); // GRECLIPSE edit // if (constant != null) return constant; if (constant != null) { String name = pe.getText().replace('$', '.'); Object alias = pe.getNodeMetaData("static.import.alias"); if (alias != null && !alias.equals(pe.getPropertyAsString())) { name += " as " + alias; } // store the qualified name to facilitate organizing static imports constant.setNodeMetaData("static.import", name); return constant; } // GRECLIPSE end } } else if (exp instanceof ListExpression) { ListExpression le = (ListExpression) exp; ListExpression result = new ListExpression(); for (Expression e : le.getExpressions()) { result.addExpression(transformInlineConstants(e)); } return result; } return exp; }
private void configureAnnotationFromDefinition(AnnotationNode definition, AnnotationNode root) { ClassNode type = definition.getClassNode(); if (!type.isResolved()) return; Class clazz = type.getTypeClass(); if (clazz == Retention.class) { 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 (clazz == Target.class) { Expression exp = definition.getMember("value"); if (!(exp instanceof ListExpression)) return; ListExpression le = (ListExpression) exp; int bitmap = 0; for (Expression e : le.getExpressions()) { PropertyExpression element = (PropertyExpression) e; String name = element.getPropertyAsString(); ElementType value = ElementType.valueOf(name); bitmap |= getElementCode(value); } root.setAllowedTargets(bitmap); } }
public static void configureAnnotationFromDefinition( 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); } }
private void callGrabAsStaticInitIfNeeded( ClassNode classNode, ClassNode grapeClassNode, AnnotationNode node, List<Map<String, Object>> grabExcludeMaps) { if ((node.getMember("initClass") == null) || (node.getMember("initClass") == ConstantExpression.TRUE)) { List<Statement> grabInitializers = new ArrayList<Statement>(); // add Grape.grab(excludeArgs, [group:group, module:module, version:version, // classifier:classifier]) // or Grape.grab([group:group, module:module, version:version, classifier:classifier]) MapExpression me = new MapExpression(); for (String s : GRAB_REQUIRED) { me.addMapEntryExpression(new ConstantExpression(s), node.getMember(s)); } for (String s : GRAB_OPTIONAL) { if (node.getMember(s) != null) me.addMapEntryExpression(new ConstantExpression(s), node.getMember(s)); } if (autoDownload != null) { me.addMapEntryExpression( new ConstantExpression(AUTO_DOWNLOAD_SETTING), new ConstantExpression(autoDownload)); } if (disableChecksums != null) { me.addMapEntryExpression( new ConstantExpression(DISABLE_CHECKSUMS_SETTING), new ConstantExpression(disableChecksums)); } ArgumentListExpression grabArgs; if (grabExcludeMaps.isEmpty()) { grabArgs = new ArgumentListExpression(me); } else { MapExpression args = new MapExpression(); ListExpression list = new ListExpression(); for (Map<String, Object> map : grabExcludeMaps) { Set<Map.Entry<String, Object>> entries = map.entrySet(); MapExpression inner = new MapExpression(); for (Map.Entry<String, Object> entry : entries) { inner.addMapEntryExpression( new ConstantExpression(entry.getKey()), new ConstantExpression(entry.getValue())); } list.addExpression(inner); } args.addMapEntryExpression(new ConstantExpression("excludes"), list); grabArgs = new ArgumentListExpression(args, me); } grabInitializers.add( new ExpressionStatement( new StaticMethodCallExpression(grapeClassNode, "grab", grabArgs))); // insert at beginning so we have the classloader set up before the class is called classNode.addStaticInitializerStatements(grabInitializers, true); } }
private Class[] getTransformClasses(ClassNode classNode) { if (!classNode.hasClass()) { List<AnnotationNode> annotations = classNode.getAnnotations(); AnnotationNode transformAnnotation = null; for (AnnotationNode anno : annotations) { if (anno.getClassNode().getName().equals(GroovyASTTransformationClass.class.getName())) { transformAnnotation = anno; break; } } if (transformAnnotation != null) { Expression expr = (Expression) transformAnnotation.getMember("classes"); if (expr == null) { return NO_CLASSES; } Class<?>[] values = NO_CLASSES; // Will need to extract the classnames if (expr instanceof ListExpression) { List<Class<?>> loadedClasses = new ArrayList<Class<?>>(); ListExpression expression = (ListExpression) expr; List<Expression> expressions = expression.getExpressions(); for (Expression oneExpr : expressions) { String classname = ((ClassExpression) oneExpr).getType().getName(); try { Class<?> clazz = Class.forName(classname, false, transformLoader); loadedClasses.add(clazz); } catch (ClassNotFoundException cnfe) { source .getErrorCollector() .addError( new SimpleMessage( "Ast transform processing, cannot find " + classname, source)); } } if (loadedClasses.size() != 0) { values = loadedClasses.toArray(new Class<?>[loadedClasses.size()]); } return values; } else { } throw new RuntimeException( "nyi implemented in eclipse: need to support: " + expr + " (class=" + expr.getClass() + ")"); } return null; } else { Annotation transformClassAnnotation = getTransformClassAnnotation(classNode); if (transformClassAnnotation == null) { return null; } return getTransformClasses(transformClassAnnotation); } }
private void callGrabAsStaticInitIfNeeded( ClassNode classNode, ClassNode grapeClassNode, List<Map<String, Object>> grabMapsInit, List<Map<String, Object>> grabExcludeMaps) { List<Statement> grabInitializers = new ArrayList<Statement>(); MapExpression basicArgs = new MapExpression(); if (autoDownload != null) { basicArgs.addMapEntryExpression( new ConstantExpression(AUTO_DOWNLOAD_SETTING), new ConstantExpression(autoDownload)); } if (disableChecksums != null) { basicArgs.addMapEntryExpression( new ConstantExpression(DISABLE_CHECKSUMS_SETTING), new ConstantExpression(disableChecksums)); } if (!grabExcludeMaps.isEmpty()) { ListExpression list = new ListExpression(); for (Map<String, Object> map : grabExcludeMaps) { Set<Map.Entry<String, Object>> entries = map.entrySet(); MapExpression inner = new MapExpression(); for (Map.Entry<String, Object> entry : entries) { inner.addMapEntryExpression( new ConstantExpression(entry.getKey()), new ConstantExpression(entry.getValue())); } list.addExpression(inner); } basicArgs.addMapEntryExpression(new ConstantExpression("excludes"), list); } List<Expression> argList = new ArrayList<Expression>(); argList.add(basicArgs); if (grabMapsInit.size() == 0) return; for (Map<String, Object> grabMap : grabMapsInit) { // add Grape.grab(excludeArgs, [group:group, module:module, version:version, // classifier:classifier]) // or Grape.grab([group:group, module:module, version:version, classifier:classifier]) MapExpression dependencyArg = new MapExpression(); for (String s : GRAB_REQUIRED) { dependencyArg.addMapEntryExpression( new ConstantExpression(s), new ConstantExpression(grabMap.get(s))); } for (String s : GRAB_OPTIONAL) { if (grabMap.containsKey(s)) dependencyArg.addMapEntryExpression( new ConstantExpression(s), new ConstantExpression(grabMap.get(s))); } argList.add(dependencyArg); } ArgumentListExpression grabArgs = new ArgumentListExpression(argList); grabInitializers.add( new ExpressionStatement(new StaticMethodCallExpression(grapeClassNode, "grab", grabArgs))); // insert at beginning so we have the classloader set up before the class is called classNode.addStaticInitializerStatements(grabInitializers, true); }
/** * For the supplied classnode, this method will check if there is an annotation on it of kind * 'GroovyASTTransformationClass'. If there is then the 'value' member of that annotation will be * retrieved and the value considered to be the class name of a transformation. * * @return null if no annotation found, otherwise a String[] of classnames - this will be size 0 * if no value was specified */ private String[] getTransformClassNames(ClassNode cn) { if (!cn.hasClass()) { List<AnnotationNode> annotations = cn.getAnnotations(); AnnotationNode transformAnnotation = null; for (AnnotationNode anno : annotations) { if (anno.getClassNode().getName().equals(GroovyASTTransformationClass.class.getName())) { transformAnnotation = anno; break; } } if (transformAnnotation != null) { // will work so long as signature for the member 'value' is String[] Expression expr2 = transformAnnotation.getMember("value"); String[] values = null; if (expr2 == null) { return NONE; } if (expr2 instanceof ListExpression) { ListExpression expression = (ListExpression) expr2; List<Expression> expressions = expression.getExpressions(); values = new String[expressions.size()]; int e = 0; for (Expression expr : expressions) { values[e++] = ((ConstantExpression) expr).getText(); } } else if (expr2 instanceof ConstantExpression) { values = new String[1]; values[0] = ((ConstantExpression) expr2).getText(); } else { throw new IllegalStateException( "NYI: eclipse doesn't understand this kind of expression in an Ast transform definition: " + expr2 + " (class=" + expr2.getClass().getName() + ")"); } return values; } return null; } else { // FIXASC check haven't broken transforms for 'vanilla' (outside of eclipse) execution of // groovyc Annotation transformClassAnnotation = getTransformClassAnnotation(cn); if (transformClassAnnotation == null) { return null; } return getTransformClassNames(transformClassAnnotation); } }
private List<groovy.transform.PackageScopeTarget> determineTargets(Expression expr) { List<groovy.transform.PackageScopeTarget> list = new ArrayList<groovy.transform.PackageScopeTarget>(); if (expr instanceof PropertyExpression) { list.add(extractTarget((PropertyExpression) expr)); } else if (expr instanceof ListExpression) { final ListExpression expressionList = (ListExpression) expr; final List<Expression> expressions = expressionList.getExpressions(); for (Expression ex : expressions) { if (ex instanceof PropertyExpression) { list.add(extractTarget((PropertyExpression) ex)); } } } return list; }
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.getClass().isArray()) { ListExpression elementExprs = new ListExpression(); int len = Array.getLength(value); for (int i = 0; i != len; ++i) elementExprs.addExpression(annotationValueToExpression(Array.get(value, i))); return elementExprs; } return null; }
int[] extractLineNumberArray(AnnotationNode node) { ListExpression lineNumberArray = (ListExpression) node.getMember("lines"); // make assumption that this is a simple array of constants List<Integer> numbers = new ArrayList<Integer>(); for (Expression e : lineNumberArray.getExpressions()) { if (e instanceof ConstantExpression) { numbers.add((Integer) ((ConstantExpression) e).getValue()); } else { numbers.add(-1); } } // LOG.debug "We have transformed: ${numbers}" if (numbers.isEmpty()) { return null; } int[] array = new int[numbers.size()]; for (int i = 0, count = numbers.size(); i < count; i++) { array[i] = numbers.get(i); } return array; }
private Expression transformInlineConstants(Expression exp) { if (exp instanceof PropertyExpression) { PropertyExpression pe = (PropertyExpression) exp; if (pe.getObjectExpression() instanceof ClassExpression) { ClassExpression ce = (ClassExpression) pe.getObjectExpression(); ClassNode type = ce.getType(); if (type.isEnum()) return exp; Expression constant = findConstant(type.getField(pe.getPropertyAsString())); if (constant != null) return constant; } } else if (exp instanceof ListExpression) { ListExpression le = (ListExpression) exp; ListExpression result = new ListExpression(); for (Expression e : le.getExpressions()) { result.addExpression(transformInlineConstants(e)); } return result; } return exp; }
private Set<String> getPropertyNamesExpressedInTransientsList(final ClassNode classNode) { final Set<String> transientFields = new HashSet<String>(); final FieldNode transientsField = classNode.getField("transients"); if (transientsField != null && transientsField.isStatic()) { final Expression initialValueExpression = transientsField.getInitialValueExpression(); if (initialValueExpression instanceof ListExpression) { final ListExpression le = (ListExpression) initialValueExpression; final List<Expression> expressions = le.getExpressions(); for (Expression expr : expressions) { if (expr instanceof ConstantExpression) { final ConstantExpression ce = (ConstantExpression) expr; final Object contantValue = ce.getValue(); if (contantValue instanceof String) { transientFields.add((String) contantValue); } } } } } return transientFields; }
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 = new Method[0]; } 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 e) { } catch (InvocationTargetException e) { } } } }
private void addDefaultDatabindingWhitelistField( final SourceUnit sourceUnit, final ClassNode classNode) { final FieldNode defaultWhitelistField = classNode.getDeclaredField(DEFAULT_DATABINDING_WHITELIST); if (defaultWhitelistField == null) { final Set<String> propertyNamesToIncludeInWhiteList = getPropertyNamesToIncludeInWhiteList(sourceUnit, classNode); final ListExpression listExpression = new ListExpression(); for (String propertyName : propertyNamesToIncludeInWhiteList) { listExpression.addExpression(new ConstantExpression(propertyName)); final FieldNode declaredField = classNode.getDeclaredField(propertyName); if (declaredField != null) { final ClassNode type = declaredField.getType(); if (type != null && !SIMPLE_TYPES.contains(type)) { if (STRUCTURED_EDITOR_TYPES.contains(type)) { listExpression.addExpression(new ConstantExpression(propertyName + "_*")); } else { String packageName = type.getPackageName(); if (packageName != null && packageName.startsWith(JODATIME_PACKAGE)) { listExpression.addExpression(new ConstantExpression(propertyName + "_*")); } else { listExpression.addExpression(new ConstantExpression(propertyName + ".*")); } } } } } classNode.addField( DEFAULT_DATABINDING_WHITELIST, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL, new ClassNode(List.class), listExpression); } }
private String getAnnotationValue(Object memberValue) { String val = "null"; if (memberValue instanceof ListExpression) { StringBuilder sb = new StringBuilder("{"); boolean first = true; ListExpression le = (ListExpression) memberValue; for (Expression e : le.getExpressions()) { if (first) first = false; else sb.append(","); sb.append(getAnnotationValue(e)); } sb.append("}"); val = sb.toString(); } else if (memberValue instanceof ConstantExpression) { ConstantExpression ce = (ConstantExpression) memberValue; Object constValue = ce.getValue(); if (constValue instanceof AnnotationNode) { StringWriter writer = new StringWriter(); PrintWriter out = new PrintWriter(writer); printAnnotation(out, (AnnotationNode) constValue); val = writer.toString(); } else if (constValue instanceof Number || constValue instanceof Boolean) val = constValue.toString(); else val = "\"" + escapeSpecialChars(constValue.toString()) + "\""; } else if (memberValue instanceof PropertyExpression || memberValue instanceof VariableExpression) { // assume must be static class field or enum value or class that Java can resolve val = ((Expression) memberValue).getText(); } else if (memberValue instanceof ClosureExpression) { // annotation closure; replaced with this specific class literal to cover the // case where annotation type uses Class<? extends Closure> for the closure's type val = "groovy.lang.Closure.class"; } else if (memberValue instanceof ClassExpression) { val = ((Expression) memberValue).getText() + ".class"; } return val; }
private List<String> getKnownImmutables(AnnotationNode node) { final ArrayList<String> immutables = new ArrayList<String>(); final Expression expression = node.getMember(MEMBER_KNOWN_IMMUTABLES); if (expression == null) return immutables; if (!(expression instanceof ListExpression)) { addError( "Use the Groovy list notation [el1, el2] to specify known immutable property names via \"" + MEMBER_KNOWN_IMMUTABLES + "\"", node); return immutables; } final ListExpression listExpression = (ListExpression) expression; for (Expression listItemExpression : listExpression.getExpressions()) { if (listItemExpression instanceof ConstantExpression) { immutables.add((String) ((ConstantExpression) listItemExpression).getValue()); } } return immutables; }
@Override public void visitListExpression(ListExpression expression) { // LOG.debug "Transforming expression '${expression}':" if (expression.getLineNumber() >= 0 && expression.getLineNumber() < lineNumbers.length) { // LOG.debug " start from ${expression.lineNumber} to ${lineNumbers[expression.lineNumber // - 1]}" expression.setLineNumber(lineNumbers[expression.getLineNumber() - 1]); } if (expression.getLastLineNumber() > 0 && expression.getLastLineNumber() < lineNumbers.length) { // LOG.debug " end from ${expression.lastLineNumber} to // ${lineNumbers[expression.lastLineNumber - 1]}" expression.setLastLineNumber(lineNumbers[expression.getLastLineNumber() - 1]); } super.visitListExpression(expression); }
protected void weaveMixinClass(ClassNode classNode, Class mixinClass) { ListExpression listExpression = new ListExpression(); listExpression.addExpression(new ClassExpression(new ClassNode(mixinClass))); weaveMixinsIntoClass(classNode, listExpression); }
public void evaluateEqual(BinaryExpression expression, boolean defineVariable) { AsmClassGenerator acg = controller.getAcg(); CompileStack compileStack = controller.getCompileStack(); OperandStack operandStack = controller.getOperandStack(); Expression rightExpression = expression.getRightExpression(); Expression leftExpression = expression.getLeftExpression(); ClassNode lhsType = controller.getTypeChooser().resolveType(leftExpression, controller.getClassNode()); if (defineVariable && rightExpression instanceof EmptyExpression && !(leftExpression instanceof TupleExpression)) { VariableExpression ve = (VariableExpression) leftExpression; BytecodeVariable var = compileStack.defineVariable( ve, controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false); operandStack.loadOrStoreVariable(var, false); return; } // let's evaluate the RHS and store the result ClassNode rhsType; if (rightExpression instanceof ListExpression && lhsType.isArray()) { ListExpression list = (ListExpression) rightExpression; ArrayExpression array = new ArrayExpression(lhsType.getComponentType(), list.getExpressions()); array.setSourcePosition(list); array.visit(acg); } else if (rightExpression instanceof EmptyExpression) { rhsType = leftExpression.getType(); loadInitValue(rhsType); } else { rightExpression.visit(acg); } rhsType = operandStack.getTopOperand(); boolean directAssignment = defineVariable && !(leftExpression instanceof TupleExpression); int rhsValueId; if (directAssignment) { VariableExpression var = (VariableExpression) leftExpression; if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(rhsType)) { // GROOVY-5570: if a closure shared variable is a primitive type, it must be boxed rhsType = ClassHelper.getWrapper(rhsType); operandStack.box(); } // ensure we try to unbox null to cause a runtime NPE in case we assign // null to a primitive typed variable, even if it is used only in boxed // form as it is closure shared if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(var.getOriginType()) && isNull(rightExpression)) { operandStack.doGroovyCast(var.getOriginType()); // these two are never reached in bytecode and only there // to avoid verifyerrors and compiler infrastructure hazzle operandStack.box(); operandStack.doGroovyCast(lhsType); } // normal type transformation if (!ClassHelper.isPrimitiveType(lhsType) && isNull(rightExpression)) { operandStack.replace(lhsType); } else { operandStack.doGroovyCast(lhsType); } rhsType = lhsType; rhsValueId = compileStack.defineVariable(var, lhsType, true).getIndex(); } else { rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType, true); } // TODO: if rhs is VariableSlotLoader already, then skip crating a new one BytecodeExpression rhsValueLoader = new VariableSlotLoader(rhsType, rhsValueId, operandStack); // assignment for subscript if (leftExpression instanceof BinaryExpression) { BinaryExpression leftBinExpr = (BinaryExpression) leftExpression; if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) { assignToArray( expression, leftBinExpr.getLeftExpression(), leftBinExpr.getRightExpression(), rhsValueLoader); } compileStack.removeVar(rhsValueId); return; } compileStack.pushLHS(true); // multiple declaration if (leftExpression instanceof TupleExpression) { TupleExpression tuple = (TupleExpression) leftExpression; int i = 0; for (Expression e : tuple.getExpressions()) { VariableExpression var = (VariableExpression) e; MethodCallExpression call = new MethodCallExpression( rhsValueLoader, "getAt", new ArgumentListExpression(new ConstantExpression(i))); call.visit(acg); i++; if (defineVariable) { operandStack.doGroovyCast(var); compileStack.defineVariable(var, true); operandStack.remove(1); } else { acg.visitVariableExpression(var); } } } // single declaration else if (defineVariable) { rhsValueLoader.visit(acg); operandStack.remove(1); compileStack.popLHS(); return; } // normal assignment else { int mark = operandStack.getStackLength(); // to leave a copy of the rightExpression value on the stack after the assignment. rhsValueLoader.visit(acg); TypeChooser typeChooser = controller.getTypeChooser(); ClassNode targetType = typeChooser.resolveType(leftExpression, controller.getClassNode()); operandStack.doGroovyCast(targetType); leftExpression.visit(acg); operandStack.remove(operandStack.getStackLength() - mark); } compileStack.popLHS(); // return value of assignment rhsValueLoader.visit(acg); compileStack.removeVar(rhsValueId); }
public void visitListExpression(ListExpression expression) { visitListOfExpressions(expression.getExpressions()); }