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 doCreateSuperForwarder.
/**
* Creates a method to dispatch to "super traits" in a "stackable" fashion. The generated method looks like this:
* <p>
* <code>ReturnType trait$super$method(Class clazz, Arg1 arg1, Arg2 arg2, ...) {
* if (SomeTrait.is(A) { return SomeOtherTrait$Trait$Helper.method(this, arg1, arg2) }
* super.method(arg1,arg2)
* }</code>
* </p>
* @param targetNode
* @param forwarderMethod
* @param interfacesToGenerateForwarderFor
* @param genericsSpec
*/
private static void doCreateSuperForwarder(ClassNode targetNode, MethodNode forwarderMethod, ClassNode[] interfacesToGenerateForwarderFor, Map<String, ClassNode> genericsSpec) {
Parameter[] parameters = forwarderMethod.getParameters();
Parameter[] superForwarderParams = new Parameter[parameters.length];
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
ClassNode originType = parameter.getOriginType();
superForwarderParams[i] = new Parameter(correctToGenericsSpecRecurse(genericsSpec, originType), parameter.getName());
}
for (int i = 0; i < interfacesToGenerateForwarderFor.length; i++) {
final ClassNode current = interfacesToGenerateForwarderFor[i];
final ClassNode next = i < interfacesToGenerateForwarderFor.length - 1 ? interfacesToGenerateForwarderFor[i + 1] : null;
String forwarderName = Traits.getSuperTraitMethodName(current, forwarderMethod.getName());
if (targetNode.getDeclaredMethod(forwarderName, superForwarderParams) == null) {
ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, forwarderMethod.getReturnType());
Statement delegate = next == null ? createSuperFallback(forwarderMethod, returnType) : createDelegatingForwarder(forwarderMethod, next);
MethodNode methodNode = targetNode.addMethod(forwarderName, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, returnType, superForwarderParams, ClassNode.EMPTY_ARRAY, delegate);
methodNode.setGenericsTypes(forwarderMethod.getGenericsTypes());
}
}
}
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;
}
use of org.codehaus.groovy.ast.Parameter in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method visitMethodCallArguments.
protected void visitMethodCallArguments(final ClassNode receiver, ArgumentListExpression arguments, boolean visitClosures, final MethodNode selectedMethod) {
Parameter[] params = selectedMethod != null ? selectedMethod.getParameters() : Parameter.EMPTY_ARRAY;
List<Expression> expressions = new LinkedList<Expression>(arguments.getExpressions());
if (selectedMethod instanceof ExtensionMethodNode) {
params = ((ExtensionMethodNode) selectedMethod).getExtensionMethodNode().getParameters();
expressions.add(0, new VariableExpression("$self", receiver));
}
ArgumentListExpression newArgs = new ArgumentListExpression(expressions);
for (int i = 0, expressionsSize = expressions.size(); i < expressionsSize; i++) {
final Expression expression = expressions.get(i);
if (visitClosures && expression instanceof ClosureExpression || !visitClosures && !(expression instanceof ClosureExpression)) {
if (i < params.length && visitClosures) {
Parameter param = params[i];
checkClosureWithDelegatesTo(receiver, selectedMethod, newArgs, params, expression, param);
if (selectedMethod instanceof ExtensionMethodNode) {
if (i > 0) {
inferClosureParameterTypes(receiver, arguments, (ClosureExpression) expression, param, selectedMethod);
}
} else {
inferClosureParameterTypes(receiver, newArgs, (ClosureExpression) expression, param, selectedMethod);
}
}
expression.visit(this);
if (expression.getNodeMetaData(StaticTypesMarker.DELEGATION_METADATA) != null) {
expression.removeNodeMetaData(StaticTypesMarker.DELEGATION_METADATA);
}
}
}
}
use of org.codehaus.groovy.ast.Parameter in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method checkGroovyStyleConstructor.
/**
* Checks that a constructor style expression is valid regarding the number of arguments and the argument types.
*
* @param node the class node for which we will try to find a matching constructor
* @param arguments the constructor arguments
*/
protected MethodNode checkGroovyStyleConstructor(final ClassNode node, final ClassNode[] arguments, final ASTNode source) {
if (node.equals(ClassHelper.OBJECT_TYPE) || node.equals(ClassHelper.DYNAMIC_TYPE)) {
// in that case, we are facing a list constructor assigned to a def or object
return null;
}
List<ConstructorNode> constructors = node.getDeclaredConstructors();
if (constructors.isEmpty() && arguments.length == 0) {
return null;
}
List<MethodNode> constructorList = findMethod(node, "<init>", arguments);
if (constructorList.isEmpty()) {
if (isBeingCompiled(node) && arguments.length == 1 && LINKEDHASHMAP_CLASSNODE.equals(arguments[0])) {
// there will be a default hash map constructor added later
ConstructorNode cn = new ConstructorNode(Opcodes.ACC_PUBLIC, new Parameter[] { new Parameter(LINKEDHASHMAP_CLASSNODE, "args") }, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
return cn;
} else {
addStaticTypeError("No matching constructor found: " + node + toMethodParametersString("<init>", arguments), source);
return null;
}
} else if (constructorList.size() > 1) {
addStaticTypeError("Ambiguous constructor call " + node + toMethodParametersString("<init>", arguments), source);
return null;
}
return constructorList.get(0);
}
Aggregations