public GenericsType(ClassNode type, ClassNode[] upperBounds, ClassNode lowerBound) { this.type = type; this.name = type.isGenericsPlaceHolder() ? type.getUnresolvedName() : type.getName(); this.upperBounds = upperBounds; this.lowerBound = lowerBound; placeholder = type.isGenericsPlaceHolder(); resolved = false; }
private static ClassNode applyErasure(ClassNode genericType, ClassNode erasure) { if (genericType.isGenericsPlaceHolder()) { genericType.setRedirect(erasure); } return genericType; }
private String toString(Set<String> visited) { if (placeholder) visited.add(name); StringBuilder ret = new StringBuilder(wildcard ? "?" : ((type == null || placeholder) ? name : genericsBounds(type, visited))); if (upperBounds != null) { if (placeholder && upperBounds.length==1 && !upperBounds[0].isGenericsPlaceHolder() && upperBounds[0].getName().equals("java.lang.Object")) { // T extends Object should just be printed as T } else { ret.append(" extends "); for (int i = 0; i < upperBounds.length; i++) { ret.append(genericsBounds(upperBounds[i], visited)); if (i + 1 < upperBounds.length) ret.append(" & "); } } } else if (lowerBound != null) { ret.append(" super ").append(genericsBounds(lowerBound, visited)); } return ret.toString(); }
private static boolean equalIncludingGenerics(ClassNode orig, ClassNode copy) { if (orig == copy) return true; if (orig.isGenericsPlaceHolder() != copy.isGenericsPlaceHolder()) return false; if (!orig.equals(copy)) return false; GenericsType[] gt1 = orig.getGenericsTypes(); GenericsType[] gt2 = orig.getGenericsTypes(); if ((gt1 == null) ^ (gt2 == null)) return false; if (gt1 != gt2) { if (gt1.length != gt2.length) return false; for (int i = 0; i < gt1.length; i++) { if (!equalIncludingGenerics(gt1[i], gt2[i])) return false; } } return true; }
private static void writeGenericsBoundType(StringBuilder ret, ClassNode printType, boolean writeInterfaceMarker) { if (writeInterfaceMarker && printType.isInterface()) ret.append(":"); if (printType.isGenericsPlaceHolder() && printType.getGenericsTypes()!=null) { ret.append("T"); ret.append(printType.getGenericsTypes()[0].getName()); ret.append(";"); } else { ret.append(getTypeDescription(printType, false)); addSubTypes(ret, printType.getGenericsTypes(), "<", ">"); if (!ClassHelper.isPrimitiveType(printType)) ret.append(";"); } }
public static String getGenericsBounds(ClassNode type) { GenericsType[] genericsTypes = type.getGenericsTypes(); if (genericsTypes == null) return null; StringBuilder ret = new StringBuilder(100); if (type.isGenericsPlaceHolder()) { addSubTypes(ret, type.getGenericsTypes(), "", ""); } else { GenericsType gt = new GenericsType(type); writeGenericsBounds(ret, gt, false); } return ret.toString(); }
public static ClassNode makeClassSafe0(ClassNode type, GenericsType... genericTypes) { ClassNode plainNodeReference = newClass(type); if (genericTypes != null && genericTypes.length > 0) { plainNodeReference.setGenericsTypes(genericTypes); if (type.isGenericsPlaceHolder()) plainNodeReference.setGenericsPlaceHolder(true); } return plainNodeReference; }
private static boolean isGenericsPlaceHolderOrArrayOf(ClassNode cn) { if (cn.isArray()) return isGenericsPlaceHolderOrArrayOf(cn.getComponentType()); return cn.isGenericsPlaceHolder(); }
private void printType(PrintWriter out, ClassNode type) { if (type.isArray()) { printType(out, type.getComponentType()); out.print("[]"); } else if (java5 && type.isGenericsPlaceHolder()) { out.print(type.getGenericsTypes()[0].getName()); } else { printGenericsBounds(out, type, false); } }
private static boolean hasNonTrivialBounds(GenericsType gt) { ClassNode[] upperBounds = gt.getUpperBounds(); return gt.getLowerBound() != null || gt.isWildcard() || (upperBounds != null && ( upperBounds.length != 1 || upperBounds[0].isGenericsPlaceHolder() || !OBJECT_TYPE.equals(upperBounds[0]))); }
private static ClassNode infer(Variable variable) { ClassNode originType = variable.getOriginType(); if (originType.isGenericsPlaceHolder()) { GenericsType[] genericsTypes = originType.getGenericsTypes(); if (null != genericsTypes && genericsTypes.length > 0) { GenericsType gt = genericsTypes[0]; ClassNode[] upperBounds = gt.getUpperBounds(); if (null != upperBounds && upperBounds.length > 0) { return upperBounds[0]; } } } return variable.getOriginType(); } }
private static void extractGenericsConnections(Map<GenericsTypeName, GenericsType> connections, ClassNode[] usage, ClassNode[] declaration) { if (usage == null || declaration == null || declaration.length == 0) return; // both have generics for (int i = 0; i < usage.length; i++) { ClassNode ui = usage[i]; ClassNode di = declaration[i]; if (di.isGenericsPlaceHolder()) { GenericsType gt = new GenericsType(di); gt.setPlaceholder(di.isGenericsPlaceHolder()); connections.put(new GenericsTypeName(di.getGenericsTypes()[0].getName()), gt); } else if (di.isUsingGenerics()) { extractGenericsConnections(connections, ui.getGenericsTypes(), di.getGenericsTypes()); } } }
public static ClassNode correctToGenericsSpec(Map<String, ClassNode> genericsSpec, ClassNode type) { if (type.isArray()) { return correctToGenericsSpec(genericsSpec, type.getComponentType()).makeArray(); } if (type.isGenericsPlaceHolder()) { String name = type.getGenericsTypes()[0].getName(); type = genericsSpec.get(name); } if (type == null) type = ClassHelper.OBJECT_TYPE; return type; }
private static void extractSuperClassGenerics(ClassNode[] usage, ClassNode[] declaration, Map<String, ClassNode> spec) { if (usage == null || declaration == null || declaration.length == 0) return; // both have generics for (int i = 0; i < usage.length; i++) { ClassNode ui = usage[i]; ClassNode di = declaration[i]; if (di.isGenericsPlaceHolder()) { spec.put(di.getGenericsTypes()[0].getName(), di); } else if (di.isUsingGenerics()) { extractSuperClassGenerics(ui.getGenericsTypes(), di.getGenericsTypes(), spec); } } }
public static String getGenericsMethodSignature(MethodNode node) { GenericsType[] generics = node.getGenericsTypes(); Parameter[] param = node.getParameters(); ClassNode returnType = node.getReturnType(); if (generics == null && !hasGenerics(param) && !hasGenerics(returnType)) return null; StringBuilder ret = new StringBuilder(100); getGenericsTypeSpec(ret, generics); GenericsType[] paramTypes = new GenericsType[param.length]; for (int i = 0; i < param.length; i++) { ClassNode pType = param[i].getType(); if (pType.getGenericsTypes() == null || !pType.isGenericsPlaceHolder()) { paramTypes[i] = new GenericsType(pType); } else { paramTypes[i] = pType.getGenericsTypes()[0]; } } addSubTypes(ret, paramTypes, "(", ")"); addSubTypes(ret, new GenericsType[]{new GenericsType(returnType)}, "", ""); return ret.toString(); }
public static void extractSuperClassGenerics(ClassNode type, ClassNode target, Map<String, ClassNode> spec) { // TODO: this method is very similar to StaticTypesCheckingSupport#extractGenericsConnections, // but operates on ClassNodes instead of GenericsType if (target == null || type == target) return; if (type.isArray() && target.isArray()) { extractSuperClassGenerics(type.getComponentType(), target.getComponentType(), spec); } else if (type.isArray() && JAVA_LANG_OBJECT.equals(target.getName())) { // Object is superclass of arrays but no generics involved } else if (target.isGenericsPlaceHolder() || type.equals(target) || !implementsInterfaceOrIsSubclassOf(type, target)) { // structural match route if (target.isGenericsPlaceHolder()) { spec.put(target.getGenericsTypes()[0].getName(), type); } else { extractSuperClassGenerics(type.getGenericsTypes(), target.getGenericsTypes(), spec); } } else { // have first to find matching super class or interface ClassNode superClass = getSuperClass(type, target); if (superClass != null) { ClassNode corrected = getCorrectedClassNode(type, superClass, false); extractSuperClassGenerics(corrected, target, spec); } else { // if we reach here, we have an unhandled case throw new GroovyBugError("The type " + type + " seems not to normally extend " + target + ". Sorry, I cannot handle this."); } } }
/** * Apply the bounds from the declared type when the using type simply declares a parameter as an unbounded wildcard. * * @param type A parameterized type * @return A parameterized type with more precise wildcards */ static ClassNode boundUnboundedWildcards(ClassNode type) { if (type.isArray()) { return boundUnboundedWildcards(type.getComponentType()).makeArray(); } ClassNode target = type.redirect(); if (target == null || type == target || !isUsingGenericsOrIsArrayUsingGenerics(target)) return type; ClassNode newType = type.getPlainNodeReference(); newType.setGenericsPlaceHolder(type.isGenericsPlaceHolder()); newType.setGenericsTypes(boundUnboundedWildcards(type.getGenericsTypes(), target.getGenericsTypes())); return newType; }
private static boolean compatibleConnection(GenericsType resolved, GenericsType connection) { GenericsType gt = connection; if (!connection.isWildcard()) gt = buildWildcardType(connection); if (resolved.isPlaceholder() && resolved.getUpperBounds() != null && resolved.getUpperBounds().length == 1 && !resolved.getUpperBounds()[0].isGenericsPlaceHolder() && resolved.getUpperBounds()[0].getName().equals("java.lang.Object")) { return true; } ClassNode compareNode; if (hasNonTrivialBounds(resolved)) { compareNode = getCombinedBoundType(resolved); compareNode = compareNode.redirect().getPlainNodeReference(); } else { if (!resolved.isPlaceholder()) { compareNode = resolved.getType().getPlainNodeReference(); } else { return true; } } return gt.isCompatibleWith(compareNode); }
static ClassNode applyGenericsContext( Map<GenericsTypeName, GenericsType> spec, ClassNode bound ) { if (bound == null) return null; if (bound.isArray()) { return applyGenericsContext(spec, bound.getComponentType()).makeArray(); } if (!bound.isUsingGenerics()) return bound; ClassNode newBound = bound.getPlainNodeReference(); newBound.setGenericsTypes(applyGenericsContext(spec, bound.getGenericsTypes())); if (bound.isGenericsPlaceHolder()) { GenericsType[] gt = newBound.getGenericsTypes(); boolean hasBounds = hasNonTrivialBounds(gt[0]); if (hasBounds || !gt[0].isPlaceholder()) return getCombinedBoundType(gt[0]); String placeHolderName = newBound.getGenericsTypes()[0].getName(); if (!placeHolderName.equals(newBound.getUnresolvedName())) { // we should produce a clean placeholder ClassNode here ClassNode clean = make(placeHolderName); clean.setGenericsTypes(newBound.getGenericsTypes()); clean.setRedirect(newBound); newBound = clean; } newBound.setGenericsPlaceHolder(true); } return newBound; }
private static GenericsType applyGenericsContext(Map<GenericsTypeName, GenericsType> spec, GenericsType gt) { if (gt.isPlaceholder()) { GenericsTypeName name = new GenericsTypeName(gt.getName()); GenericsType specType = spec.get(name); if (specType != null) return specType; if (hasNonTrivialBounds(gt)) { GenericsType newGT = new GenericsType(gt.getType(), applyGenericsContext(spec, gt.getUpperBounds()), applyGenericsContext(spec, gt.getLowerBound())); newGT.setPlaceholder(true); return newGT; } return gt; } else if (gt.isWildcard()) { GenericsType newGT = new GenericsType(gt.getType(), applyGenericsContext(spec, gt.getUpperBounds()), applyGenericsContext(spec, gt.getLowerBound())); newGT.setWildcard(true); return newGT; } ClassNode type = gt.getType(); ClassNode newType; if (type.isArray()) { newType = applyGenericsContext(spec, type.getComponentType()).makeArray(); } else { if (type.getGenericsTypes()==null) return gt; newType = type.getPlainNodeReference(); newType.setGenericsPlaceHolder(type.isGenericsPlaceHolder()); newType.setGenericsTypes(applyGenericsContext(spec, type.getGenericsTypes())); } return new GenericsType(newType); }