Search in sources :

Example 46 with Parameter

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);
            }
        }
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) FieldNode(org.codehaus.groovy.ast.FieldNode) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) LinkedList(java.util.LinkedList) LinkedHashMap(java.util.LinkedHashMap) MethodNode(org.codehaus.groovy.ast.MethodNode) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) AnnotationNode(org.codehaus.groovy.ast.AnnotationNode) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) ArrayExpression(org.codehaus.groovy.ast.expr.ArrayExpression) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) BinaryExpression(org.codehaus.groovy.ast.expr.BinaryExpression) CastExpression(org.codehaus.groovy.ast.expr.CastExpression) BooleanExpression(org.codehaus.groovy.ast.expr.BooleanExpression) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) MethodCallExpression(org.codehaus.groovy.ast.expr.MethodCallExpression) Expression(org.codehaus.groovy.ast.expr.Expression) ClassExpression(org.codehaus.groovy.ast.expr.ClassExpression) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) Parameter(org.codehaus.groovy.ast.Parameter)

Example 47 with Parameter

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());
        }
    }
}
Also used : ClassNode(org.codehaus.groovy.ast.ClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) IfStatement(org.codehaus.groovy.ast.stmt.IfStatement) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement) Statement(org.codehaus.groovy.ast.stmt.Statement) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) EmptyStatement(org.codehaus.groovy.ast.stmt.EmptyStatement) Parameter(org.codehaus.groovy.ast.Parameter)

Example 48 with Parameter

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;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) PropertyNode(org.codehaus.groovy.ast.PropertyNode) ArrayList(java.util.ArrayList) Parameter(org.codehaus.groovy.ast.Parameter) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode)

Example 49 with Parameter

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);
            }
        }
    }
}
Also used : Parameter(org.codehaus.groovy.ast.Parameter) LinkedList(java.util.LinkedList) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint)

Example 50 with Parameter

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);
}
Also used : MethodNode(org.codehaus.groovy.ast.MethodNode) ConstructorNode(org.codehaus.groovy.ast.ConstructorNode) Parameter(org.codehaus.groovy.ast.Parameter)

Aggregations

Parameter (org.codehaus.groovy.ast.Parameter)342 ClassNode (org.codehaus.groovy.ast.ClassNode)202 MethodNode (org.codehaus.groovy.ast.MethodNode)135 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)117 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)111 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)102 Expression (org.codehaus.groovy.ast.expr.Expression)98 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)90 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)75 FieldNode (org.codehaus.groovy.ast.FieldNode)71 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)71 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)69 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)68 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)66 ConstructorCallExpression (org.codehaus.groovy.ast.expr.ConstructorCallExpression)66 Statement (org.codehaus.groovy.ast.stmt.Statement)66 ArrayList (java.util.ArrayList)62 ClosureExpression (org.codehaus.groovy.ast.expr.ClosureExpression)56 BinaryExpression (org.codehaus.groovy.ast.expr.BinaryExpression)52 PropertyExpression (org.codehaus.groovy.ast.expr.PropertyExpression)51