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;
}
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);
}
}
}
}
}
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();
}
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;
}
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;
}
Aggregations