blob: 793769dfc6fd52425a97da6161edb4993ba98329 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.ast.tools;
import org.codehaus.groovy.ast.ASTNode;
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.FieldNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.PackageNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.Variable;
import org.codehaus.groovy.ast.VariableScope;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.AttributeExpression;
import org.codehaus.groovy.ast.expr.BinaryExpression;
import org.codehaus.groovy.ast.expr.BooleanExpression;
import org.codehaus.groovy.ast.expr.CastExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.FieldExpression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.MapEntryExpression;
import org.codehaus.groovy.ast.expr.MapExpression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.NotExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.ast.stmt.CatchStatement;
import org.codehaus.groovy.ast.stmt.EmptyStatement;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.IfStatement;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.ast.stmt.ThrowStatement;
import org.codehaus.groovy.ast.stmt.TryCatchStatement;
import org.codehaus.groovy.classgen.Verifier;
import org.codehaus.groovy.control.io.ReaderSource;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.syntax.Token;
import org.codehaus.groovy.syntax.Types;
import org.codehaus.groovy.transform.AbstractASTTransformation;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.apache.groovy.util.BeanUtils.capitalize;
import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_IDENTICAL;
/**
* Handy methods when working with the Groovy AST
*/
public class GeneralUtils {
public static final Token ASSIGN = Token.newSymbol(Types.ASSIGN, -1, -1);
public static final Token EQ = Token.newSymbol(Types.COMPARE_EQUAL, -1, -1);
public static final Token NE = Token.newSymbol(Types.COMPARE_NOT_EQUAL, -1, -1);
public static final Token NOT_IDENTICAL = Token.newSymbol(COMPARE_NOT_IDENTICAL, -1, -1);
public static final Token LT = Token.newSymbol(Types.COMPARE_LESS_THAN, -1, -1);
public static final Token AND = Token.newSymbol(Types.LOGICAL_AND, -1, -1);
public static final Token OR = Token.newSymbol(Types.LOGICAL_OR, -1, -1);
public static final Token CMP = Token.newSymbol(Types.COMPARE_TO, -1, -1);
private static final Token INSTANCEOF = Token.newSymbol(Types.KEYWORD_INSTANCEOF, -1, -1);
private static final Token PLUS = Token.newSymbol(Types.PLUS, -1, -1);
private static final Token INDEX = Token.newSymbol("[", -1, -1);
public static BinaryExpression andX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, AND, rhv);
}
public static ArgumentListExpression args(Expression... expressions) {
List<Expression> args = new ArrayList<Expression>();
Collections.addAll(args, expressions);
return new ArgumentListExpression(args);
}
public static ArgumentListExpression args(List<Expression> expressions) {
return new ArgumentListExpression(expressions);
}
public static ArgumentListExpression args(Parameter[] parameters) {
return new ArgumentListExpression(parameters);
}
public static ArgumentListExpression args(String... names) {
List<Expression> vars = new ArrayList<Expression>();
for (String name : names) {
vars.add(varX(name));
}
return new ArgumentListExpression(vars);
}
public static Statement assignS(Expression target, Expression value) {
return new ExpressionStatement(assignX(target, value));
}
public static Expression assignX(Expression target, Expression value) {
return new BinaryExpression(target, ASSIGN, value);
}
public static Expression attrX(Expression oe, Expression prop) {
return new AttributeExpression(oe, prop);
}
public static BinaryExpression binX(Expression left, Token token, Expression right) {
return new BinaryExpression(left, token, right);
}
public static BlockStatement block(VariableScope varScope, Statement... stmts) {
BlockStatement block = new BlockStatement();
block.setVariableScope(varScope);
for (Statement stmt : stmts) block.addStatement(stmt);
return block;
}
public static BlockStatement block(VariableScope varScope, List<Statement> stmts) {
BlockStatement block = new BlockStatement();
block.setVariableScope(varScope);
for (Statement stmt : stmts) block.addStatement(stmt);
return block;
}
public static BlockStatement block(Statement... stmts) {
BlockStatement block = new BlockStatement();
for (Statement stmt : stmts) block.addStatement(stmt);
return block;
}
public static MethodCallExpression callSuperX(String methodName, Expression args) {
return callX(varX("super"), methodName, args);
}
public static MethodCallExpression callSuperX(String methodName) {
return callSuperX(methodName, MethodCallExpression.NO_ARGUMENTS);
}
public static MethodCallExpression callThisX(String methodName, Expression args) {
return callX(varX("this"), methodName, args);
}
public static MethodCallExpression callThisX(String methodName) {
return callThisX(methodName, MethodCallExpression.NO_ARGUMENTS);
}
public static MethodCallExpression callX(Expression receiver, String methodName, Expression args) {
return new MethodCallExpression(receiver, methodName, args);
}
public static MethodCallExpression callX(Expression receiver, Expression method, Expression args) {
return new MethodCallExpression(receiver, method, args);
}
public static MethodCallExpression callX(Expression receiver, String methodName) {
return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS);
}
public static StaticMethodCallExpression callX(ClassNode receiver, String methodName, Expression args) {
return new StaticMethodCallExpression(receiver, methodName, args);
}
public static StaticMethodCallExpression callX(ClassNode receiver, String methodName) {
return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS);
}
public static CastExpression castX(ClassNode type, Expression expression) {
return new CastExpression(type, expression);
}
public static BooleanExpression boolX(Expression boolExpr) {
return new BooleanExpression(boolExpr);
}
public static CastExpression castX(ClassNode type, Expression expression, boolean ignoreAutoboxing) {
return new CastExpression(type, expression, ignoreAutoboxing);
}
public static ClassExpression classX(ClassNode clazz) {
return new ClassExpression(clazz);
}
public static ClassExpression classX(Class clazz) {
return classX(ClassHelper.make(clazz).getPlainNodeReference());
}
public static ClosureExpression closureX(Parameter[] params, Statement code) {
return new ClosureExpression(params, code);
}
public static ClosureExpression closureX(Statement code) {
return closureX(Parameter.EMPTY_ARRAY, code);
}
public static Parameter[] cloneParams(Parameter[] source) {
Parameter[] result = new Parameter[source.length];
for (int i = 0; i < source.length; i++) {
Parameter srcParam = source[i];
Parameter dstParam = new Parameter(srcParam.getOriginType(), srcParam.getName());
result[i] = dstParam;
}
return result;
}
/**
* Build a binary expression that compares two values
* @param lhv expression for the value to compare from
* @param rhv expression for the value value to compare to
* @return the expression comparing two values
*/
public static BinaryExpression cmpX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, CMP, rhv);
}
public static ConstantExpression constX(Object val) {
return new ConstantExpression(val);
}
public static ConstantExpression constX(Object val, boolean keepPrimitive) {
return new ConstantExpression(val, keepPrimitive);
}
/**
* Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
* and {@link java.lang.annotation.RetentionPolicy#CLASS}.
* <p>
* Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported at present.
*/
public static void copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, final List<AnnotationNode> copied, List<AnnotationNode> notCopied) {
copyAnnotatedNodeAnnotations(annotatedNode, copied, notCopied, true);
}
/**
* Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
* and {@link java.lang.annotation.RetentionPolicy#CLASS}.
* {@link groovy.transform.Generated} annotations will be copied if {@code includeGenerated} is true.
* <p>
* Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported at present.
*/
public static void copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, final List<AnnotationNode> copied, List<AnnotationNode> notCopied, boolean includeGenerated) {
List<AnnotationNode> annotationList = annotatedNode.getAnnotations();
for (AnnotationNode annotation : annotationList) {
List<AnnotationNode> annotations = annotation.getClassNode().getAnnotations(AbstractASTTransformation.RETENTION_CLASSNODE);
if (annotations.isEmpty()) continue;
if (hasClosureMember(annotation)) {
notCopied.add(annotation);
continue;
}
if (!includeGenerated && annotation.getClassNode().getName().equals("groovy.transform.Generated")) {
continue;
}
AnnotationNode retentionPolicyAnnotation = annotations.get(0);
Expression valueExpression = retentionPolicyAnnotation.getMember("value");
if (!(valueExpression instanceof PropertyExpression)) continue;
PropertyExpression propertyExpression = (PropertyExpression) valueExpression;
boolean processAnnotation =
propertyExpression.getProperty() instanceof ConstantExpression &&
(
"RUNTIME".equals(((ConstantExpression) (propertyExpression.getProperty())).getValue()) ||
"CLASS".equals(((ConstantExpression) (propertyExpression.getProperty())).getValue())
);
if (processAnnotation) {
AnnotationNode newAnnotation = new AnnotationNode(annotation.getClassNode());
for (Map.Entry<String, Expression> member : annotation.getMembers().entrySet()) {
newAnnotation.addMember(member.getKey(), member.getValue());
}
newAnnotation.setSourcePosition(annotatedNode);
copied.add(newAnnotation);
}
}
}
public static Statement createConstructorStatementDefault(FieldNode fNode) {
final String name = fNode.getName();
final ClassNode fType = fNode.getType();
final Expression fieldExpr = propX(varX("this"), name);
Expression initExpr = fNode.getInitialValueExpression();
Statement assignInit;
if (initExpr == null || (initExpr instanceof ConstantExpression && ((ConstantExpression)initExpr).isNullExpression())) {
if (ClassHelper.isPrimitiveType(fType)) {
assignInit = EmptyStatement.INSTANCE;
} else {
assignInit = assignS(fieldExpr, ConstantExpression.EMPTY_EXPRESSION);
}
} else {
assignInit = assignS(fieldExpr, initExpr);
}
fNode.setInitialValueExpression(null);
Expression value = findArg(name);
return ifElseS(equalsNullX(value), assignInit, assignS(fieldExpr, castX(fType, value)));
}
public static ConstructorCallExpression ctorX(ClassNode type, Expression args) {
return new ConstructorCallExpression(type, args);
}
public static ConstructorCallExpression ctorX(ClassNode type) {
return new ConstructorCallExpression(type, ArgumentListExpression.EMPTY_ARGUMENTS);
}
public static Statement ctorSuperS(Expression args) {
return stmt(ctorX(ClassNode.SUPER, args));
}
public static Statement ctorThisS(Expression args) {
return stmt(ctorX(ClassNode.THIS, args));
}
public static Statement ctorSuperS() {
return stmt(ctorX(ClassNode.SUPER));
}
public static Statement ctorThisS() {
return stmt(ctorX(ClassNode.THIS));
}
public static Statement declS(Expression target, Expression init) {
return new ExpressionStatement(new DeclarationExpression(target, ASSIGN, init));
}
public static BinaryExpression eqX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, EQ, rhv);
}
public static BooleanExpression equalsNullX(Expression argExpr) {
return new BooleanExpression(eqX(argExpr, new ConstantExpression(null)));
}
public static FieldExpression fieldX(FieldNode fieldNode) {
return new FieldExpression(fieldNode);
}
public static FieldExpression fieldX(ClassNode owner, String fieldName) {
return new FieldExpression(owner.getField(fieldName));
}
public static Expression findArg(String argName) {
return new PropertyExpression(new VariableExpression("args"), argName);
}
public static List<MethodNode> getAllMethods(ClassNode type) {
ClassNode node = type;
List<MethodNode> result = new ArrayList<MethodNode>();
while (node != null) {
result.addAll(node.getMethods());
node = node.getSuperClass();
}
return result;
}
public static List<PropertyNode> getAllProperties(ClassNode type) {
ClassNode node = type;
List<PropertyNode> result = new ArrayList<PropertyNode>();
while (node != null) {
result.addAll(node.getProperties());
node = node.getSuperClass();
}
return result;
}
public static String getGetterName(PropertyNode pNode) {
return "get" + Verifier.capitalize(pNode.getName());
}
public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) {
final List<FieldNode> result = new ArrayList<FieldNode>();
for (FieldNode fNode : cNode.getFields()) {
if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
result.add(fNode);
}
}
return result;
}
public static List<String> getInstanceNonPropertyFieldNames(ClassNode cNode) {
List<FieldNode> fList = getInstanceNonPropertyFields(cNode);
List<String> result = new ArrayList<String>(fList.size());
for (FieldNode fNode : fList) {
result.add(fNode.getName());
}
return result;
}
public static List<PropertyNode> getInstanceProperties(ClassNode cNode) {
final List<PropertyNode> result = new ArrayList<PropertyNode>();
for (PropertyNode pNode : cNode.getProperties()) {
if (!pNode.isStatic()) {
result.add(pNode);
}
}
return result;
}
public static List<String> getInstancePropertyNames(ClassNode cNode) {
List<PropertyNode> pList = BeanUtils.getAllProperties(cNode, false, false, true);
List<String> result = new ArrayList<String>(pList.size());
for (PropertyNode pNode : pList) {
result.add(pNode.getName());
}
return result;
}
public static List<FieldNode> getInstancePropertyFields(ClassNode cNode) {
final List<FieldNode> result = new ArrayList<FieldNode>();
for (PropertyNode pNode : cNode.getProperties()) {
if (!pNode.isStatic()) {
result.add(pNode.getField());
}
}
return result;
}
public static Set<ClassNode> getInterfacesAndSuperInterfaces(ClassNode type) {
Set<ClassNode> res = new LinkedHashSet<ClassNode>();
if (type.isInterface()) {
res.add(type);
return res;
}
ClassNode next = type;
while (next != null) {
res.addAll(next.getAllInterfaces());
next = next.getSuperClass();
}
return res;
}
public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
final List<FieldNode> result;
if (cNode == ClassHelper.OBJECT_TYPE) {
result = new ArrayList<FieldNode>();
} else {
result = getSuperNonPropertyFields(cNode.getSuperClass());
}
for (FieldNode fNode : cNode.getFields()) {
if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
result.add(fNode);
}
}
return result;
}
public static List<FieldNode> getSuperPropertyFields(ClassNode cNode) {
final List<FieldNode> result;
if (cNode == ClassHelper.OBJECT_TYPE) {
result = new ArrayList<FieldNode>();
} else {
result = getSuperPropertyFields(cNode.getSuperClass());
}
for (PropertyNode pNode : cNode.getProperties()) {
if (!pNode.isStatic()) {
result.add(pNode.getField());
}
}
return result;
}
public static List<PropertyNode> getAllProperties(Set<String> names, ClassNode cNode, boolean includeProperties, boolean includeFields, boolean includePseudoGetters, boolean includePseudoSetters, boolean traverseSuperClasses, boolean skipReadonly) {
return getAllProperties(names, cNode, cNode, includeProperties, includeFields, includePseudoGetters, includePseudoSetters, traverseSuperClasses, skipReadonly);
}
public static List<PropertyNode> getAllProperties(Set<String> names, ClassNode origType, ClassNode cNode, boolean includeProperties, boolean includeFields, boolean includePseudoGetters, boolean includePseudoSetters, boolean traverseSuperClasses, boolean skipReadonly) {
return getAllProperties(names, origType, cNode, includeProperties, includeFields, includePseudoGetters, includePseudoSetters, traverseSuperClasses, skipReadonly, false, false, false);
}
public static List<PropertyNode> getAllProperties(Set<String> names, ClassNode origType, ClassNode cNode, boolean includeProperties,
boolean includeFields, boolean includePseudoGetters, boolean includePseudoSetters,
boolean traverseSuperClasses, boolean skipReadonly, boolean reverse, boolean allNames, boolean includeStatic) {
final List<PropertyNode> result = new ArrayList<PropertyNode>();
if (cNode != ClassHelper.OBJECT_TYPE && traverseSuperClasses && !reverse) {
result.addAll(getAllProperties(names, origType, cNode.getSuperClass(), includeProperties, includeFields, includePseudoGetters, includePseudoSetters, true, skipReadonly));
}
if (includeProperties) {
for (PropertyNode pNode : cNode.getProperties()) {
if ((!pNode.isStatic() || includeStatic) && !names.contains(pNode.getName())) {
result.add(pNode);
names.add(pNode.getName());
}
}
if (includePseudoGetters || includePseudoSetters) {
BeanUtils.addPseudoProperties(origType, cNode, result, names, includeStatic, includePseudoGetters, includePseudoSetters);
}
}
if (includeFields) {
for (FieldNode fNode : cNode.getFields()) {
if ((fNode.isStatic() && !includeStatic) || fNode.isSynthetic() || cNode.getProperty(fNode.getName()) != null || names.contains(fNode.getName())) {
continue;
}
// internal field
if (fNode.getName().contains("$") && !allNames) {
continue;
}
if (fNode.isPrivate() && !cNode.equals(origType)) {
continue;
}
if (fNode.isFinal() && fNode.getInitialExpression() != null && skipReadonly) {
continue;
}
result.add(new PropertyNode(fNode, fNode.getModifiers(), null, null));
names.add(fNode.getName());
}
}
if (cNode != ClassHelper.OBJECT_TYPE && traverseSuperClasses && reverse) {
result.addAll(getAllProperties(names, origType, cNode.getSuperClass(), includeProperties, includeFields, includePseudoGetters, includePseudoSetters, true, skipReadonly));
}
return result;
}
public static BinaryExpression hasClassX(Expression instance, ClassNode cNode) {
return eqX(classX(cNode), callX(instance, "getClass"));
}
private static boolean hasClosureMember(AnnotationNode annotation) {
Map<String, Expression> members = annotation.getMembers();
for (Map.Entry<String, Expression> member : members.entrySet()) {
if (member.getValue() instanceof ClosureExpression) return true;
if (member.getValue() instanceof ClassExpression) {
ClassExpression classExpression = (ClassExpression) member.getValue();
Class<?> typeClass = classExpression.getType().isResolved() ? classExpression.getType().redirect().getTypeClass() : null;
if (typeClass != null && GeneratedClosure.class.isAssignableFrom(typeClass)) return true;
}
}
return false;
}
public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) {
List<MethodNode> ms = cNode.getDeclaredMethods(name);
for (MethodNode m : ms) {
Parameter[] paras = m.getParameters();
if (paras != null && paras.length == argsCount) {
return true;
}
}
return false;
}
public static BinaryExpression hasEqualFieldX(FieldNode fNode, Expression other) {
return eqX(varX(fNode), propX(other, fNode.getName()));
}
public static BinaryExpression hasEqualPropertyX(ClassNode annotatedNode, PropertyNode pNode, VariableExpression other) {
return eqX(getterThisX(annotatedNode, pNode), getterX(other.getOriginType(), other, pNode));
}
@Deprecated
public static BinaryExpression hasEqualPropertyX(PropertyNode pNode, Expression other) {
String getterName = getGetterName(pNode);
return eqX(callThisX(getterName), callX(other, getterName));
}
public static BooleanExpression hasSameFieldX(FieldNode fNode, Expression other) {
return sameX(varX(fNode), propX(other, fNode.getName()));
}
public static BooleanExpression hasSamePropertyX(PropertyNode pNode, Expression other) {
ClassNode cNode = pNode.getDeclaringClass();
return sameX(getterThisX(cNode, pNode), getterX(cNode, other, pNode));
}
public static Statement ifElseS(Expression cond, Statement thenStmt, Statement elseStmt) {
return new IfStatement(
cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond),
thenStmt,
elseStmt
);
}
public static Statement ifS(Expression cond, Expression trueExpr) {
return ifS(cond, new ExpressionStatement(trueExpr));
}
public static Statement ifS(Expression cond, Statement trueStmt) {
return new IfStatement(
cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond),
trueStmt,
EmptyStatement.INSTANCE
);
}
public static Expression indexX(Expression target, Expression value) {
return new BinaryExpression(target, INDEX, value);
}
public static BooleanExpression isInstanceOfX(Expression objectExpression, ClassNode cNode) {
return new BooleanExpression(new BinaryExpression(objectExpression, INSTANCEOF, classX(cNode)));
}
public static BooleanExpression isNullX(Expression expr) {
return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(null)));
}
public static BooleanExpression isOneX(Expression expr) {
return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(1)));
}
public static boolean isOrImplements(ClassNode type, ClassNode interfaceType) {
return type.equals(interfaceType) || type.implementsInterface(interfaceType);
}
public static BooleanExpression isTrueX(Expression argExpr) {
return new BooleanExpression(new BinaryExpression(argExpr, EQ, new ConstantExpression(Boolean.TRUE)));
}
public static BooleanExpression isZeroX(Expression expr) {
return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(0)));
}
public static ListExpression listX(List<Expression> args) {
return new ListExpression(args);
}
public static ListExpression list2args(List args) {
ListExpression result = new ListExpression();
for (Object o : args) {
result.addExpression(new ConstantExpression(o));
}
return result;
}
public static ListExpression classList2args(List<String> args) {
ListExpression result = new ListExpression();
for (Object o : args) {
result.addExpression(new ClassExpression(ClassHelper.make(o.toString())));
}
return result;
}
public static VariableExpression localVarX(String name) {
VariableExpression result = new VariableExpression(name);
result.setAccessedVariable(result);
return result;
}
public static VariableExpression localVarX(String name, ClassNode type) {
VariableExpression result = new VariableExpression(name, type);
result.setAccessedVariable(result);
return result;
}
public static BinaryExpression ltX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, LT, rhv);
}
public static MapExpression mapX(List<MapEntryExpression> expressions) {
return new MapExpression(expressions);
}
public static MapEntryExpression entryX(Expression key, Expression value) {
return new MapEntryExpression(key, value);
}
public static BinaryExpression notIdenticalX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, NOT_IDENTICAL, rhv);
}
/**
* @deprecated use MethodNodeUtils#methodDescriptorWithoutReturnType(MethodNode) instead
*/
@Deprecated
public static String makeDescriptorWithoutReturnType(MethodNode mn) {
StringBuilder sb = new StringBuilder();
sb.append(mn.getName()).append(':');
for (Parameter p : mn.getParameters()) {
sb.append(p.getType()).append(',');
}
return sb.toString();
}
public static BinaryExpression neX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, NE, rhv);
}
public static ConstantExpression nullX() {
return new ConstantExpression(null);
}
public static BooleanExpression notNullX(Expression argExpr) {
return new BooleanExpression(new BinaryExpression(argExpr, NE, new ConstantExpression(null)));
}
public static NotExpression notX(Expression expr) {
return new NotExpression(expr instanceof BooleanExpression ? expr : new BooleanExpression(expr));
}
public static BinaryExpression orX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, OR, rhv);
}
public static Parameter param(ClassNode type, String name) {
return param(type, name, null);
}
public static Parameter param(ClassNode type, String name, Expression initialExpression) {
Parameter param = new Parameter(type, name);
if (initialExpression != null) {
param.setInitialExpression(initialExpression);
}
return param;
}
public static Parameter[] params(Parameter... params) {
return params != null ? params : Parameter.EMPTY_ARRAY;
}
public static BinaryExpression plusX(Expression lhv, Expression rhv) {
return new BinaryExpression(lhv, PLUS, rhv);
}
public static PropertyExpression propX(Expression owner, String property) {
return new PropertyExpression(owner, property);
}
public static PropertyExpression propX(Expression owner, Expression property) {
return new PropertyExpression(owner, property);
}
public static PropertyExpression thisPropX(boolean implicit, String property) {
PropertyExpression pexp = propX(varX("this"), property);
pexp.setImplicitThis(implicit);
return pexp;
}
public static Statement returnS(Expression expr) {
return new ReturnStatement(new ExpressionStatement(expr));
}
public static Statement safeExpression(Expression fieldExpr, Expression expression) {
return new IfStatement(
equalsNullX(fieldExpr),
new ExpressionStatement(fieldExpr),
new ExpressionStatement(expression));
}
public static BooleanExpression sameX(Expression self, Expression other) {
return new BooleanExpression(callX(self, "is", args(other)));
}
public static Statement stmt(Expression expr) {
return new ExpressionStatement(expr);
}
public static TernaryExpression ternaryX(Expression cond, Expression trueExpr, Expression elseExpr) {
return new TernaryExpression(
cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond),
trueExpr,
elseExpr);
}
public static VariableExpression varX(String name) {
return new VariableExpression(name);
}
public static VariableExpression varX(Variable variable) {
return new VariableExpression(variable);
}
public static VariableExpression varX(String name, ClassNode type) {
return new VariableExpression(name, type);
}
public static ThrowStatement throwS(Expression expr) {
return new ThrowStatement(expr);
}
public static CatchStatement catchS(Parameter variable, Statement code) {
return new CatchStatement(variable, code);
}
public static TryCatchStatement tryCatchS(Statement tryStatement) {
return tryCatchS(tryStatement, EmptyStatement.INSTANCE);
}
public static TryCatchStatement tryCatchS(Statement tryStatement, Statement finallyStatement) {
return new TryCatchStatement(tryStatement, finallyStatement);
}
/**
* This method is similar to {@link #propX(Expression, Expression)} but will make sure that if the property
* being accessed is defined inside the classnode provided as a parameter, then a getter call is generated
* instead of a field access.
* @param annotatedNode the class node where the property node is accessed from
* @param pNode the property being accessed
* @return a method call expression or a property expression
*/
public static Expression getterThisX(ClassNode annotatedNode, PropertyNode pNode) {
ClassNode owner = pNode.getDeclaringClass();
if (annotatedNode.equals(owner)) {
return callThisX(getterName(annotatedNode, pNode));
}
return propX(new VariableExpression("this"), pNode.getName());
}
private static String getterName(ClassNode annotatedNode, PropertyNode pNode) {
String getterName = "get" + capitalize(pNode.getName());
boolean existingExplicitGetter = annotatedNode.getMethod(getterName, Parameter.EMPTY_ARRAY) != null;
if (ClassHelper.boolean_TYPE.equals(pNode.getOriginType()) && !existingExplicitGetter) {
getterName = "is" + capitalize(pNode.getName());
}
return getterName;
}
/**
* This method is similar to {@link #propX(Expression, Expression)} but will make sure that if the property
* being accessed is defined inside the classnode provided as a parameter, then a getter call is generated
* instead of a field access.
* @param annotatedNode the class node where the property node is accessed from
* @param receiver the object having the property
* @param pNode the property being accessed
* @return a method call expression or a property expression
*/
public static Expression getterX(ClassNode annotatedNode, Expression receiver, PropertyNode pNode) {
ClassNode owner = pNode.getDeclaringClass();
if (annotatedNode.equals(owner)) {
return callX(receiver, getterName(annotatedNode, pNode));
}
return propX(receiver, pNode.getName());
}
/**
* Converts an expression into the String source. Only some specific expressions like closure expression
* support this.
*
* @param readerSource a source
* @param expression an expression. Can't be null
* @return the source the closure was created from
* @throws java.lang.IllegalArgumentException when expression is null
* @throws java.lang.Exception when closure can't be read from source
*/
public static String convertASTToSource(ReaderSource readerSource, ASTNode expression) throws Exception {
if (expression == null) throw new IllegalArgumentException("Null: expression");
StringBuilder result = new StringBuilder();
for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) {
String line = readerSource.getLine(x, null);
if (line == null) {
throw new Exception(
"Error calculating source code for expression. Trying to read line " + x + " from " + readerSource.getClass()
);
}
if (x == expression.getLastLineNumber()) {
line = line.substring(0, expression.getLastColumnNumber() - 1);
}
if (x == expression.getLineNumber()) {
line = line.substring(expression.getColumnNumber() - 1);
}
//restoring line breaks is important b/c of lack of semicolons
result.append(line).append('\n');
}
String source = result.toString().trim();
return source;
}
public static boolean copyStatementsWithSuperAdjustment(ClosureExpression pre, BlockStatement body) {
Statement preCode = pre.getCode();
boolean changed = false;
if (preCode instanceof BlockStatement) {
BlockStatement block = (BlockStatement) preCode;
List<Statement> statements = block.getStatements();
for (int i = 0; i < statements.size(); i++) {
Statement statement = statements.get(i);
// adjust the first statement if it's a super call
if (i == 0 && statement instanceof ExpressionStatement) {
ExpressionStatement es = (ExpressionStatement) statement;
Expression preExp = es.getExpression();
if (preExp instanceof MethodCallExpression) {
MethodCallExpression mce = (MethodCallExpression) preExp;
String name = mce.getMethodAsString();
if ("super".equals(name)) {
es.setExpression(new ConstructorCallExpression(ClassNode.SUPER, mce.getArguments()));
changed = true;
}
}
}
body.addStatement(statement);
}
}
return changed;
}
public static String getSetterName(String name) {
return "set" + Verifier.capitalize(name);
}
public static boolean isDefaultVisibility(int modifiers) {
return (modifiers & (Modifier.PRIVATE | Modifier.PUBLIC | Modifier.PROTECTED)) == 0;
}
public static boolean inSamePackage(ClassNode first, ClassNode second) {
PackageNode firstPackage = first.getPackage();
PackageNode secondPackage = second.getPackage();
return ((firstPackage == null && secondPackage == null) ||
firstPackage != null && secondPackage != null && firstPackage.getName().equals(secondPackage.getName()));
}
public static boolean inSamePackage(Class first, Class second) {
Package firstPackage = first.getPackage();
Package secondPackage = second.getPackage();
return ((firstPackage == null && secondPackage == null) ||
firstPackage != null && secondPackage != null && firstPackage.getName().equals(secondPackage.getName()));
}
}