use of org.codehaus.groovy.ast.expr.ClassExpression in project groovy by apache.
the class TraitComposer method createForwarderMethod.
private static void createForwarderMethod(ClassNode trait, ClassNode targetNode, MethodNode helperMethod, MethodNode originalMethod, ClassNode helperClassNode, Map<String, ClassNode> genericsSpec, Parameter[] helperMethodParams, Parameter[] traitMethodParams, Parameter[] forwarderParams, ArgumentListExpression helperMethodArgList) {
MethodCallExpression mce = new MethodCallExpression(new ClassExpression(helperClassNode), helperMethod.getName(), helperMethodArgList);
mce.setImplicitThis(false);
genericsSpec = GenericsUtils.addMethodGenerics(helperMethod, genericsSpec);
ClassNode[] exceptionNodes = correctToGenericsSpecRecurse(genericsSpec, copyExceptions(helperMethod.getExceptions()));
ClassNode fixedReturnType = correctToGenericsSpecRecurse(genericsSpec, helperMethod.getReturnType());
boolean noCastRequired = genericsSpec.isEmpty() || fixedReturnType.getName().equals(ClassHelper.VOID_TYPE.getName());
Expression forwardExpression = noCastRequired ? mce : new CastExpression(fixedReturnType, mce);
int access = helperMethod.getModifiers();
// we could rely on the first parameter name ($static$self) but that information is not
// guaranteed to be always present
boolean isHelperForStaticMethod = helperMethodParams[0].getOriginType().equals(ClassHelper.CLASS_Type);
if (Modifier.isPrivate(access) && !isHelperForStaticMethod) {
// see GROOVY-7213
return;
}
if (!isHelperForStaticMethod) {
access = access ^ Opcodes.ACC_STATIC;
}
MethodNode forwarder = new MethodNode(helperMethod.getName(), access, fixedReturnType, forwarderParams, exceptionNodes, new ExpressionStatement(forwardExpression));
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
// at this point, should *always* stay empty
List<AnnotationNode> notCopied = Collections.emptyList();
GeneralUtils.copyAnnotatedNodeAnnotations(helperMethod, copied, notCopied);
if (!copied.isEmpty()) {
forwarder.addAnnotations(copied);
}
if (originalMethod != null) {
GenericsType[] newGt = GenericsUtils.applyGenericsContextToPlaceHolders(genericsSpec, originalMethod.getGenericsTypes());
newGt = removeNonPlaceHolders(newGt);
forwarder.setGenericsTypes(newGt);
} else {
// null indicates a static method which may still need generics correction
GenericsType[] genericsTypes = helperMethod.getGenericsTypes();
if (genericsTypes != null) {
Map<String, ClassNode> methodSpec = new HashMap<String, ClassNode>();
methodSpec = GenericsUtils.addMethodGenerics(helperMethod, methodSpec);
GenericsType[] newGt = GenericsUtils.applyGenericsContextToPlaceHolders(methodSpec, helperMethod.getGenericsTypes());
forwarder.setGenericsTypes(newGt);
}
}
// add a helper annotation indicating that it is a bridge method
AnnotationNode bridgeAnnotation = new AnnotationNode(Traits.TRAITBRIDGE_CLASSNODE);
bridgeAnnotation.addMember("traitClass", new ClassExpression(trait));
bridgeAnnotation.addMember("desc", new ConstantExpression(BytecodeHelper.getMethodDescriptor(helperMethod.getReturnType(), traitMethodParams)));
forwarder.addAnnotation(bridgeAnnotation);
if (!shouldSkipMethod(targetNode, forwarder.getName(), forwarderParams)) {
targetNode.addMethod(forwarder);
}
createSuperForwarder(targetNode, forwarder, genericsSpec);
}
use of org.codehaus.groovy.ast.expr.ClassExpression in project groovy by apache.
the class TraitComposer method applyTrait.
private static void applyTrait(final ClassNode trait, final ClassNode cNode, final TraitHelpersTuple helpers) {
ClassNode helperClassNode = helpers.getHelper();
ClassNode fieldHelperClassNode = helpers.getFieldHelper();
Map<String, ClassNode> genericsSpec = GenericsUtils.createGenericsSpec(cNode);
genericsSpec = GenericsUtils.createGenericsSpec(trait, genericsSpec);
for (MethodNode methodNode : helperClassNode.getAllDeclaredMethods()) {
String name = methodNode.getName();
Parameter[] helperMethodParams = methodNode.getParameters();
boolean isAbstract = methodNode.isAbstract();
if (!isAbstract && helperMethodParams.length > 0 && ((methodNode.getModifiers() & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) && (!name.contains("$") || (methodNode.getModifiers() & Opcodes.ACC_SYNTHETIC) == 0)) {
ArgumentListExpression argList = new ArgumentListExpression();
argList.addExpression(new VariableExpression("this"));
Parameter[] origParams = new Parameter[helperMethodParams.length - 1];
Parameter[] params = new Parameter[helperMethodParams.length - 1];
System.arraycopy(methodNode.getParameters(), 1, params, 0, params.length);
Map<String, ClassNode> methodGenericsSpec = new LinkedHashMap<String, ClassNode>(genericsSpec);
MethodNode originalMethod = trait.getMethod(name, params);
// Original method may be null for the case of private or static methods
if (originalMethod != null) {
methodGenericsSpec = GenericsUtils.addMethodGenerics(originalMethod, methodGenericsSpec);
}
for (int i = 1; i < helperMethodParams.length; i++) {
Parameter parameter = helperMethodParams[i];
ClassNode originType = parameter.getOriginType();
ClassNode fixedType = correctToGenericsSpecRecurse(methodGenericsSpec, originType);
Parameter newParam = new Parameter(fixedType, "arg" + i);
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
GeneralUtils.copyAnnotatedNodeAnnotations(parameter, copied, notCopied);
newParam.addAnnotations(copied);
params[i - 1] = newParam;
origParams[i - 1] = parameter;
argList.addExpression(new VariableExpression(params[i - 1]));
}
createForwarderMethod(trait, cNode, methodNode, originalMethod, helperClassNode, methodGenericsSpec, helperMethodParams, origParams, params, argList);
}
}
cNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(new ClassExpression(helperClassNode), Traits.INIT_METHOD, new ArgumentListExpression(new VariableExpression("this")))));
MethodCallExpression staticInitCall = new MethodCallExpression(new ClassExpression(helperClassNode), Traits.STATIC_INIT_METHOD, new ArgumentListExpression(new ClassExpression(cNode)));
MethodNode staticInitMethod = new MethodNode(Traits.STATIC_INIT_METHOD, Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, ClassHelper.VOID_TYPE, new Parameter[] { new Parameter(ClassHelper.CLASS_Type, "clazz") }, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
staticInitMethod.setDeclaringClass(helperClassNode);
staticInitCall.setMethodTarget(staticInitMethod);
cNode.addStaticInitializerStatements(Collections.<Statement>singletonList(new ExpressionStatement(staticInitCall)), false);
if (fieldHelperClassNode != null && !cNode.declaresInterface(fieldHelperClassNode)) {
// we should implement the field helper interface too
cNode.addInterface(fieldHelperClassNode);
// implementation of methods
List<MethodNode> declaredMethods = new LinkedList<MethodNode>();
for (MethodNode declaredMethod : fieldHelperClassNode.getAllDeclaredMethods()) {
if (declaredMethod.getName().endsWith(Traits.DIRECT_GETTER_SUFFIX)) {
declaredMethods.add(0, declaredMethod);
} else {
declaredMethods.add(declaredMethod);
}
}
for (MethodNode methodNode : declaredMethods) {
String fieldName = methodNode.getName();
if (fieldName.endsWith(Traits.DIRECT_GETTER_SUFFIX) || fieldName.endsWith(Traits.DIRECT_SETTER_SUFFIX)) {
int suffixIdx = fieldName.lastIndexOf("$");
fieldName = fieldName.substring(0, suffixIdx);
String operation = methodNode.getName().substring(suffixIdx + 1);
boolean getter = "get".equals(operation);
ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, methodNode.getReturnType());
int fieldMods = 0;
int isStatic = 0;
boolean publicField = true;
FieldNode helperField = null;
fieldMods = 0;
isStatic = 0;
// look first for field with encoded modifier information
for (Integer mod : Traits.FIELD_PREFIXES) {
helperField = fieldHelperClassNode.getField(String.format("$0x%04x", mod) + fieldName);
if (helperField != null) {
if ((mod & Opcodes.ACC_STATIC) != 0)
isStatic = Opcodes.ACC_STATIC;
fieldMods = fieldMods | mod;
break;
}
}
if (helperField == null) {
// look for possible legacy fields (trait compiled pre 2.4.8)
helperField = fieldHelperClassNode.getField(Traits.FIELD_PREFIX + Traits.PUBLIC_FIELD_PREFIX + fieldName);
if (helperField == null) {
publicField = false;
helperField = fieldHelperClassNode.getField(Traits.FIELD_PREFIX + Traits.PRIVATE_FIELD_PREFIX + fieldName);
}
if (helperField == null) {
publicField = true;
// try to find a static one
helperField = fieldHelperClassNode.getField(Traits.STATIC_FIELD_PREFIX + Traits.PUBLIC_FIELD_PREFIX + fieldName);
if (helperField == null) {
publicField = false;
helperField = fieldHelperClassNode.getField(Traits.STATIC_FIELD_PREFIX + Traits.PRIVATE_FIELD_PREFIX + fieldName);
}
fieldMods = fieldMods | Opcodes.ACC_STATIC;
isStatic = Opcodes.ACC_STATIC;
}
fieldMods = fieldMods | (publicField ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE);
}
if (getter) {
// add field
if (helperField != null) {
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
GeneralUtils.copyAnnotatedNodeAnnotations(helperField, copied, notCopied);
FieldNode fieldNode = cNode.addField(fieldName, fieldMods, returnType, (fieldMods & Opcodes.ACC_FINAL) == 0 ? null : helperField.getInitialExpression());
fieldNode.addAnnotations(copied);
// so instead set within (static) initializer
if (fieldNode.isFinal() && !(helperClassNode instanceof InnerClassNode)) {
String baseName = fieldNode.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
Expression mce = callX(helperClassNode, baseName + fieldNode.getName());
Statement stmt = stmt(assignX(varX(fieldNode.getName(), fieldNode.getType()), mce));
if (isStatic == 0) {
cNode.addObjectInitializerStatements(stmt);
} else {
cNode.addStaticInitializerStatements(Collections.<Statement>singletonList(stmt), false);
}
}
}
}
Parameter[] newParams;
if (getter) {
newParams = Parameter.EMPTY_ARRAY;
} else {
ClassNode originType = methodNode.getParameters()[0].getOriginType();
ClassNode fixedType = originType.isGenericsPlaceHolder() ? ClassHelper.OBJECT_TYPE : correctToGenericsSpecRecurse(genericsSpec, originType);
newParams = new Parameter[] { new Parameter(fixedType, "val") };
}
Expression fieldExpr = varX(cNode.getField(fieldName));
boolean finalSetter = !getter && (fieldMods & Opcodes.ACC_FINAL) != 0;
Statement body = getter ? returnS(fieldExpr) : (finalSetter ? null : stmt(new BinaryExpression(fieldExpr, Token.newSymbol(Types.EQUAL, 0, 0), varX(newParams[0]))));
// add getter/setter even though setter not strictly needed for final fields
// but add empty body for setter for legacy compatibility
MethodNode impl = new MethodNode(methodNode.getName(), Opcodes.ACC_PUBLIC | isStatic, returnType, newParams, ClassNode.EMPTY_ARRAY, body);
AnnotationNode an = new AnnotationNode(COMPILESTATIC_CLASSNODE);
impl.addAnnotation(an);
cNode.addTransform(StaticCompileTransformation.class, an);
cNode.addMethod(impl);
}
}
}
}
use of org.codehaus.groovy.ast.expr.ClassExpression in project groovy by apache.
the class TraitReceiverTransformer method transformPrivateMethodCallOnThisInClosure.
private Expression transformPrivateMethodCallOnThisInClosure(final MethodCallExpression call, final Expression arguments, final String methodName) {
ArgumentListExpression newArgs = createArgumentList(arguments);
MethodCallExpression transformed = new MethodCallExpression(new ClassExpression(traitHelperClass), methodName, newArgs);
transformed.setSourcePosition(call);
transformed.setSafe(call.isSafe());
transformed.setSpreadSafe(call.isSpreadSafe());
transformed.setImplicitThis(true);
return transformed;
}
use of org.codehaus.groovy.ast.expr.ClassExpression in project groovy by apache.
the class SuperCallTraitTransformer method transformMethodCallExpression.
private Expression transformMethodCallExpression(final MethodCallExpression exp) {
if (isTraitSuperPropertyExpression(exp.getObjectExpression())) {
Expression objectExpression = exp.getObjectExpression();
ClassNode traitReceiver = ((PropertyExpression) objectExpression).getObjectExpression().getType();
if (traitReceiver != null) {
// (SomeTrait.super).foo() --> SomeTrait$Helper.foo(this)
ClassExpression receiver = new ClassExpression(getHelper(traitReceiver));
ArgumentListExpression newArgs = new ArgumentListExpression();
Expression arguments = exp.getArguments();
newArgs.addExpression(new VariableExpression("this"));
if (arguments instanceof TupleExpression) {
List<Expression> expressions = ((TupleExpression) arguments).getExpressions();
for (Expression expression : expressions) {
newArgs.addExpression(transform(expression));
}
} else {
newArgs.addExpression(transform(arguments));
}
MethodCallExpression result = new MethodCallExpression(receiver, transform(exp.getMethod()), newArgs);
result.setImplicitThis(false);
result.setSpreadSafe(exp.isSpreadSafe());
result.setSafe(exp.isSafe());
result.setSourcePosition(exp);
return result;
}
}
return super.transform(exp);
}
use of org.codehaus.groovy.ast.expr.ClassExpression in project groovy by apache.
the class SuperCallTraitTransformer method isTraitSuperPropertyExpression.
private boolean isTraitSuperPropertyExpression(Expression exp) {
if (exp instanceof PropertyExpression) {
PropertyExpression pexp = (PropertyExpression) exp;
Expression objectExpression = pexp.getObjectExpression();
if (objectExpression instanceof ClassExpression) {
ClassNode type = objectExpression.getType();
if (Traits.isTrait(type) && "super".equals(pexp.getPropertyAsString())) {
return true;
}
}
}
return false;
}
Aggregations