Java Code Examples for org.codehaus.groovy.ast.tools.GenericsUtils

The following examples show how to use org.codehaus.groovy.ast.tools.GenericsUtils. These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source Project: groovy   Source File: EqualsAndHashCodeASTTransformation.java    License: Apache License 2.0 6 votes vote down vote up
private static void createCanEqual(ClassNode cNode) {
    boolean hasExistingCanEqual = hasDeclaredMethod(cNode, "canEqual", 1);
    if (hasExistingCanEqual && hasDeclaredMethod(cNode, "_canEqual", 1)) return;

    final BlockStatement body = new BlockStatement();
    VariableExpression other = varX("other");
    body.addStatement(returnS(isInstanceOfX(other, GenericsUtils.nonGeneric(cNode))));
    MethodNode canEqual = addGeneratedMethod(cNode,
            hasExistingCanEqual ? "_canEqual" : "canEqual",
            hasExistingCanEqual ? ACC_PRIVATE : ACC_PUBLIC,
            ClassHelper.boolean_TYPE,
            params(param(OBJECT_TYPE, other.getName())),
            ClassNode.EMPTY_ARRAY,
            body);
    // don't null check this: prefer false to IllegalArgumentException
    NullCheckASTTransformation.markAsProcessed(canEqual);
}
 
Example 2
Source Project: groovy   Source File: AutoCloneASTTransformation.java    License: Apache License 2.0 5 votes vote down vote up
private void createCloneSerialization(ClassNode cNode) {
    final BlockStatement body = new BlockStatement();
    // def baos = new ByteArrayOutputStream()
    final Expression baos = localVarX("baos");
    body.addStatement(declS(baos, ctorX(BAOS_TYPE)));

    // baos.withObjectOutputStream{ it.writeObject(this) }
    MethodCallExpression writeObject = callX(castX(OOS_TYPE, varX("it")), "writeObject", varX("this"));
    writeObject.setImplicitThis(false);
    ClosureExpression writeClos = closureX(block(stmt(writeObject)));
    writeClos.setVariableScope(new VariableScope());
    body.addStatement(stmt(callX(baos, "withObjectOutputStream", args(writeClos))));

    // def bais = new ByteArrayInputStream(baos.toByteArray())
    final Expression bais = localVarX("bais");
    body.addStatement(declS(bais, ctorX(BAIS_TYPE, args(callX(baos, "toByteArray")))));

    // return bais.withObjectInputStream(getClass().classLoader){ (<type>) it.readObject() }
    MethodCallExpression readObject = callX(castX(OIS_TYPE, varX("it")), "readObject");
    readObject.setImplicitThis(false);
    ClosureExpression readClos = closureX(block(stmt(castX(GenericsUtils.nonGeneric(cNode), readObject))));
    readClos.setVariableScope(new VariableScope());
    Expression classLoader = callX(callThisX("getClass"), "getClassLoader");
    body.addStatement(returnS(callX(bais, "withObjectInputStream", args(classLoader, readClos))));

    new VariableScopeVisitor(sourceUnit, true).visitClass(cNode);
    ClassNode[] exceptions = {make(CloneNotSupportedException.class)};
    addGeneratedMethod(cNode, "clone", ACC_PUBLIC, GenericsUtils.nonGeneric(cNode), Parameter.EMPTY_ARRAY, exceptions, body);
}
 
Example 3
Source Project: groovy   Source File: AutoCloneASTTransformation.java    License: Apache License 2.0 5 votes vote down vote up
private static void createSimpleClone(ClassNode cNode, List<FieldNode> fieldNodes, List<String> excludes) {
    if (cNode.getDeclaredConstructors().isEmpty()) {
        // add no-arg constructor
        addGeneratedConstructor(cNode, ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, block(EmptyStatement.INSTANCE));
    }
    addSimpleCloneHelperMethod(cNode, fieldNodes, excludes);
    final Expression result = localVarX("_result");
    ClassNode[] exceptions = {make(CloneNotSupportedException.class)};
    addGeneratedMethod(cNode, "clone", ACC_PUBLIC, GenericsUtils.nonGeneric(cNode), Parameter.EMPTY_ARRAY, exceptions, block(
        declS(result, ctorX(cNode)),
        stmt(callThisX("cloneOrCopyMembers", args(result))),
        returnS(result)));
}
 
