@Override public StringBuilder visitTypeVariable(TypeVariable t, Boolean p) { Element e = t.asElement(); if (e != null) { String name = e.getSimpleName().toString(); if (!CAPTURED_WILDCARD.equals(name)) return DEFAULT_VALUE.append(name); } DEFAULT_VALUE.append("?"); //NOI18N TypeMirror bound = t.getLowerBound(); if (bound != null && bound.getKind() != TypeKind.NULL) { DEFAULT_VALUE.append(" super "); //NOI18N visit(bound, p); } else { bound = t.getUpperBound(); if (bound != null && bound.getKind() != TypeKind.NULL) { DEFAULT_VALUE.append(" extends "); //NOI18N if (bound.getKind() == TypeKind.TYPEVAR) bound = ((TypeVariable)bound).getLowerBound(); visit(bound, p); } } return DEFAULT_VALUE; }
private static boolean verifyTypeVarAccessible(ExecutableElement method, TypeMirror forType, List<Element> usedLocalTypeVariables, Element target) { Collection<TypeVariable> typeVars = Utilities.containedTypevarsRecursively(forType); if (method != null) { for (Iterator<TypeVariable> it = typeVars.iterator(); it.hasNext(); ) { TypeVariable tvar = it.next(); Element tvarEl = tvar.asElement(); if (method.getTypeParameters().contains(tvarEl)) { usedLocalTypeVariables.add(tvarEl); it.remove(); } } } return allTypeVarsAccessible(typeVars, target); }
private static void containedTypevarsRecursively(@NonNull TypeMirror tm, @NonNull Collection<TypeVariable> typeVars) { switch (tm.getKind()) { case TYPEVAR: typeVars.add((TypeVariable) tm); break; case DECLARED: DeclaredType type = (DeclaredType) tm; for (TypeMirror t : type.getTypeArguments()) { containedTypevarsRecursively(t, typeVars); } break; case ARRAY: containedTypevarsRecursively(((ArrayType) tm).getComponentType(), typeVars); break; case WILDCARD: if (((WildcardType) tm).getExtendsBound() != null) { containedTypevarsRecursively(((WildcardType) tm).getExtendsBound(), typeVars); } if (((WildcardType) tm).getSuperBound() != null) { containedTypevarsRecursively(((WildcardType) tm).getSuperBound(), typeVars); } break; } }
/** * uses FQNs where possible since javadoc does not match imports for * parameter types */ private CharSequence resolveTypeName(TypeMirror asType, boolean isVarArgs) { CharSequence ptype; if (asType.getKind() == TypeKind.DECLARED) { // snip generics Element e = ((DeclaredType) asType).asElement(); ptype = e.getKind().isClass() || e.getKind().isInterface() ? ((TypeElement) e).getQualifiedName() : e.getSimpleName(); } else if (asType.getKind() == TypeKind.TYPEVAR) { do { // Type Erasure JLS 4.6 asType = ((TypeVariable) asType).getUpperBound(); } while (asType.getKind() == TypeKind.TYPEVAR); ptype = resolveTypeName(asType, isVarArgs); } else if (isVarArgs && asType.getKind() == TypeKind.ARRAY) { ptype = resolveTypeName(((ArrayType)asType).getComponentType(), false) + "..."; //NOI18N } else { ptype = asType.toString(); } return ptype; }
@Override public Void visitTypeVariable(TypeVariable type, Void p) { Element e = type.asElement(); if (e != null) { CharSequence name = e.getSimpleName(); if (!CAPTURED_WILDCARD.contentEquals(name)) { builder.append(name); return null; } } builder.append("?"); //NOI18N TypeMirror bound = type.getLowerBound(); if (bound != null && bound.getKind() != TypeKind.NULL) { builder.append(" super "); //NOI18N visit(bound); } else { bound = type.getUpperBound(); if (bound != null && bound.getKind() != TypeKind.NULL) { builder.append(" extends "); //NOI18N if (bound.getKind() == TypeKind.TYPEVAR) bound = ((TypeVariable)bound).getLowerBound(); visit(bound); } } return null; }
/** * 取得方法参数类型列表 */ private List<String> getMethodParameterTypes(ExecutableElement executableElement) { List<? extends VariableElement> methodParameters = executableElement.getParameters(); if (methodParameters.size() == 0) { return null; } List<String> types = new ArrayList<>(); for (VariableElement variableElement : methodParameters) { TypeMirror methodParameterType = variableElement.asType(); if (methodParameterType instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) methodParameterType; methodParameterType = typeVariable.getUpperBound(); } types.add(methodParameterType.toString()); } return types; }
static String getErasedType(TypeMirror type) { switch (type.getKind()) { case DECLARED: DeclaredType declared = (DeclaredType) type; TypeElement element = (TypeElement) declared.asElement(); return element.getQualifiedName().toString(); case TYPEVAR: return getErasedType(((TypeVariable) type).getUpperBound()); case WILDCARD: return getErasedType(((WildcardType) type).getExtendsBound()); case ARRAY: return getErasedType(((ArrayType) type).getComponentType()) + "[]"; default: return type.toString(); } }
private static void appendSimpleTypeName(StringBuilder ret, TypeMirror type) { switch (type.getKind()) { case DECLARED: DeclaredType declared = (DeclaredType) type; TypeElement element = (TypeElement) declared.asElement(); ret.append(element.getSimpleName()); break; case TYPEVAR: appendSimpleTypeName(ret, ((TypeVariable) type).getUpperBound()); break; case WILDCARD: appendSimpleTypeName(ret, ((WildcardType) type).getExtendsBound()); break; case ARRAY: appendSimpleTypeName(ret, ((ArrayType) type).getComponentType()); ret.append("Array"); break; default: ret.append(type); } }
@Override public Boolean visitTypeVariable(TypeVariable a, EqualVisitorParam p) { if (p.type.getKind().equals(TYPEVAR)) { TypeVariable b = (TypeVariable) p.type; TypeParameterElement aElement = (TypeParameterElement) a.asElement(); TypeParameterElement bElement = (TypeParameterElement) b.asElement(); Set<ComparedElements> newVisiting = visitingSetPlus(p.visiting, aElement, bElement); if (newVisiting.equals(p.visiting)) { // We're already visiting this pair of elements. // This can happen with our friend Eclipse when looking at <T extends Comparable<T>>. // It incorrectly reports the upper bound of T as T itself. return true; } // We use aElement.getBounds() instead of a.getUpperBound() to avoid having to deal with // the different way intersection types (like <T extends Number & Comparable<T>>) are // represented before and after Java 8. We do have an issue that this code may consider // that <T extends Foo & Bar> is different from <T extends Bar & Foo>, but it's very // hard to avoid that, and not likely to be much of a problem in practice. return equalLists(aElement.getBounds(), bElement.getBounds(), newVisiting) && equal(a.getLowerBound(), b.getLowerBound(), newVisiting) && a.asElement().getSimpleName().equals(b.asElement().getSimpleName()); } return false; }
/** * Make a TypeVariableName for the given TypeMirror. This form is used internally to avoid * infinite recursion in cases like {@code Enum<E extends Enum<E>>}. When we encounter such a * thing, we will make a TypeVariableName without bounds and add that to the {@code typeVariables} * map before looking up the bounds. Then if we encounter this TypeVariable again while * constructing the bounds, we can just return it from the map. And, the code that put the entry * in {@code variables} will make sure that the bounds are filled in before returning. */ static com.wrmsr.wava.java.poet.TypeVariableName get( TypeVariable mirror, Map<TypeParameterElement, com.wrmsr.wava.java.poet.TypeVariableName> typeVariables) { TypeParameterElement element = (TypeParameterElement) mirror.asElement(); com.wrmsr.wava.java.poet.TypeVariableName typeVariableName = typeVariables.get(element); if (typeVariableName == null) { // Since the bounds field is public, we need to make it an unmodifiableList. But we control // the List that that wraps, which means we can change it before returning. List<TypeName> bounds = new ArrayList<>(); List<TypeName> visibleBounds = Collections.unmodifiableList(bounds); typeVariableName = new com.wrmsr.wava.java.poet.TypeVariableName(element.getSimpleName().toString(), visibleBounds); typeVariables.put(element, typeVariableName); for (TypeMirror typeMirror : element.getBounds()) { bounds.add(TypeName.get(typeMirror, typeVariables)); } bounds.remove(OBJECT); } return typeVariableName; }
/** * @see #get(java.lang.reflect.TypeVariable, Map) */ static com.wrmsr.wava.java.poet.TypeVariableName get(java.lang.reflect.TypeVariable<?> type, Map<Type, com.wrmsr.wava.java.poet.TypeVariableName> map) { com.wrmsr.wava.java.poet.TypeVariableName result = map.get(type); if (result == null) { List<TypeName> bounds = new ArrayList<>(); List<TypeName> visibleBounds = Collections.unmodifiableList(bounds); result = new com.wrmsr.wava.java.poet.TypeVariableName(type.getName(), visibleBounds); map.put(type, result); for (Type bound : type.getBounds()) { bounds.add(TypeName.get(bound, map)); } bounds.remove(OBJECT); } return result; }
/** * Make a TypeVariableName for the given TypeMirror. This form is used internally to avoid * infinite recursion in cases like {@code Enum<E extends Enum<E>>}. When we encounter such a * thing, we will make a TypeVariableName without bounds and add that to the {@code typeVariables} * map before looking up the bounds. Then if we encounter this TypeVariable again while * constructing the bounds, we can just return it from the map. And, the code that put the entry * in {@code variables} will make sure that the bounds are filled in before returning. */ static TypeVariableName get( TypeVariable mirror, Map<TypeParameterElement, TypeVariableName> typeVariables) { TypeParameterElement element = (TypeParameterElement) mirror.asElement(); TypeVariableName typeVariableName = typeVariables.get(element); if (typeVariableName == null) { // Since the bounds field is public, we need to make it an unmodifiableList. But we control // the List that that wraps, which means we can change it before returning. List<TypeName> bounds = new ArrayList<>(); List<TypeName> visibleBounds = Collections.unmodifiableList(bounds); typeVariableName = new TypeVariableName(element.getSimpleName().toString(), visibleBounds); typeVariables.put(element, typeVariableName); for (TypeMirror typeMirror : element.getBounds()) { bounds.add(TypeName.get(typeMirror, typeVariables)); } bounds.remove(OBJECT); } return typeVariableName; }
/** * @see #get(java.lang.reflect.TypeVariable, Map) */ static TypeVariableName get(java.lang.reflect.TypeVariable<?> type, Map<Type, TypeVariableName> map) { TypeVariableName result = map.get(type); if (result == null) { List<TypeName> bounds = new ArrayList<>(); List<TypeName> visibleBounds = Collections.unmodifiableList(bounds); result = new TypeVariableName(type.getName(), visibleBounds); map.put(type, result); for (Type bound : type.getBounds()) { bounds.add(TypeName.get(bound, map)); } bounds.remove(OBJECT); } return result; }
private TypeName getFeatureParameterTypeVariableName(DeclaredType featureType, int featureParameterIndex) { Element paramElem = getFeatureParameterElement(featureType, featureParameterIndex); if (paramElem == null) { return null; } if (paramElem.getKind() == ElementKind.TYPE_PARAMETER) { return TypeVariableName.get((TypeVariable) paramElem.asType()); } else if (paramElem.getKind() == ElementKind.CLASS) { return TypeName.get(paramElem.asType()); } return null; }
/** @see #get(java.lang.reflect.TypeVariable, Map) */ static TypeVariableName get(java.lang.reflect.TypeVariable<?> type, Map<Type, TypeVariableName> map) { TypeVariableName result = map.get(type); if (result == null) { List<TypeName> bounds = new ArrayList<>(); List<TypeName> visibleBounds = Collections.unmodifiableList(bounds); result = new TypeVariableName(type.getName(), visibleBounds); map.put(type, result); for (Type bound : type.getBounds()) { bounds.add(TypeName.get(bound, map)); } bounds.remove(OBJECT); } return result; }
@Override public TypeKey visitTypeVariable(TypeVariable t, Set<TypeParameterElement> visited) { TypeParameterElement element = (TypeParameterElement) t.asElement(); if (visited.contains(element)) { // This avoids infinite recursion with adapted types like <T extends Comparable<T>>. // It should probably check that T is bound correctly, but this is unlikely to be an issue // in the wild. return AnyKey.get(t.toString()); } visited.add(element); ImmutableList.Builder<TypeKey> builder = ImmutableList.builder(); for (TypeMirror bound : element.getBounds()) { TypeKey boundKey = bound.accept(this, visited); if (!boundKey.equals(OBJECT)) { builder.add(boundKey); } } ImmutableList<TypeKey> bounds = builder.build(); if (bounds.size() == 0) { return AnyKey.get(t.toString()); } else { return BoundedKey.get(t.toString(), bounds); } }
public AnnotationInfo(TypeMirror tm, String idProperty, boolean keepNonIdProperty, TypeMirror idGeneratorType, boolean customGenerator) { this.tm = tm; if (tm.getKind() != TypeKind.DECLARED) { throw new RuntimeException(tm + " should be declared"); } DeclaredType dt = (DeclaredType) tm; List<? extends TypeMirror> typeArguments = dt.getTypeArguments(); if (typeArguments != null) { for (TypeMirror tms : typeArguments) { if (tms instanceof TypeVariable) { typeVariables.add((TypeVariable) tms); } else if (tms instanceof WildcardType) { typeWildcards.add((WildcardType) tms); } } } this.idGeneratorType = idGeneratorType; this.customGenerator = customGenerator; this.idProperty = Strings.nullToEmpty(idProperty).trim(); this.keepNonIdProperty = keepNonIdProperty; }
/** * Create a type spec builder which copies from {@code element}. */ public TypeSpec.Builder buildInterface(TypeElement element) { if (!element.getKind().isInterface()) { throw new IllegalArgumentException("only interfaces are supported, got " + element.getKind()); } TypeSpec.Builder builder = TypeSpec.interfaceBuilder(element.getSimpleName().toString()); builder.addAnnotations(Poetry.annotations(element.getAnnotationMirrors())); for (Modifier modifier : element.getModifiers()) { if (modifier == Modifier.ABSTRACT) continue; builder.addModifiers(modifier); } element.getInterfaces().forEach(t -> builder.addSuperinterface(TypeName.get(t))); element.getTypeParameters() .forEach(e -> builder.addTypeVariable(TypeVariableName.get((TypeVariable) e.asType()))); List<ExecutableElement> methods = ElementFilter.methodsIn(elements.getAllMembers(element)); methods.removeIf(m -> m.getEnclosingElement().equals(elemap.get(Object.class))); for (ExecutableElement method : methods) { builder.addMethod(buildMethod(method, (DeclaredType) element.asType()).build()); } return builder; }
@Override public TypeMirror visitTypeVariable(TypeVariable typeVariable, @Nullable Substitutions substitutions) { assert substitutions != null; TypeParameterElement formalTypeParameter = (TypeParameterElement) typeVariable.asElement(); @Nullable TypeVariable freshTypeVariable = substitutions.freshTypeVariables.get(formalTypeParameter); if (freshTypeVariable != null && formalTypeParameter.asType().equals(typeVariable)) { return freshTypeVariable; } @Nullable TypeMirror substitution = substitutions.map.get(formalTypeParameter); if (substitution != null) { return substitution; } return getTypeVariable( formalTypeParameter, typeVariable.getUpperBound().accept(this, substitutions), typeVariable.getLowerBound().accept(this, substitutions), capturedTypeArgument(typeVariable) ); }
/** * Verifies the {@link TypeElement} instances in {@link #typeElementMap}. * * <p>The following is verified: * <ul><li> * {@link TypeElement#asType()} returns "a <i>prototypical</i> type" which is "the element's invocation on the * type variables corresponding to its own formal type parameters". * </li><li> * {@link #type(Class)} returns a raw type if the given class object represents a generic type declaration. * </li><li> * Passing the raw type returned by {@link #type(Class)} to * {@link AbstractTypes#toString(TypeMirror)} yields a string equal to the class's name. * </li></ul> */ @Test public void testSetup() { for (Map.Entry<Class<?>, TypeElement> entry: typeElementMap.entrySet()) { Class<?> clazz = entry.getKey(); TypeElement typeElement = entry.getValue(); assertTrue(typeElement.getKind().isClass() || typeElement.getKind().isInterface()); DeclaredType prototypicalType = (DeclaredType) typeElement.asType(); assertEquals(typeElement.getTypeParameters().size(), prototypicalType.getTypeArguments().size()); for (TypeMirror typeArgument: prototypicalType.getTypeArguments()) { assertTrue(typeArgument.getKind() == TypeKind.TYPEVAR && typeArgument instanceof TypeVariable); } DeclaredType rawType = (DeclaredType) type(clazz); assertTrue(rawType.getTypeArguments().isEmpty()); assertEquals(clazz.getCanonicalName(), types.toString(rawType)); } }
/** * Verifies {@link AbstractTypes#capture(TypeMirror)}. */ @Test public void capture() { assertEquals(types.capture(type(Integer.class)), type(Integer.class)); DeclaredType outerClassType = types.getDeclaredType(element(OuterClass.class), type(Integer.class)); DeclaredType arrayListOfIntegersType = types.getDeclaredType(element(ArrayList.class), type(Integer.class)); // innerClassType: OuterClass<Integer>.InnerClass<? extends ArrayList<Integer>> DeclaredType innerClassType = types.getDeclaredType( outerClassType, element(OuterClass.InnerClass.class), types.getWildcardType(arrayListOfIntegersType, null) ); DeclaredType capturedType = (DeclaredType) types.capture(innerClassType); TypeVariable actualTypeArgument = (TypeVariable) capturedType.getTypeArguments().get(0); // intersectionType = glb(ArrayList<Integer>, List<?>, Serializable) IntersectionType intersectionType = (IntersectionType) actualTypeArgument.getUpperBound(); assertTrue(isSubtypeOfOneOf(arrayListOfIntegersType, intersectionType.getBounds())); PrimitiveType intType = types.getPrimitiveType(TypeKind.INT); assertTrue(types.isSameType(types.capture(intType), intType)); }
@Test public void captureSingleRecursiveBound() { // enumType: Enum<?> DeclaredType enumType = types.getDeclaredType(element(Enum.class), types.getWildcardType(null, null)); // capture: java.lang.Enum<capture<?>> DeclaredType capture = (DeclaredType) types.capture(enumType); assertEquals(capture.getTypeArguments().size(), 1); TypeVariable newTypeVariable = (TypeVariable) capture.getTypeArguments().get(0); DeclaredType upperBound = (DeclaredType) newTypeVariable.getUpperBound(); assertEquals(upperBound.getKind(), TypeKind.DECLARED); // Since Enum has a recursive type bound, upperBound must represent Enum<capture<?>> as well! assertEquals(capture, upperBound); // The following should be implied, but explicit test does not hurt TypeElement upperBoundAsElement = (TypeElement) upperBound.asElement(); assertTrue(upperBoundAsElement.getQualifiedName().contentEquals(Enum.class.getName())); }
/** * Verifies {@link AbstractTypes#setTypeVariableBounds(TypeVariable, TypeMirror, TypeMirror)}. */ @Test public void testSetTypeVariableBounds() { TypeElement listDeclaration = element(List.class); TypeParameterElement elementTypeParameter = listDeclaration.getTypeParameters().get(0); TypeVariable typeVariable = types.createTypeVariable(elementTypeParameter, null); types.setTypeVariableBounds(typeVariable, type(Integer.class), types.getNullType()); assertEquals(typeVariable.asElement(), elementTypeParameter); assertTrue(types.isSameType(typeVariable.getUpperBound(), type(Integer.class))); assertTrue(types.isSameType(typeVariable.getLowerBound(), types.getNullType())); assertNull(types.capturedTypeArgument(typeVariable)); try { types.setTypeVariableBounds(typeVariable, type(Integer.class), types.getNullType()); Assert.fail("Expected exception."); } catch (IllegalStateException ignored) { } }
private BundleFieldBinding getBundleFieldBinding(Element element) throws InvalidTypeException { TypeMirror type = element.asType(); if (type instanceof TypeVariable) { type = ((TypeVariable) type).getUpperBound(); } TypeMirror bundleSerializer = getAnnotationElementClass(element, BundleSerializer.class); validateSerializer(element, BundleSerializer.class, bundleSerializer, PocketKnifeBundleSerializer.class); String name = element.getSimpleName().toString(); String bundleType = null; if (bundleSerializer == null) { bundleType = typeUtil.getBundleType(type); } KeySpec key = getKey(element, ARG_KEY_PREFIX); return new BundleFieldBinding(name, null, type, bundleType, key, bundleSerializer); }
private IntentFieldBinding getIntentFieldBinding(Element element) throws InvalidTypeException { TypeMirror type = element.asType(); if (type instanceof TypeVariable) { type = ((TypeVariable) type).getUpperBound(); } TypeMirror intentSerializer = getAnnotationElementClass(element, IntentSerializer.class); validateSerializer(element, IntentSerializer.class, intentSerializer, PocketKnifeIntentSerializer.class); String name = element.getSimpleName().toString(); String intentType = null; if (intentSerializer == null) { intentType = typeUtil.getIntentType(type); } boolean arrayList = isIntentArrayList(intentType); KeySpec key = getKey(element, EXTRA_KEY_PREFIX); return new IntentFieldBinding(name, null, type, intentType, key, arrayList, intentSerializer); }
@Override public Void visitTypeVariable(TypeVariable t, StringBuilderAndState<TypeMirror> state) { if (state.visitingMethod) { TypeMirror upperBound = IgnoreCompletionFailures.in(t::getUpperBound); upperBound.accept(this, state); return null; } if (state.visitedObjects.contains(t)) { state.bld.append("%"); return null; } state.visitedObjects.add(t); TypeMirror lowerBound = IgnoreCompletionFailures.in(t::getLowerBound); if (lowerBound != null && lowerBound.getKind() != TypeKind.NULL) { lowerBound.accept(this, state); state.bld.append("-"); } IgnoreCompletionFailures.in(t::getUpperBound).accept(this, state); state.bld.append("+"); return null; }
@Override public Void visitTypeVariable(TypeVariable t, StringBuilderAndState<TypeMirror> state) { if (state.visitedObjects.contains(t)) { state.bld.append(t.asElement().getSimpleName()); return null; } state.visitedObjects.add(t); state.bld.append(t.asElement().getSimpleName()); if (!state.visitingMethod) { TypeMirror lowerBound = IgnoreCompletionFailures.in(t::getLowerBound); if (lowerBound != null && lowerBound.getKind() != TypeKind.NULL) { state.bld.append(" super "); lowerBound.accept(this, state); } state.bld.append(" extends "); IgnoreCompletionFailures.in(t::getUpperBound).accept(this, state); } return null; }
protected TypeMirror inferType(TypeVariable typeVariable, TypeElement classElement, TypeMirror classMirror) { DeclaredType declaredType = TypeMirrorUtil.toDeclaredType( classMirror, env); if (declaredType == null) { return null; } List<? extends TypeMirror> args = declaredType.getTypeArguments(); if (args.isEmpty()) { return null; } int argsSize = args.size(); int index = 0; for (TypeParameterElement typeParam : classElement .getTypeParameters()) { if (index >= argsSize) { break; } if (TypeMirrorUtil.isSameType(typeVariable, typeParam.asType(), env)) { return args.get(index); } index++; } return null; }
/** * If the argument is a bounded TypeVariable or WildcardType, * return its non-variable, non-wildcard upper bound. Otherwise, * return the type itself. * * @param type a type * @return the non-variable, non-wildcard upper bound of a type, * if it has one, or itself if it has no bounds */ public static TypeMirror upperBound(TypeMirror type) { do { if (type instanceof TypeVariable) { TypeVariable tvar = (TypeVariable) type; if (tvar.getUpperBound() != null) { type = tvar.getUpperBound(); } else { break; } } else if (type instanceof WildcardType) { WildcardType wc = (WildcardType) type; if (wc.getExtendsBound() != null) { type = wc.getExtendsBound(); } else { break; } } else { break; } } while (true); return type; }
/** * A helper method that standarize type by printing simple names * instead of fully qualified names. * * This eliminates the need for imports. */ private static String standarizeType(TypeMirror type) { switch (type.getKind()) { case ARRAY: return standarizeType(((ArrayType)type).getComponentType()) + "[]"; case TYPEVAR: return ((TypeVariable)type).asElement().getSimpleName().toString(); case DECLARED: { return ((DeclaredType)type).asElement().getSimpleName().toString(); } default: if (type.getKind().isPrimitive()) return type.toString(); } ErrorReporter.errorAbort("StubUtil: unhandled type: " + type); return null; // dead code }