use of org.codehaus.groovy.ast.Parameter in project groovy-core by groovy.
the class TraitComposer method createSuperForwarder.
/**
* Creates, if necessary, a super forwarder method, for stackable traits.
* @param forwarder a forwarder method
* @param genericsSpec
*/
private static void createSuperForwarder(ClassNode targetNode, MethodNode forwarder, final Map<String, ClassNode> genericsSpec) {
List<ClassNode> interfaces = new ArrayList<ClassNode>(Traits.collectAllInterfacesReverseOrder(targetNode, new LinkedHashSet<ClassNode>()));
String name = forwarder.getName();
Parameter[] forwarderParameters = forwarder.getParameters();
LinkedHashSet<ClassNode> traits = new LinkedHashSet<ClassNode>();
List<MethodNode> superForwarders = new LinkedList<MethodNode>();
for (ClassNode node : interfaces) {
if (Traits.isTrait(node)) {
MethodNode method = node.getDeclaredMethod(name, forwarderParameters);
if (method != null) {
// a similar method exists, we need a super bridge
// trait$super$foo(Class currentTrait, ...)
traits.add(node);
superForwarders.add(method);
}
}
}
for (MethodNode superForwarder : superForwarders) {
doCreateSuperForwarder(targetNode, superForwarder, traits.toArray(new ClassNode[traits.size()]), genericsSpec);
}
}
use of org.codehaus.groovy.ast.Parameter in project groovy-core by groovy.
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("$")) {
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 in case of a private method
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 = fieldHelperClassNode.getAllDeclaredMethods();
Collections.sort(declaredMethods, GETTER_FIRST_COMPARATOR);
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 isStatic = 0;
boolean publicField = true;
FieldNode 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);
}
isStatic = Opcodes.ACC_STATIC;
}
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, (publicField ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE) | isStatic, returnType, null);
fieldNode.addAnnotations(copied);
}
}
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 = new VariableExpression(cNode.getField(fieldName));
Statement body = getter ? new ReturnStatement(fieldExpr) : new ExpressionStatement(new BinaryExpression(fieldExpr, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression(newParams[0])));
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.Parameter in project groovy-core by groovy.
the class TraitComposer method createDelegatingForwarder.
private static Statement createDelegatingForwarder(final MethodNode forwarderMethod, final ClassNode next) {
// generates --> next$Trait$Helper.method(this, arg1, arg2)
TraitHelpersTuple helpers = Traits.findHelpers(next);
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new VariableExpression("this"));
Parameter[] forwarderMethodParameters = forwarderMethod.getParameters();
for (final Parameter forwarderMethodParameter : forwarderMethodParameters) {
args.addExpression(new VariableExpression(forwarderMethodParameter));
}
StaticMethodCallExpression delegateCall = new StaticMethodCallExpression(helpers.getHelper(), forwarderMethod.getName(), args);
Statement result;
if (ClassHelper.VOID_TYPE.equals(forwarderMethod.getReturnType())) {
BlockStatement stmt = new BlockStatement();
stmt.addStatement(new ExpressionStatement(delegateCall));
stmt.addStatement(new ReturnStatement(new ConstantExpression(null)));
result = stmt;
} else {
result = new ReturnStatement(delegateCall);
}
return result;
}
use of org.codehaus.groovy.ast.Parameter in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method addGeneratedMethods.
private List<MethodNode> addGeneratedMethods(final ClassNode receiver, final List<MethodNode> methods) {
// using a comparator of parameters
List<MethodNode> result = new LinkedList<MethodNode>();
for (MethodNode method : methods) {
result.add(method);
Parameter[] parameters = method.getParameters();
int counter = 0;
int size = parameters.length;
for (int i = size - 1; i >= 0; i--) {
Parameter parameter = parameters[i];
if (parameter != null && parameter.hasInitialExpression()) {
counter++;
}
}
for (int j = 1; j <= counter; j++) {
Parameter[] newParams = new Parameter[parameters.length - j];
int index = 0;
int k = 1;
for (int i = 0; i < parameters.length; i++) {
if (k > counter - j && parameters[i] != null && parameters[i].hasInitialExpression()) {
k++;
} else if (parameters[i] != null && parameters[i].hasInitialExpression()) {
newParams[index++] = parameters[i];
k++;
} else {
newParams[index++] = parameters[i];
}
}
MethodNode stubbed;
if ("<init>".equals(method.getName())) {
stubbed = new ConstructorNode(method.getModifiers(), newParams, method.getExceptions(), GENERATED_EMPTY_STATEMENT);
} else {
stubbed = new MethodNode(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), GENERATED_EMPTY_STATEMENT);
stubbed.setGenericsTypes(method.getGenericsTypes());
}
stubbed.setDeclaringClass(receiver);
result.add(stubbed);
}
}
return result;
}
use of org.codehaus.groovy.ast.Parameter in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method findMethod.
protected List<MethodNode> findMethod(ClassNode receiver, String name, ClassNode... args) {
if (isPrimitiveType(receiver))
receiver = getWrapper(receiver);
List<MethodNode> methods;
if (!receiver.isInterface() && "<init>".equals(name)) {
methods = addGeneratedMethods(receiver, new ArrayList<MethodNode>(receiver.getDeclaredConstructors()));
if (methods.isEmpty()) {
MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
node.setDeclaringClass(receiver);
return Collections.singletonList(node);
}
} else {
methods = findMethodsWithGenerated(receiver, name);
if (receiver.isInterface()) {
collectAllInterfaceMethodsByName(receiver, name, methods);
methods.addAll(OBJECT_TYPE.getMethods(name));
}
if (typeCheckingContext.getEnclosingClosure() == null) {
// not in a closure
ClassNode parent = receiver;
while (parent instanceof InnerClassNode && !parent.isStaticClass()) {
parent = parent.getOuterClass();
methods.addAll(findMethodsWithGenerated(parent, name));
}
}
if (methods.isEmpty()) {
addArrayMethods(methods, receiver, name, args);
}
if (methods.isEmpty() && (args == null || args.length == 0)) {
// check if it's a property
String pname = extractPropertyNameFromMethodName("get", name);
if (pname == null) {
pname = extractPropertyNameFromMethodName("is", name);
}
if (pname != null) {
// we don't use property exists there because findMethod is called on super clases recursively
PropertyNode property = null;
ClassNode curNode = receiver;
while (property == null && curNode != null) {
property = curNode.getProperty(pname);
ClassNode svCur = curNode;
while (property == null && svCur instanceof InnerClassNode && !svCur.isStaticClass()) {
svCur = svCur.getOuterClass();
property = svCur.getProperty(pname);
if (property != null) {
receiver = svCur;
break;
}
}
curNode = curNode.getSuperClass();
}
if (property != null) {
MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
if (property.isStatic()) {
node.setModifiers(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC);
}
node.setDeclaringClass(receiver);
return Collections.singletonList(node);
}
}
} else if (methods.isEmpty() && args != null && args.length == 1) {
// maybe we are looking for a setter ?
String pname = extractPropertyNameFromMethodName("set", name);
if (pname != null) {
ClassNode curNode = receiver;
PropertyNode property = null;
while (property == null && curNode != null) {
property = curNode.getProperty(pname);
curNode = curNode.getSuperClass();
}
if (property != null) {
ClassNode type = property.getOriginType();
if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) {
MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, VOID_TYPE, new Parameter[] { new Parameter(type, "arg") }, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
if (property.isStatic()) {
node.setModifiers(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC);
}
node.setDeclaringClass(receiver);
return Collections.singletonList(node);
}
}
}
}
}
if (methods.isEmpty()) {
// look at the interfaces, there's a chance that a method is not implemented and we should not hide the
// error from the compiler
collectAllInterfaceMethodsByName(receiver, name, methods);
}
// lookup in DGM methods too
findDGMMethodsByNameAndArguments(getTransformLoader(), receiver, name, args, methods);
List<MethodNode> chosen = chooseBestMethod(receiver, methods, args);
if (!chosen.isEmpty())
return chosen;
// GROOVY-5566
if (receiver instanceof InnerClassNode && ((InnerClassNode) receiver).isAnonymous() && methods.size() == 1 && args != null && "<init>".equals(name)) {
MethodNode constructor = methods.get(0);
if (constructor.getParameters().length == args.length) {
return methods;
}
}
if (receiver.equals(CLASS_Type) && receiver.getGenericsTypes() != null) {
List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
if (!result.isEmpty())
return result;
}
if (ClassHelper.GSTRING_TYPE.equals(receiver))
return findMethod(ClassHelper.STRING_TYPE, name, args);
if (isBeingCompiled(receiver)) {
chosen = findMethod(GROOVY_OBJECT_TYPE, name, args);
if (!chosen.isEmpty())
return chosen;
}
return EMPTY_METHODNODE_LIST;
}
Aggregations