Example 4
Source Project: groovy   Source File: AutoCloneASTTransformation.java    License: Apache License 2.0 5 votes vote down vote up
private static void addSimpleCloneHelperMethod(ClassNode cNode, List<FieldNode> fieldNodes, List<String> excludes) {
    Parameter methodParam = new Parameter(GenericsUtils.nonGeneric(cNode), "other");
    final Expression other = varX(methodParam);
    boolean hasParent = cNode.getSuperClass() != ClassHelper.OBJECT_TYPE;
    BlockStatement methodBody = new BlockStatement();
    if (hasParent) {
        methodBody.addStatement(stmt(callSuperX("cloneOrCopyMembers", args(other))));
    }
    for (FieldNode fieldNode : fieldNodes) {
        String name = fieldNode.getName();
        if (excludes != null && excludes.contains(name)) continue;
        ClassNode fieldType = fieldNode.getType();
        Expression direct = propX(varX("this"), name);
        Expression to = propX(other, name);
        Statement assignDirect = assignS(to, direct);
        Statement assignCloned = assignS(to, castX(fieldType, callCloneDirectX(direct)));
        Statement assignClonedDynamic = assignS(to, castX(fieldType, callCloneDynamicX(direct)));
        if (isCloneableType(fieldType)) {
            methodBody.addStatement(assignCloned);
        } else if (!possiblyCloneable(fieldType)) {
            methodBody.addStatement(assignDirect);
        } else {
            methodBody.addStatement(ifElseS(isInstanceOfX(direct, CLONEABLE_TYPE), assignClonedDynamic, assignDirect));
        }
    }
    ClassNode[] exceptions = {make(CloneNotSupportedException.class)};
    addGeneratedMethod(cNode, "cloneOrCopyMembers", ACC_PROTECTED, ClassHelper.VOID_TYPE, params(methodParam), exceptions, methodBody);
}
 
Example 5
Source Project: groovy   Source File: AutoCloneASTTransformation.java    License: Apache License 2.0 5 votes vote down vote up
private static void createClone(ClassNode cNode, List<FieldNode> fieldNodes, List<String> excludes) {
    final BlockStatement body = new BlockStatement();

    // def _result = super.clone() as cNode
    final Expression result = localVarX("_result");
    body.addStatement(declS(result, castX(cNode, callSuperX("clone"))));

    for (FieldNode fieldNode : fieldNodes) {
        if (excludes != null && excludes.contains(fieldNode.getName())) continue;
        ClassNode fieldType = fieldNode.getType();
        Expression fieldExpr = varX(fieldNode);
        Expression to = propX(result, fieldNode.getName());
        Statement doClone = assignS(to, castX(fieldType, callCloneDirectX(fieldExpr)));
        Statement doCloneDynamic = assignS(to, castX(fieldType, callCloneDynamicX(fieldExpr)));
        if (isCloneableType(fieldType)) {
            body.addStatement(doClone);
        } else if (possiblyCloneable(fieldType)) {
            body.addStatement(ifS(isInstanceOfX(fieldExpr, CLONEABLE_TYPE), doCloneDynamic));
        }
    }

    // return _result
    body.addStatement(returnS(result));

    ClassNode[] exceptions = {make(CloneNotSupportedException.class)};
    addGeneratedMethod(cNode, "clone", ACC_PUBLIC, GenericsUtils.nonGeneric(cNode), Parameter.EMPTY_ARRAY, exceptions, body);
}
 
Example 6
Source Project: groovy   Source File: DelegateASTTransformation.java    License: Apache License 2.0 5 votes vote down vote up
private static void addSetterIfNeeded(DelegateDescription delegate, PropertyNode prop, String name, boolean allNames) {
    String setterName = "set" + Verifier.capitalize(name);
    if ((prop.getModifiers() & ACC_FINAL) == 0
            && delegate.owner.getSetterMethod(setterName) == null && delegate.owner.getProperty(name) == null
            && !shouldSkipPropertyMethod(name, setterName, delegate.excludes, delegate.includes, allNames)) {
        addGeneratedMethod(delegate.owner, setterName,
                ACC_PUBLIC,
                ClassHelper.VOID_TYPE,
                params(new Parameter(GenericsUtils.nonGeneric(prop.getType()), "value")),
                null,
                assignS(propX(delegate.getOp, name), varX("value"))
        );
    }
}
 
