Search in sources :

Example 96 with GenericsType

use of org.codehaus.groovy.ast.GenericsType in project groovy-core by groovy.

the class StaticTypeCheckingVisitor method extractPlaceHolders.

private static Map<String, GenericsType> extractPlaceHolders(MethodNode method, ClassNode receiver, ClassNode declaringClass) {
    if (declaringClass.equals(OBJECT_TYPE)) {
        Map<String, GenericsType> resolvedPlaceholders = new HashMap<String, GenericsType>();
        if (method != null)
            addMethodLevelDeclaredGenerics(method, resolvedPlaceholders);
        return resolvedPlaceholders;
    }
    Map<String, GenericsType> resolvedPlaceholders = null;
    if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
        receiver = getWrapper(receiver);
    }
    final List<ClassNode> queue;
    if (receiver instanceof UnionTypeClassNode) {
        queue = Arrays.asList(((UnionTypeClassNode) receiver).getDelegates());
    } else {
        queue = Collections.singletonList(receiver);
    }
    for (ClassNode item : queue) {
        ClassNode current = item;
        while (current != null) {
            boolean continueLoop = true;
            //extract the place holders
            Map<String, GenericsType> currentPlaceHolders = new HashMap<String, GenericsType>();
            if (isGenericsPlaceHolderOrArrayOf(declaringClass) || declaringClass.equals(current)) {
                extractGenericsConnections(currentPlaceHolders, current, declaringClass);
                if (method != null)
                    addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
                continueLoop = false;
            } else {
                GenericsUtils.extractPlaceholders(current, currentPlaceHolders);
            }
            if (resolvedPlaceholders != null) {
                // merge maps
                Set<Map.Entry<String, GenericsType>> entries = currentPlaceHolders.entrySet();
                for (Map.Entry<String, GenericsType> entry : entries) {
                    GenericsType gt = entry.getValue();
                    if (!gt.isPlaceholder())
                        continue;
                    GenericsType referenced = resolvedPlaceholders.get(gt.getName());
                    if (referenced == null)
                        continue;
                    entry.setValue(referenced);
                }
            }
            resolvedPlaceholders = currentPlaceHolders;
            // we are done if we are now in the declaring class
            if (!continueLoop)
                break;
            current = getNextSuperClass(current, declaringClass);
            if (current == null && CLASS_Type.equals(declaringClass)) {
                // this can happen if the receiver is Class<Foo>, then
                // the actual receiver is Foo and declaringClass is Class
                current = declaringClass;
            }
        }
    }
    if (resolvedPlaceholders == null) {
        String descriptor = "<>";
        if (method != null)
            descriptor = method.getTypeDescriptor();
        throw new GroovyBugError("Declaring class for method call to '" + descriptor + "' declared in " + declaringClass.getName() + " was not matched with found receiver " + receiver.getName() + "." + " This should not have happened!");
    }
    return resolvedPlaceholders;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedHashMap(java.util.LinkedHashMap) ListHashMap(org.codehaus.groovy.util.ListHashMap) HashMap(java.util.HashMap) GroovyBugError(org.codehaus.groovy.GroovyBugError) GenericsType(org.codehaus.groovy.ast.GenericsType) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) ListHashMap(org.codehaus.groovy.util.ListHashMap) HashMap(java.util.HashMap)

Example 97 with GenericsType

use of org.codehaus.groovy.ast.GenericsType in project groovy-core by groovy.

the class StaticTypeCheckingVisitor method checkClosureWithDelegatesTo.

