Search in sources :

Example 16 with Parameter

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);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ClassNode(org.codehaus.groovy.ast.ClassNode) MethodNode(org.codehaus.groovy.ast.MethodNode) ArrayList(java.util.ArrayList) Parameter(org.codehaus.groovy.ast.Parameter) LinkedList(java.util.LinkedList)

Example 17 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 18 with Parameter

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;
}
Also used : 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) ExpressionStatement(org.codehaus.groovy.ast.stmt.ExpressionStatement) ConstantExpression(org.codehaus.groovy.ast.expr.ConstantExpression) StaticMethodCallExpression(org.codehaus.groovy.ast.expr.StaticMethodCallExpression) ReturnStatement(org.codehaus.groovy.ast.stmt.ReturnStatement) ArgumentListExpression(org.codehaus.groovy.ast.expr.ArgumentListExpression) Parameter(org.codehaus.groovy.ast.Parameter) VariableExpression(org.codehaus.groovy.ast.expr.VariableExpression) BlockStatement(org.codehaus.groovy.ast.stmt.BlockStatement)

Example 19 with Parameter

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

Example 20 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)

Aggregations

Parameter (org.codehaus.groovy.ast.Parameter)221 ClassNode (org.codehaus.groovy.ast.ClassNode)135 MethodNode (org.codehaus.groovy.ast.MethodNode)79 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)70 BlockStatement (org.codehaus.groovy.ast.stmt.BlockStatement)67 FieldNode (org.codehaus.groovy.ast.FieldNode)49 Expression (org.codehaus.groovy.ast.expr.Expression)47 VariableExpression (org.codehaus.groovy.ast.expr.VariableExpression)47 ExpressionStatement (org.codehaus.groovy.ast.stmt.ExpressionStatement)44 Statement (org.codehaus.groovy.ast.stmt.Statement)34 MethodCallExpression (org.codehaus.groovy.ast.expr.MethodCallExpression)33 ArrayList (java.util.ArrayList)32 LinkedList (java.util.LinkedList)32 ConstructorNode (org.codehaus.groovy.ast.ConstructorNode)30 ReturnStatement (org.codehaus.groovy.ast.stmt.ReturnStatement)29 ClassExpression (org.codehaus.groovy.ast.expr.ClassExpression)26 ConstantExpression (org.codehaus.groovy.ast.expr.ConstantExpression)26 IfStatement (org.codehaus.groovy.ast.stmt.IfStatement)26 ArgumentListExpression (org.codehaus.groovy.ast.expr.ArgumentListExpression)25 EmptyStatement (org.codehaus.groovy.ast.stmt.EmptyStatement)25