Example 7
Source Project: groovy   Source File: DelegateASTTransformation.java    License: Apache License 2.0 5 votes vote down vote up
private static void addGetterIfNeeded(DelegateDescription delegate, PropertyNode prop, String name, boolean allNames) {
    boolean isPrimBool = prop.getOriginType().equals(ClassHelper.boolean_TYPE);
    // do a little bit of pre-work since Groovy compiler hasn't added property accessors yet
    boolean willHaveGetAccessor = true;
    boolean willHaveIsAccessor = isPrimBool;
    String suffix = Verifier.capitalize(name);
    if (isPrimBool) {
        ClassNode cNode = prop.getDeclaringClass();
        if (cNode.getGetterMethod("is" + suffix) != null && cNode.getGetterMethod("get" + suffix) == null)
            willHaveGetAccessor = false;
        if (cNode.getGetterMethod("get" + suffix) != null && cNode.getGetterMethod("is" + suffix) == null)
            willHaveIsAccessor = false;
    }
    Reference<Boolean> ownerWillHaveGetAccessor = new Reference<Boolean>();
    Reference<Boolean> ownerWillHaveIsAccessor = new Reference<Boolean>();
    extractAccessorInfo(delegate.owner, name, ownerWillHaveGetAccessor, ownerWillHaveIsAccessor);

    for (String prefix : new String[]{"get", "is"}) {
        String getterName = prefix + suffix;
        if ((prefix.equals("get") && willHaveGetAccessor && !ownerWillHaveGetAccessor.get()
                || prefix.equals("is") && willHaveIsAccessor && !ownerWillHaveIsAccessor.get())
                && !shouldSkipPropertyMethod(name, getterName, delegate.excludes, delegate.includes, allNames)) {
            addGeneratedMethod(delegate.owner, getterName,
                    ACC_PUBLIC,
                    GenericsUtils.nonGeneric(prop.getType()),
                    Parameter.EMPTY_ARRAY,
                    null,
                    returnS(propX(delegate.getOp, name)));
        }
    }
}
 
Example 8
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Checks if a class node is assignable to another. This is used for example in
 * assignment checks where you want to verify that the assignment is valid.
 *
 * @return true if the class node is assignable to the other class node, false otherwise
 */
static boolean isAssignableTo(ClassNode type, ClassNode toBeAssignedTo) {
    if (type == toBeAssignedTo || type == UNKNOWN_PARAMETER_TYPE) return true;
    if (isPrimitiveType(type)) type = getWrapper(type);
    if (isPrimitiveType(toBeAssignedTo)) toBeAssignedTo = getWrapper(toBeAssignedTo);
    if (NUMBER_TYPES.containsKey(type.redirect()) && NUMBER_TYPES.containsKey(toBeAssignedTo.redirect())) {
        return NUMBER_TYPES.get(type.redirect()) <= NUMBER_TYPES.get(toBeAssignedTo.redirect());
    }
    if (type.isArray() && toBeAssignedTo.isArray()) {
        return isAssignableTo(type.getComponentType(), toBeAssignedTo.getComponentType());
    }
    if (type.isDerivedFrom(GSTRING_TYPE) && STRING_TYPE.equals(toBeAssignedTo)) {
        return true;
    }
    if (STRING_TYPE.equals(type) && toBeAssignedTo.isDerivedFrom(GSTRING_TYPE)) {
        return true;
    }
    if (implementsInterfaceOrIsSubclassOf(type, toBeAssignedTo)) {
        if (toBeAssignedTo.getGenericsTypes() != null) {
            // perform additional check on generics
            // ? extends toBeAssignedTo
            GenericsType gt = GenericsUtils.buildWildcardType(toBeAssignedTo);
            return gt.isCompatibleWith(type);
        }
        return true;
    }
    // SAM check
    if (type.isDerivedFrom(CLOSURE_TYPE) && isSAMType(toBeAssignedTo)) {
        return true;
    }

    return false;
}
 
Example 9
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Given a receiver and a method node, parameterize the method arguments using
 * available generic type information.
 *
 * @param receiver the class
 * @param m        the method
 * @return the parameterized arguments
 */
public static Parameter[] parameterizeArguments(final ClassNode receiver, final MethodNode m) {
    Map<GenericsTypeName, GenericsType> genericFromReceiver = GenericsUtils.extractPlaceholders(receiver);
    Map<GenericsTypeName, GenericsType> contextPlaceholders = extractGenericsParameterMapOfThis(m);
    Parameter[] methodParameters = m.getParameters();
    Parameter[] params = new Parameter[methodParameters.length];
    for (int i = 0, n = methodParameters.length; i < n; i += 1) {
        Parameter methodParameter = methodParameters[i];
        ClassNode paramType = methodParameter.getType();
        params[i] = buildParameter(genericFromReceiver, contextPlaceholders, methodParameter, paramType);
    }
    return params;
}
 
Example 10
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Checks that the parameterized generics of an argument are compatible with the generics of the parameter.
 *
 * @param parameterType the parameter type of a method
 * @param argumentType  the type of the argument passed to the method
 */