private void checkClosureWithDelegatesTo(final ClassNode receiver, final MethodNode mn, final ArgumentListExpression arguments, final Parameter[] params, final Expression expression, final Parameter param) {
    List<AnnotationNode> annotations = param.getAnnotations(DELEGATES_TO);
    if (annotations != null && !annotations.isEmpty()) {
        for (AnnotationNode annotation : annotations) {
            // in theory, there can only be one annotation of that type
            Expression value = annotation.getMember("value");
            Expression strategy = annotation.getMember("strategy");
            Expression genericTypeIndex = annotation.getMember("genericTypeIndex");
            Expression type = annotation.getMember("type");
            Integer stInt = Closure.OWNER_FIRST;
            if (strategy != null) {
                stInt = (Integer) evaluateExpression(new CastExpression(ClassHelper.Integer_TYPE, strategy), typeCheckingContext.source.getConfiguration());
            }
            if (value instanceof ClassExpression && !value.getType().equals(DELEGATES_TO_TARGET)) {
                if (genericTypeIndex != null) {
                    addStaticTypeError("Cannot use @DelegatesTo(genericTypeIndex=" + genericTypeIndex.getText() + ") without @DelegatesTo.Target because generic argument types are not available at runtime", value);
                }
                // temporarily store the delegation strategy and the delegate type
                expression.putNodeMetaData(StaticTypesMarker.DELEGATION_METADATA, new DelegationMetadata(value.getType(), stInt, typeCheckingContext.delegationMetadata));
            } else if (type != null && !"".equals(type.getText()) && type instanceof ConstantExpression) {
                String typeString = type.getText();
                ClassNode[] resolved = GenericsUtils.parseClassNodesFromString(typeString, getSourceUnit(), typeCheckingContext.compilationUnit, mn, type);
                if (resolved != null) {
                    if (resolved.length == 1) {
                        resolved = resolveGenericsFromTypeHint(receiver, arguments, mn, resolved);
                        expression.putNodeMetaData(StaticTypesMarker.DELEGATION_METADATA, new DelegationMetadata(resolved[0], stInt, typeCheckingContext.delegationMetadata));
                    } else {
                        addStaticTypeError("Incorrect type hint found in method " + (mn), type);
                    }
                }
            } else {
                final List<Expression> expressions = arguments.getExpressions();
                final int expressionsSize = expressions.size();
                Expression parameter = annotation.getMember("target");
                String parameterName = parameter != null && parameter instanceof ConstantExpression ? parameter.getText() : "";
                // todo: handle vargs!
                for (int j = 0, paramsLength = params.length; j < paramsLength; j++) {
                    final Parameter methodParam = params[j];
                    List<AnnotationNode> targets = methodParam.getAnnotations(DELEGATES_TO_TARGET);
                    if (targets != null && targets.size() == 1) {
                        // @DelegatesTo.Target Obj foo
                        AnnotationNode targetAnnotation = targets.get(0);
                        Expression idMember = targetAnnotation.getMember("value");
                        String id = idMember != null && idMember instanceof ConstantExpression ? idMember.getText() : "";
                        if (id.equals(parameterName)) {
                            if (j < expressionsSize) {
                                Expression actualArgument = expressions.get(j);
                                ClassNode actualType = getType(actualArgument);
                                if (genericTypeIndex != null && genericTypeIndex instanceof ConstantExpression) {
                                    int gti = Integer.parseInt(genericTypeIndex.getText());
                                    // type annotated with @DelegatesTo.Target
                                    ClassNode paramType = methodParam.getType();
                                    GenericsType[] genericsTypes = paramType.getGenericsTypes();
                                    if (genericsTypes == null) {
                                        addStaticTypeError("Cannot use @DelegatesTo(genericTypeIndex=" + genericTypeIndex.getText() + ") with a type that doesn't use generics", methodParam);
                                    } else if (gti < 0 || gti >= genericsTypes.length) {
                                        addStaticTypeError("Index of generic type @DelegatesTo(genericTypeIndex=" + genericTypeIndex.getText() + ") " + (gti < 0 ? "lower" : "greater") + " than those of the selected type", methodParam);
                                    } else {
                                        ClassNode pType = GenericsUtils.parameterizeType(actualType, paramType);
                                        GenericsType[] pTypeGenerics = pType.getGenericsTypes();
                                        if (pTypeGenerics != null && pTypeGenerics.length > gti) {
                                            actualType = pTypeGenerics[gti].getType();
                                        } else {
                                            addStaticTypeError("Unable to map actual type [" + actualType.toString(false) + "] onto " + paramType.toString(false), methodParam);
                                        }
                                    }
                                }
                                expression.putNodeMetaData(StaticTypesMarker.DELEGATION_METADATA, new DelegationMetadata(actualType, stInt, typeCheckingContext.delegationMetadata));
                                break;
                            }
                        }
                    }
                }
                if (expression.getNodeMetaData(StaticTypesMarker.DELEGATION_METADATA) == null) {
                    addError("Not enough arguments found for a @DelegatesTo method call. Please check that you either use an explicit class or @DelegatesTo.Target with a correct id", arguments);
                }
            }
        }
    }
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) AnnotationNode(org.codehaus.groovy.ast.AnnotationNode) GenericsType(org.codehaus.groovy.ast.GenericsType) Parameter(org.codehaus.groovy.ast.Parameter) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList)

Example 98 with GenericsType

use of org.codehaus.groovy.ast.GenericsType in project groovy-core by groovy.

the class StaticTypeCheckingVisitor method toMethodGenericTypesString.

private String toMethodGenericTypesString(MethodNode node) {
    GenericsType[] genericsTypes = node.getGenericsTypes();
    if (genericsTypes == null)
        return "";
    StringBuilder sb = new StringBuilder("<");
    for (int i = 0; i < genericsTypes.length; i++) {
        final GenericsType genericsType = genericsTypes[i];
        sb.append(genericsType.toString());
        if (i < genericsTypes.length - 1) {
            sb.append(",");
        }
    }
    sb.append("> ");
    return sb.toString();
}
Also used : GenericsType(org.codehaus.groovy.ast.GenericsType) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint)

Example 99 with GenericsType

use of org.codehaus.groovy.ast.GenericsType in project groovy-core by groovy.

