/** * A restricted version of areClassTypesAssignable that is used for comparing the type arguments * of parameterized types, where the lhsTypeArg is the container. */ private static boolean doesTypeArgumentContain(JClassType lhsTypeArg, JClassType rhsTypeArg) { if (lhsTypeArg == rhsTypeArg) { return true; } // Check for wildcard types JWildcardType lhsWildcard = lhsTypeArg.isWildcard(); JWildcardType rhsWildcard = rhsTypeArg.isWildcard(); if (lhsWildcard != null) { if (rhsWildcard != null) { return areWildcardsAssignable(lhsWildcard, rhsWildcard); } else { // LHS is a wildcard but the RHS is not. if (lhsWildcard.getLowerBounds().length > 0) { return areClassTypesAssignable(rhsTypeArg, lhsWildcard.getFirstBound()); } else { return areClassTypesAssignable(lhsWildcard.getFirstBound(), rhsTypeArg); } } } /* * At this point the arguments are not the same and they are not wildcards * so, they cannot be assignable, Eh. */ return false; }
public JParameterizedType asParameterizationOf( com.google.gwt.core.ext.typeinfo.JGenericType type) { Set<JClassType> supertypes = getFlattenedSuperTypeHierarchy(this); for (JClassType supertype : supertypes) { JParameterizedType isParameterized = supertype.isParameterized(); if (isParameterized != null && isParameterized.getBaseType() == type) { return isParameterized; } JRawType isRaw = supertype.isRawType(); if (isRaw != null && isRaw.getBaseType() == type) { return isRaw.asParameterizedByWildcards(); } } return null; }
private static void getFlattenedSuperTypeHierarchyRecursive( JClassType type, Set<JClassType> typesSeen) { if (typesSeen.contains(type)) { return; } typesSeen.add(type); // Check the interfaces JClassType[] intfs = type.getImplementedInterfaces(); for (JClassType intf : intfs) { typesSeen.addAll(getFlattenedSuperTypeHierarchy(intf)); } // Superclass JClassType superclass = type.getSuperclass(); if (superclass != null) { typesSeen.addAll(getFlattenedSuperTypeHierarchy(superclass)); } }
/** * Returns all of the superclasses and superinterfaces for a given type including the type itself. * The returned set maintains an internal breadth-first ordering of the type, followed by its * interfaces (and their super-interfaces), then the supertype and its interfaces, and so on. */ protected static Set<JClassType> getFlattenedSuperTypeHierarchy(JClassType type) { Set<JClassType> flattened = type.flattenedSupertypes; if (flattened == null) { flattened = new LinkedHashSet<JClassType>(); getFlattenedSuperTypeHierarchyRecursive(type, flattened); // flattened.size() > 1 for all types other than Object type.flattenedSupertypes = Collections.unmodifiableSet(flattened); } return flattened; }
/** * Find an annotation on a type or on one of its superclasses or superinterfaces. * * <p>This provides semantics similar to that of {@link java.lang.annotation.Inherited} except * that it checks all types to which this type is assignable. {@code @Inherited} only works on * superclasses, not superinterfaces. * * <p>Annotations present on the superclass chain will be returned preferentially over those found * in the superinterface hierarchy. Note that the annotation does not need to be tagged with * {@code @Inherited} in order to be returned from the superclass chain. * * @param annotationType the type of the annotation to look for * @return the desired annotation or <code>null</code> if the annotation is not present in the * type's type hierarchy */ @Override public <T extends Annotation> T findAnnotationInTypeHierarchy(Class<T> annotationType) { // Remember what we've seen to avoid loops Set<JClassType> seen = new HashSet<JClassType>(); // Work queue List<JClassType> searchTypes = new LinkedList<JClassType>(); searchTypes.add(this); T toReturn = null; while (!searchTypes.isEmpty()) { JClassType current = searchTypes.remove(0); if (!seen.add(current)) { continue; } toReturn = current.getAnnotation(annotationType); if (toReturn != null) { /* * First one wins. It might be desirable at some point to have a * variation that can return more than one instance of the annotation if * it is present on multiple supertypes. */ break; } if (current.getSuperclass() != null) { // Add the superclass at the front of the list searchTypes.add(0, current.getSuperclass()); } // Superinterfaces Collections.addAll(searchTypes, current.getImplementedInterfaces()); } return toReturn; }
/** * Return the real argument names for a given method from the source. * * @param method method to lookup parameter names for * @return array of argument names or null if no source is available */ public synchronized String[] getArguments(JAbstractMethod method) { JClassType type = method.getEnclosingType(); JClassType topType = getTopmostType(type); CompilationUnitDeclaration cud = getCudForTopLevelType(topType); if (cud == null) { return null; } TypeDeclaration jdtType = findType(cud, type.getQualifiedBinaryName()); if (jdtType == null) { // TODO(jat): any thing else to do here? return null; } AbstractMethodDeclaration jdtMethod = findMethod(jdtType, method); if (jdtMethod == null) { // TODO(jat): any thing else to do here? return null; } int n = jdtMethod.arguments.length; String[] argNames = new String[n]; for (int i = 0; i < n; ++i) { argNames[i] = String.valueOf(jdtMethod.arguments[i].name); } return argNames; }
public static JClassType getTopmostType(JClassType type) { while (type.getEnclosingType() != null) { type = type.getEnclosingType(); } return type; }
/** * Returns <code>true</code> if the lhs and rhs are assignable without consideration of the * supertypes of the rhs. * * @param lhsType * @param rhsType * @return true if rhsType can be assigned to lhsType */ private static boolean areClassTypesAssignableNoSupers(JClassType lhsType, JClassType rhsType) { if (lhsType == rhsType) { // Done, these are the same types. return true; } if (lhsType == lhsType.getOracle().getJavaLangObject()) { // Done, any type can be assigned to object. return true; } /* * Get the generic base type, if there is one, for the lhs type and convert * it to a raw type if it is generic. */ if (lhsType.isGenericType() != null) { lhsType = lhsType.isGenericType().getRawType(); } if (rhsType.isGenericType() != null) { // Treat the generic rhs type as a raw type. rhsType = rhsType.isGenericType().getRawType(); } // Check for JTypeParameters. JTypeParameter lhsTypeParam = lhsType.isTypeParameter(); JTypeParameter rhsTypeParam = rhsType.isTypeParameter(); if (lhsTypeParam != null) { JClassType[] lhsTypeBounds = lhsTypeParam.getBounds(); for (JClassType lhsTypeBound : lhsTypeBounds) { if (!areClassTypesAssignable(lhsTypeBound, rhsType)) { // Done, the rhsType was not assignable to one of the bounds. return false; } } // Done, the rhsType was assignable to all of the bounds. return true; } else if (rhsTypeParam != null) { JClassType[] possibleSubtypeBounds = rhsTypeParam.getBounds(); for (JClassType possibleSubtypeBound : possibleSubtypeBounds) { if (areClassTypesAssignable(lhsType, possibleSubtypeBound)) { // Done, at least one bound is assignable to this type. return true; } } return false; } /* * Check for JWildcards. We have not examined this part in great detail * since there should not be top level wildcard types. */ JWildcardType lhsWildcard = lhsType.isWildcard(); JWildcardType rhsWildcard = rhsType.isWildcard(); if (lhsWildcard != null && rhsWildcard != null) { // Both types are wildcards. return areWildcardsAssignable(lhsWildcard, rhsWildcard); } else if (lhsWildcard != null) { // The lhs type is a wildcard but the rhs is not. // ? extends T, U OR ? super T, U JClassType[] lowerBounds = lhsWildcard.getLowerBounds(); if (lowerBounds.length > 0) { // ? super T will reach object no matter what the rhs type is return true; } else { return areClassTypesAssignable(lhsWildcard.getFirstBound(), rhsType); } } // Check for JArrayTypes. JArrayType lhsArray = lhsType.isArray(); JArrayType rhsArray = rhsType.isArray(); if (lhsArray != null) { if (rhsArray == null) { return false; } else { return areArraysAssignable(lhsArray, rhsArray); } } else if (rhsArray != null) { // Safe although perhaps not necessary return false; } // Check for JParameterizedTypes and JRawTypes. JMaybeParameterizedType lhsMaybeParameterized = lhsType.isMaybeParameterizedType(); JMaybeParameterizedType rhsMaybeParameterized = rhsType.isMaybeParameterizedType(); if (lhsMaybeParameterized != null && rhsMaybeParameterized != null) { if (lhsMaybeParameterized.getBaseType() == rhsMaybeParameterized.getBaseType()) { if (lhsMaybeParameterized.isRawType() != null || rhsMaybeParameterized.isRawType() != null) { /* * Any raw type can be assigned to or from any parameterization of its * generic type. */ return true; } assert (lhsMaybeParameterized.isRawType() == null && rhsMaybeParameterized.isRawType() == null); JParameterizedType lhsParameterized = lhsMaybeParameterized.isParameterized(); JParameterizedType rhsParameterized = rhsMaybeParameterized.isParameterized(); assert (lhsParameterized != null && rhsParameterized != null); return areTypeArgumentsAssignable(lhsParameterized, rhsParameterized); } } // Default to not being assignable. return false; }