protected static boolean typeCheckMethodArgumentWithGenerics(final ClassNode parameterType, final ClassNode argumentType, final boolean lastArg) {
    if (UNKNOWN_PARAMETER_TYPE == argumentType) {
        // called with null
        return !isPrimitiveType(parameterType);
    }
    if (!isAssignableTo(argumentType, parameterType) && !lastArg) {
        // incompatible assignment
        return false;
    }
    if (!isAssignableTo(argumentType, parameterType) && lastArg) {
        if (parameterType.isArray()) {
            if (!isAssignableTo(argumentType, parameterType.getComponentType())) {
                return false;
            }
        } else {
            return false;
        }
    }
    if (parameterType.isUsingGenerics() && argumentType.isUsingGenerics()) {
        GenericsType gt = GenericsUtils.buildWildcardType(parameterType);
        if (!gt.isCompatibleWith(argumentType)) {
            boolean samCoercion = isSAMType(parameterType) && argumentType.equals(CLOSURE_TYPE);
            if (!samCoercion) return false;
        }
    } else if (parameterType.isArray() && argumentType.isArray()) {
        // verify component type
        return typeCheckMethodArgumentWithGenerics(parameterType.getComponentType(), argumentType.getComponentType(), lastArg);
    } else if (lastArg && parameterType.isArray()) {
        // verify component type, but if we reach that point, the only possibility is that the argument is
        // the last one of the call, so we're in the cast of a vargs call
        // (otherwise, we face a type checker bug)
        return typeCheckMethodArgumentWithGenerics(parameterType.getComponentType(), argumentType, lastArg);
    }
    return true;
}
 
Example 11
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 5 votes vote down vote up
static Map<GenericsTypeName, GenericsType> applyGenericsContextToParameterClass(final Map<GenericsTypeName, GenericsType> spec, final ClassNode parameterUsage) {
    GenericsType[] gts = parameterUsage.getGenericsTypes();
    if (gts == null) return Collections.emptyMap();

    GenericsType[] newGTs = applyGenericsContext(spec, gts);
    ClassNode newTarget = parameterUsage.redirect().getPlainNodeReference();
    newTarget.setGenericsTypes(newGTs);
    return GenericsUtils.extractPlaceholders(newTarget);
}
 
Example 12
Source Project: groovy   Source File: Traits.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Collects all interfaces of a class node, but reverses the order of the declaration of direct interfaces
 * of this class node. This is used to make sure a trait implementing A,B where both A and B have the same
 * method will take the method from B (latest), aligning the behavior with categories.
 * @param cNode a class node
 * @param interfaces ordered set of interfaces
 */
public static LinkedHashSet<ClassNode> collectAllInterfacesReverseOrder(ClassNode cNode, LinkedHashSet<ClassNode> interfaces) {
    if (cNode.isInterface())
        interfaces.add(cNode);

    ClassNode[] directInterfaces = cNode.getInterfaces();
    for (int i = directInterfaces.length-1; i >=0 ; i--) {
        final ClassNode anInterface = directInterfaces[i];
        interfaces.add(GenericsUtils.parameterizeType(cNode,anInterface));
        collectAllInterfacesReverseOrder(anInterface, interfaces);
    }
    return interfaces;
}
 
Example 13
private static void createReadExternal(ClassNode cNode, List<String> excludes, List<FieldNode> list) {
    final BlockStatement body = new BlockStatement();
    Parameter oin = param(OBJECTINPUT_TYPE, "oin");
    for (FieldNode fNode : list) {
        if (excludes != null && excludes.contains(fNode.getName())) continue;
        if ((fNode.getModifiers() & ACC_TRANSIENT) != 0) continue;
        String suffix = suffixForField(fNode);
        MethodCallExpression readObject = callX(varX(oin), "read" + suffix);
        readObject.setImplicitThis(false);
        body.addStatement(assignS(varX(fNode), suffix.equals("Object") ? castX(GenericsUtils.nonGeneric(fNode.getType()), readObject) : readObject));
    }
    addGeneratedMethod(cNode, "readExternal", ACC_PUBLIC, ClassHelper.VOID_TYPE, params(oin), ClassNode.EMPTY_ARRAY, body);
}
 