the class StaticTypeCheckingVisitor method inferSAMTypeGenericsInAssignment.

private ClassNode inferSAMTypeGenericsInAssignment(ClassNode samUsage, MethodNode sam, ClassNode closureType, ClosureExpression closureExpression) {
    // if the sam type or closure type do not provide generics information, 
    // we cannot infer anything, thus we simply return the provided samUsage
    GenericsType[] samGt = samUsage.getGenericsTypes();
    GenericsType[] closureGt = closureType.getGenericsTypes();
    if (samGt == null || closureGt == null)
        return samUsage;
    // extract the generics from the return type
    Map<String, GenericsType> connections = new HashMap<String, GenericsType>();
    extractGenericsConnections(connections, closureType, sam.getReturnType());
    // next we get the block parameter types and set the generics 
    // information just like before
    // TODO: add vargs handling
    Parameter[] closureParams = closureExpression.getParameters();
    Parameter[] methodParams = sam.getParameters();
    for (int i = 0; i < closureParams.length; i++) {
        ClassNode fromClosure = closureParams[i].getType();
        ClassNode fromMethod = methodParams[i].getType();
        extractGenericsConnections(connections, fromClosure, fromMethod);
    }
    ClassNode result = applyGenericsContext(connections, samUsage.redirect());
    return result;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) LinkedHashMap(java.util.LinkedHashMap) ListHashMap(org.codehaus.groovy.util.ListHashMap) HashMap(java.util.HashMap) GenericsType(org.codehaus.groovy.ast.GenericsType) Parameter(org.codehaus.groovy.ast.Parameter) ClosureSignatureHint(groovy.transform.stc.ClosureSignatureHint)

Example 100 with GenericsType

use of org.codehaus.groovy.ast.GenericsType in project groovy-core by groovy.

the class StaticTypeCheckingVisitor method getTypeForMapPropertyExpression.

private ClassNode getTypeForMapPropertyExpression(ClassNode testClass, ClassNode objectExpressionType, PropertyExpression pexp) {
    if (!implementsInterfaceOrIsSubclassOf(testClass, MAP_TYPE))
        return null;
    ClassNode intf;
    if (objectExpressionType.getGenericsTypes() != null) {
        intf = GenericsUtils.parameterizeType(objectExpressionType, MAP_TYPE.getPlainNodeReference());
    } else {
        intf = MAP_TYPE.getPlainNodeReference();
    }
    // 0 is the key, 1 is the value
    GenericsType[] types = intf.getGenericsTypes();
    if (types == null || types.length != 2)
        return OBJECT_TYPE;
    if (pexp.isSpreadSafe()) {
        // only "key" and "value" are allowed
        if ("key".equals(pexp.getPropertyAsString())) {
            ClassNode listKey = LIST_TYPE.getPlainNodeReference();
            listKey.setGenericsTypes(new GenericsType[] { types[0] });
            return listKey;
        } else if ("value".equals(pexp.getPropertyAsString())) {
            ClassNode listValue = LIST_TYPE.getPlainNodeReference();
            listValue.setGenericsTypes(new GenericsType[] { types[1] });
            return listValue;
        } else {
            addStaticTypeError("Spread operator on map only allows one of [key,value]", pexp);
        }
    } else {
        return types[1].getType();
    }
    return null;
}
Also used : LowestUpperBoundClassNode(org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode) ClassNode(org.codehaus.groovy.ast.ClassNode) InnerClassNode(org.codehaus.groovy.ast.InnerClassNode) GenericsType(org.codehaus.groovy.ast.GenericsType)

Aggregations

GenericsType (org.codehaus.groovy.ast.GenericsType)165 ClassNode (org.codehaus.groovy.ast.ClassNode)143 InnerClassNode (org.codehaus.groovy.ast.InnerClassNode)71 LowestUpperBoundClassNode (org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode)52 Parameter (org.codehaus.groovy.ast.Parameter)20 ClosureSignatureHint (groovy.transform.stc.ClosureSignatureHint)19 MethodNode (org.codehaus.groovy.ast.MethodNode)19 LinkedList (java.util.LinkedList)18 HashMap (java.util.HashMap)17 ArrayList (java.util.ArrayList)15 LinkedHashMap (java.util.LinkedHashMap)9 AST (antlr.collections.AST)8 AnnotationNode (org.codehaus.groovy.ast.AnnotationNode)8 ListHashMap (org.codehaus.groovy.util.ListHashMap)8 Map (java.util.Map)6 AtomicReference (java.util.concurrent.atomic.AtomicReference)6 EnumConstantClassNode (org.codehaus.groovy.ast.EnumConstantClassNode)6 FieldNode (org.codehaus.groovy.ast.FieldNode)6 GroovyBugError (org.codehaus.groovy.GroovyBugError)5 DynamicVariable (org.codehaus.groovy.ast.DynamicVariable)4