Example 14
Source Project: groovy   Source File: BinaryExpressionHelper.java    License: Apache License 2.0 5 votes vote down vote up
private VariableSlotLoader loadWithSubscript(final Expression expression) {
    AsmClassGenerator acg = controller.getAcg();
    // if we have a BinaryExpression, check if it is with subscription
    if (expression instanceof BinaryExpression) {
        BinaryExpression bexp = (BinaryExpression) expression;
        if (bexp.getOperation().getType() == LEFT_SQUARE_BRACKET) {
            // right expression is the subscript expression
            // we store the result of the subscription on the stack
            Expression subscript = bexp.getRightExpression();
            subscript.visit(acg);
            OperandStack operandStack = controller.getOperandStack();
            ClassNode subscriptType = operandStack.getTopOperand();
            if (subscriptType.isGenericsPlaceHolder() || GenericsUtils.hasPlaceHolders(subscriptType)) {
                subscriptType = controller.getTypeChooser().resolveType(bexp, controller.getClassNode());
            }
            int id = controller.getCompileStack().defineTemporaryVariable("$subscript", subscriptType, true);
            VariableSlotLoader subscriptExpression = new VariableSlotLoader(subscriptType, id, operandStack);
            BinaryExpression rewrite = binX(bexp.getLeftExpression(), bexp.getOperation(), subscriptExpression);
            rewrite.copyNodeMetaData(bexp);
            rewrite.setSourcePosition(bexp);
            rewrite.visit(acg);
            return subscriptExpression;
        }
    }

    // normal loading of expression
    expression.visit(acg);
    return null;
}
 
Example 15
Source Project: netbeans   Source File: MethodInference.java    License: Apache License 2.0 4 votes vote down vote up
@CheckForNull
private static ClassNode findReturnTypeFor(
        @NonNull ClassNode callerType, 
        @NonNull String methodName,
        @NonNull Expression arguments,
        @NonNull AstPath path,
        @NonNull boolean isStatic,
        @NonNull BaseDocument baseDocument,
        @NonNull int offset
        ) {

    List<ClassNode> paramTypes = new ArrayList<>();
    if (arguments instanceof ArgumentListExpression) {
        ArgumentListExpression argExpression = (ArgumentListExpression) arguments;
        for (Expression e : argExpression.getExpressions()) {
            if (e instanceof VariableExpression) {
                ModuleNode moduleNode = (ModuleNode) path.root();
                int newOffset = ASTUtils.getOffset(baseDocument, e.getLineNumber(), e.getColumnNumber());
                AstPath newPath = new AstPath(moduleNode, newOffset, baseDocument);
                TypeInferenceVisitor tiv = new TypeInferenceVisitor(moduleNode.getContext(), newPath, baseDocument, newOffset);
                tiv.collect();
                ClassNode guessedType = tiv.getGuessedType();
                if (null == guessedType) {
                    System.out.println("Bad guessed type");
                } else {
                    paramTypes.add(tiv.getGuessedType());
                }
            } else if(e instanceof ConstantExpression) {
                paramTypes.add(((ConstantExpression)e).getType());
            } else if (e instanceof MethodCallExpression) {
                paramTypes.add(findCallerType(e, path, baseDocument, offset));
            } else if (e instanceof BinaryExpression) {
                BinaryExpression binExpression = (BinaryExpression) e;
                paramTypes.add(binExpression.getType());
            } else if (e instanceof ClassExpression) {
                ClassExpression classExpression = (ClassExpression) e;
                // This should be Class<classExpression.getType()>
                paramTypes.add(GenericsUtils.makeClassSafeWithGenerics(Class.class, classExpression.getType()));
            } else {
                System.out.println(e.getClass());
            }
        }
    }

    MethodNode possibleMethod = tryFindPossibleMethod(callerType, methodName, paramTypes, isStatic);
    if (possibleMethod != null) {
        return possibleMethod.getReturnType();
    }
    return null;
}
 
Example 16
Source Project: groovy   Source File: AutoCloneASTTransformation.java    License: Apache License 2.0 4 votes vote down vote up
private static void createCloneCopyConstructor(ClassNode cNode, List<FieldNode> list, List<String> excludes) {
    if (cNode.getDeclaredConstructors().isEmpty()) {
        // add no-arg constructor
        BlockStatement noArgBody = new BlockStatement();
        noArgBody.addStatement(EmptyStatement.INSTANCE);
        addGeneratedConstructor(cNode, ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, noArgBody);
    }
    boolean hasThisCons = false;
    for (ConstructorNode consNode : cNode.getDeclaredConstructors()) {
        Parameter[] parameters = consNode.getParameters();
        if (parameters.length == 1 && parameters[0].getType().equals(cNode)) {
            hasThisCons = true;
        }
    }
    if (!hasThisCons) {
        BlockStatement initBody = new BlockStatement();
        Parameter initParam = param(GenericsUtils.nonGeneric(cNode), "other");
        final Expression other = varX(initParam);
        boolean hasParent = cNode.getSuperClass() != ClassHelper.OBJECT_TYPE;
        if (hasParent) {
            initBody.addStatement(stmt(ctorX(ClassNode.SUPER, other)));
        }
        for (FieldNode fieldNode : list) {
            String name = fieldNode.getName();
            if (excludes != null && excludes.contains(name)) continue;
            ClassNode fieldType = fieldNode.getType();
            Expression direct = propX(other, name);
            Expression to = propX(varX("this"), name);
            Statement assignDirect = assignS(to, direct);
            Statement assignCloned = assignS(to, castX(fieldType, callCloneDirectX(direct)));
            Statement assignClonedDynamic = assignS(to, castX(fieldType, callCloneDynamicX(direct)));
            if (isCloneableType(fieldType)) {
                initBody.addStatement(assignCloned);
            } else if (!possiblyCloneable(fieldType)) {
                initBody.addStatement(assignDirect);
            } else {
                initBody.addStatement(ifElseS(isInstanceOfX(direct, CLONEABLE_TYPE), assignClonedDynamic, assignDirect));
            }
        }
        addGeneratedConstructor(cNode, ACC_PROTECTED, params(initParam), ClassNode.EMPTY_ARRAY, initBody);
    }
    ClassNode[] exceptions = {make(CloneNotSupportedException.class)};
    addGeneratedMethod(cNode, "clone", ACC_PUBLIC, GenericsUtils.nonGeneric(cNode), Parameter.EMPTY_ARRAY, exceptions, block(stmt(ctorX(cNode, args(varX("this"))))));
}
 
Example 17
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 4 votes vote down vote up
/**
 * Given a list of candidate methods, returns the one which best matches the argument types
 *
 * @param receiver
 * @param methods  candidate methods
 * @param argumentTypes     argument types
 * @return the list of methods which best matches the argument types. It is still possible that multiple
 * methods match the argument types.
 */
public static List<MethodNode> chooseBestMethod(final ClassNode receiver, final Collection<MethodNode> methods, final ClassNode... argumentTypes) {
    if (methods.isEmpty()) return Collections.emptyList();
    if (isUsingUncheckedGenerics(receiver)) {
        ClassNode raw = makeRawType(receiver);
        return chooseBestMethod(raw, methods, argumentTypes);
    }
    List<MethodNode> bestChoices = new LinkedList<>();
    int bestDist = Integer.MAX_VALUE;
    Collection<MethodNode> choicesLeft = removeCovariantsAndInterfaceEquivalents(methods);
    for (MethodNode candidateNode : choicesLeft) {
        ClassNode declaringClassForDistance = candidateNode.getDeclaringClass();
        ClassNode actualReceiverForDistance = receiver != null ? receiver : candidateNode.getDeclaringClass();
        MethodNode safeNode = candidateNode;
        ClassNode[] safeArgs = argumentTypes;
        boolean isExtensionMethodNode = candidateNode instanceof ExtensionMethodNode;
        if (isExtensionMethodNode) {
            safeArgs = new ClassNode[argumentTypes.length + 1];
            System.arraycopy(argumentTypes, 0, safeArgs, 1, argumentTypes.length);
            safeArgs[0] = receiver;
            safeNode = ((ExtensionMethodNode) candidateNode).getExtensionMethodNode();
        }

        // todo : corner case
        /*
            class B extends A {}

            Animal foo(A o) {...}
            Person foo(B i){...}

            B  a = new B()
            Person p = foo(b)
         */

        Map<GenericsType, GenericsType> declaringAndActualGenericsTypeMap = GenericsUtils.makeDeclaringAndActualGenericsTypeMap(declaringClassForDistance, actualReceiverForDistance);
        Parameter[] params = makeRawTypes(safeNode.getParameters(), declaringAndActualGenericsTypeMap);
        int dist = measureParametersAndArgumentsDistance(params, safeArgs);
        if (dist >= 0) {
            dist += getClassDistance(declaringClassForDistance, actualReceiverForDistance);
            dist += getExtensionDistance(isExtensionMethodNode);
            if (dist < bestDist) {
                bestChoices.clear();
                bestChoices.add(candidateNode);
                bestDist = dist;
            } else if (dist == bestDist) {
                bestChoices.add(candidateNode);
            }
        }
    }
    if (bestChoices.size() > 1) {
        // GROOVY-6849: prefer extension methods in case of ambiguity
        List<MethodNode> onlyExtensionMethods = new LinkedList<>();
        for (MethodNode choice : bestChoices) {
            if (choice instanceof ExtensionMethodNode) {
                onlyExtensionMethods.add(choice);
            }
        }
        if (onlyExtensionMethods.size() == 1) {
            return onlyExtensionMethods;
        }
    }
    return bestChoices;
}
 
Example 18
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 4 votes vote down vote up
static void addMethodLevelDeclaredGenerics(final MethodNode method, final Map<GenericsTypeName, GenericsType> resolvedPlaceholders) {
    ClassNode dummy = OBJECT_TYPE.getPlainNodeReference();
    dummy.setGenericsTypes(method.getGenericsTypes());
    GenericsUtils.extractPlaceholders(dummy, resolvedPlaceholders);
}
 
Example 19
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 4 votes vote down vote up
private static boolean typeCheckMethodsWithGenerics(final ClassNode receiver, final ClassNode[] argumentTypes, final MethodNode candidateMethod, final boolean isExtensionMethod) {
    boolean failure = false;

    // correct receiver for inner class
    // we assume the receiver is an instance of the declaring class of the
    // candidate method, but findMethod returns also outer class methods
    // for that receiver. For now we skip receiver based checks in that case
    // TODO: correct generics for when receiver is to be skipped
    boolean skipBecauseOfInnerClassNotReceiver = !implementsInterfaceOrIsSubclassOf(receiver, candidateMethod.getDeclaringClass());

    Parameter[] parameters = candidateMethod.getParameters();
    Map<GenericsTypeName, GenericsType> classGTs;
    if (skipBecauseOfInnerClassNotReceiver) {
        classGTs = Collections.emptyMap();
    } else {
        classGTs = GenericsUtils.extractPlaceholders(receiver);
    }
    if (parameters.length > argumentTypes.length || parameters.length == 0) {
        // this is a limitation that must be removed in a future version
        // we cannot check generic type arguments if there are default parameters!
        return true;
    }

    // we have here different generics contexts we have to deal with.
    // There is firstly the context given through the class, and the method.
    // The method context may hide generics given through the class, but use
    // the non-hidden ones.
    Map<GenericsTypeName, GenericsType> resolvedMethodGenerics = new HashMap<>();
    if (!skipBecauseOfInnerClassNotReceiver) {
        addMethodLevelDeclaredGenerics(candidateMethod, resolvedMethodGenerics);
    }
    // first remove hidden generics
    for (GenericsTypeName key : resolvedMethodGenerics.keySet()) {
        classGTs.remove(key);
    }
    // then use the remaining information to refine the given generics
    applyGenericsConnections(classGTs, resolvedMethodGenerics);
    // and then start our checks with the receiver
    if (!skipBecauseOfInnerClassNotReceiver) {
        failure = failure || inferenceCheck(Collections.emptySet(), resolvedMethodGenerics, candidateMethod.getDeclaringClass(), receiver, false);
    }
    // the outside context parts till now define placeholder we are not allowed to
    // generalize, thus we save that for later use...
    // extension methods are special, since they set the receiver as
    // first parameter. While we normally allow generalization for the first
    // parameter, in case of an extension method we must not.
    Set<GenericsTypeName> fixedGenericsPlaceHolders = extractResolvedPlaceHolders(resolvedMethodGenerics);

    for (int i = 0, n = argumentTypes.length; i < n; i += 1) {
        int pindex = min(i, parameters.length - 1);
        ClassNode wrappedArgument = argumentTypes[i];
        ClassNode type = parameters[pindex].getOriginType();

        failure = failure || inferenceCheck(fixedGenericsPlaceHolders, resolvedMethodGenerics, type, wrappedArgument, i >= parameters.length - 1);

        // set real fixed generics for extension methods
        if (isExtensionMethod && i == 0)
            fixedGenericsPlaceHolders = extractResolvedPlaceHolders(resolvedMethodGenerics);
    }
    return !failure;
}
 
Example 20
Source Project: groovy   Source File: StaticTypeCheckingSupport.java    License: Apache License 2.0 4 votes vote down vote up
public static ClassNode getCorrectedClassNode(final ClassNode type, final ClassNode superClass, final boolean handlingGenerics) {
    if (handlingGenerics && missesGenericsTypes(type)) return superClass.getPlainNodeReference();
    return GenericsUtils.correctToGenericsSpecRecurse(GenericsUtils.createGenericsSpec(type), superClass);
}
 
Example 21
Source Project: groovy   Source File: EqualsAndHashCodeASTTransformation.java    License: Apache License 2.0 4 votes vote down vote up
public static void createEquals(ClassNode cNode, boolean includeFields, boolean callSuper, boolean useCanEqual, List<String> excludes, List<String> includes, boolean allNames, boolean allProperties) {
    if (useCanEqual) createCanEqual(cNode);
    // make a public method if none exists otherwise try a private method with leading underscore
    boolean hasExistingEquals = hasDeclaredMethod(cNode, "equals", 1);
    if (hasExistingEquals && hasDeclaredMethod(cNode, "_equals", 1)) return;

    final BlockStatement body = new BlockStatement();
    VariableExpression other = varX("other");

    // some short circuit cases for efficiency
    body.addStatement(ifS(equalsNullX(other), returnS(constX(Boolean.FALSE, true))));
    body.addStatement(ifS(sameX(varX("this"), other), returnS(constX(Boolean.TRUE, true))));

    if (useCanEqual) {
        body.addStatement(ifS(notX(isInstanceOfX(other, GenericsUtils.nonGeneric(cNode))), returnS(constX(Boolean.FALSE,true))));
    } else {
        body.addStatement(ifS(notX(hasClassX(other, GenericsUtils.nonGeneric(cNode))), returnS(constX(Boolean.FALSE,true))));
    }

    VariableExpression otherTyped = localVarX("otherTyped", GenericsUtils.nonGeneric(cNode));
    CastExpression castExpression = new CastExpression(GenericsUtils.nonGeneric(cNode), other);
    castExpression.setStrict(true);
    body.addStatement(declS(otherTyped, castExpression));

    if (useCanEqual) {
        body.addStatement(ifS(notX(callX(otherTyped, "canEqual", varX("this"))), returnS(constX(Boolean.FALSE,true))));
    }

    final Set<String> names = new HashSet<String>();
    final List<PropertyNode> pList = getAllProperties(names, cNode, true, includeFields, allProperties, false, false, false);
    for (PropertyNode pNode : pList) {
        if (shouldSkipUndefinedAware(pNode.getName(), excludes, includes, allNames)) continue;
        boolean canBeSelf = StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(
                pNode.getOriginType(), cNode
        );
        if (!canBeSelf) {
            body.addStatement(ifS(notX(hasEqualPropertyX(otherTyped.getOriginType(), pNode, otherTyped)), returnS(constX(Boolean.FALSE, true))));
        } else {
            body.addStatement(
                    ifS(notX(hasSamePropertyX(pNode, otherTyped)),
                            ifElseS(differentSelfRecursivePropertyX(pNode, otherTyped),
                                    returnS(constX(Boolean.FALSE, true)),
                                    ifS(notX(bothSelfRecursivePropertyX(pNode, otherTyped)),
                                            ifS(notX(hasEqualPropertyX(otherTyped.getOriginType(), pNode, otherTyped)), returnS(constX(Boolean.FALSE, true))))
                            )
                    )
            );
        }
    }
    List<FieldNode> fList = new ArrayList<FieldNode>();
    if (includeFields) {
        fList.addAll(getInstanceNonPropertyFields(cNode));
    }
    for (FieldNode fNode : fList) {
        if (shouldSkipUndefinedAware(fNode.getName(), excludes, includes, allNames)) continue;
        body.addStatement(
                ifS(notX(hasSameFieldX(fNode, otherTyped)),
                        ifElseS(differentSelfRecursiveFieldX(fNode, otherTyped),
                                returnS(constX(Boolean.FALSE,true)),
                                ifS(notX(bothSelfRecursiveFieldX(fNode, otherTyped)),
                                        ifS(notX(hasEqualFieldX(fNode, otherTyped)), returnS(constX(Boolean.FALSE,true)))))
                ));
    }
    if (callSuper) {
        body.addStatement(ifS(
                notX(isTrueX(callSuperX("equals", other))),
                returnS(constX(Boolean.FALSE,true))
        ));
    }

    // default
    body.addStatement(returnS(constX(Boolean.TRUE,true)));

    MethodNode equal = addGeneratedMethod(cNode,
            hasExistingEquals ? "_equals" : "equals",
            hasExistingEquals ? ACC_PRIVATE : ACC_PUBLIC,
            ClassHelper.boolean_TYPE,
            params(param(OBJECT_TYPE, other.getName())),
            ClassNode.EMPTY_ARRAY,
            body);
    // don't null check this: prefer false to IllegalArgumentException
    NullCheckASTTransformation.markAsProcessed(equal);
}
 
Example 22
Source Project: groovy   Source File: FromString.java    License: Apache License 2.0 2 votes vote down vote up
/**
 * Parses a string representing a type, that must be aligned with the current context.
 * For example, <i>"List&lt;T&gt;"</i> must be converted into the appropriate ClassNode
 * for which <i>T</i> matches the appropriate placeholder.
 *
 *
 * @param option a string representing a type
 * @param sourceUnit the source unit (of the file being compiled)
 * @param compilationUnit the compilation unit (of the file being compiled)
 * @param mn the method node
 * @param usage
 * @return a class node if it could be parsed and resolved, null otherwise
 */
private static ClassNode[] parseOption(final String option, final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage) {
    return GenericsUtils.parseClassNodesFromString(option, sourceUnit, compilationUnit, mn, usage);
}