use of javax.lang.model.type.WildcardType in project auto by google.
the class TypeVariables method canAssignStaticMethodResult.
/**
* Tests whether a given parameter can be given to a static method like {@code
* ImmutableMap.copyOf} to produce a value that can be assigned to the given target type.
*
* <p>For example, suppose we have this method in {@code ImmutableMap}:<br>
* {@code static <K, V> ImmutableMap<K, V> copyOf(Map<? extends K, ? extends V>)}<br>
* and we want to know if we can do this:
*
* <pre>
* {@code ImmutableMap<String, Integer> actualParameter = ...;}
* {@code ImmutableMap<String, Number> target = ImmutableMap.copyOf(actualParameter);}
* </pre>
*
* We will infer {@code K=String}, {@code V=Number} based on the target type, and then rewrite the
* formal parameter type from<br>
* {@code Map<? extends K, ? extends V>} to<br>
* {@code Map<? extends String, ? extends Number>}. Then we can check whether {@code
* actualParameter} is assignable to that.
*
* <p>The logic makes some simplifying assumptions, which are met for the {@code copyOf} and
* {@code of} methods that we use this for. The method must be static, it must have exactly one
* parameter, and it must have type parameters without bounds that are the same as the type
* parameters of its return type. We can see that these assumptions are met for the {@code
* ImmutableMap.copyOf} example above.
*/
static boolean canAssignStaticMethodResult(ExecutableElement method, TypeMirror actualParameterType, TypeMirror targetType, Types typeUtils) {
if (!targetType.getKind().equals(TypeKind.DECLARED) || !method.getModifiers().contains(Modifier.STATIC) || method.getParameters().size() != 1) {
return false;
}
List<? extends TypeParameterElement> typeParameters = method.getTypeParameters();
List<? extends TypeMirror> targetTypeArguments = MoreTypes.asDeclared(targetType).getTypeArguments();
if (typeParameters.size() != targetTypeArguments.size()) {
return false;
}
Map<Equivalence.Wrapper<TypeVariable>, TypeMirror> typeVariables = new LinkedHashMap<>();
for (int i = 0; i < typeParameters.size(); i++) {
TypeVariable v = MoreTypes.asTypeVariable(typeParameters.get(i).asType());
typeVariables.put(MoreTypes.equivalence().wrap(v), targetTypeArguments.get(i));
}
Function<TypeVariable, TypeMirror> substitute = v -> typeVariables.get(MoreTypes.equivalence().wrap(v));
TypeMirror formalParameterType = method.getParameters().get(0).asType();
SubstitutionVisitor substitutionVisitor = new SubstitutionVisitor(substitute, typeUtils);
TypeMirror substitutedParameterType = substitutionVisitor.visit(formalParameterType, null);
if (substitutedParameterType.getKind().equals(TypeKind.WILDCARD)) {
// If the target type is Optional<? extends Foo> then <T> T Optional.of(T) will give us
// ? extends Foo here, and typeUtils.isAssignable will return false. But we can in fact
// give a Foo as an argument, so we just replace ? extends Foo with Foo.
WildcardType wildcard = MoreTypes.asWildcard(substitutedParameterType);
if (wildcard.getExtendsBound() != null) {
substitutedParameterType = wildcard.getExtendsBound();
}
}
return typeUtils.isAssignable(actualParameterType, substitutedParameterType);
}
use of javax.lang.model.type.WildcardType in project auto by google.
the class MoreTypesTest method testIsTypeOf.
@Test
public void testIsTypeOf() {
Types types = compilationRule.getTypes();
PrimitiveType intType = types.getPrimitiveType(TypeKind.INT);
TypeMirror integerType = types.boxedClass(intType).asType();
WildcardType wildcardType = types.getWildcardType(null, null);
expect.that(MoreTypes.isTypeOf(int.class, intType)).isTrue();
expect.that(MoreTypes.isTypeOf(Integer.class, integerType)).isTrue();
expect.that(MoreTypes.isTypeOf(Integer.class, intType)).isFalse();
expect.that(MoreTypes.isTypeOf(int.class, integerType)).isFalse();
expect.that(MoreTypes.isTypeOf(Integer.class, FAKE_ERROR_TYPE)).isFalse();
assertThrows(IllegalArgumentException.class, () -> MoreTypes.isTypeOf(Integer.class, wildcardType));
}
use of javax.lang.model.type.WildcardType in project auto by google.
the class MoreTypesTest method equivalence.
@Test
public void equivalence() {
Types types = compilationRule.getTypes();
Elements elements = compilationRule.getElements();
TypeMirror objectType = elements.getTypeElement(Object.class.getCanonicalName()).asType();
TypeMirror stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
TypeElement mapElement = elements.getTypeElement(Map.class.getCanonicalName());
TypeElement setElement = elements.getTypeElement(Set.class.getCanonicalName());
TypeElement enumElement = elements.getTypeElement(Enum.class.getCanonicalName());
TypeElement container = elements.getTypeElement(Container.class.getCanonicalName());
TypeElement contained = elements.getTypeElement(Container.Contained.class.getCanonicalName());
TypeElement funkyBounds = elements.getTypeElement(FunkyBounds.class.getCanonicalName());
TypeElement funkyBounds2 = elements.getTypeElement(FunkyBounds2.class.getCanonicalName());
TypeElement funkierBounds = elements.getTypeElement(FunkierBounds.class.getCanonicalName());
TypeMirror funkyBoundsVar = ((DeclaredType) funkyBounds.asType()).getTypeArguments().get(0);
TypeMirror funkyBounds2Var = ((DeclaredType) funkyBounds2.asType()).getTypeArguments().get(0);
TypeMirror funkierBoundsVar = ((DeclaredType) funkierBounds.asType()).getTypeArguments().get(0);
DeclaredType mapOfObjectToObjectType = types.getDeclaredType(mapElement, objectType, objectType);
TypeMirror mapType = mapElement.asType();
DeclaredType setOfSetOfObject = types.getDeclaredType(setElement, types.getDeclaredType(setElement, objectType));
DeclaredType setOfSetOfString = types.getDeclaredType(setElement, types.getDeclaredType(setElement, stringType));
DeclaredType setOfSetOfSetOfObject = types.getDeclaredType(setElement, setOfSetOfObject);
DeclaredType setOfSetOfSetOfString = types.getDeclaredType(setElement, setOfSetOfString);
WildcardType wildcard = types.getWildcardType(null, null);
DeclaredType containerOfObject = types.getDeclaredType(container, objectType);
DeclaredType containerOfString = types.getDeclaredType(container, stringType);
TypeMirror containedInObject = types.asMemberOf(containerOfObject, contained);
TypeMirror containedInString = types.asMemberOf(containerOfString, contained);
EquivalenceTester<TypeMirror> tester = EquivalenceTester.<TypeMirror>of(MoreTypes.equivalence()).addEquivalenceGroup(types.getNullType()).addEquivalenceGroup(types.getNoType(NONE)).addEquivalenceGroup(types.getNoType(VOID)).addEquivalenceGroup(objectType).addEquivalenceGroup(stringType).addEquivalenceGroup(containedInObject).addEquivalenceGroup(containedInString).addEquivalenceGroup(funkyBounds.asType()).addEquivalenceGroup(funkyBounds2.asType()).addEquivalenceGroup(funkierBounds.asType()).addEquivalenceGroup(funkyBoundsVar, funkyBounds2Var).addEquivalenceGroup(funkierBoundsVar).addEquivalenceGroup(enumElement.asType()).addEquivalenceGroup(mapType).addEquivalenceGroup(mapOfObjectToObjectType).addEquivalenceGroup(types.getDeclaredType(mapElement, wildcard, wildcard)).addEquivalenceGroup(types.erasure(mapType), types.erasure(mapOfObjectToObjectType)).addEquivalenceGroup(types.getDeclaredType(mapElement, objectType, stringType)).addEquivalenceGroup(types.getDeclaredType(mapElement, stringType, objectType)).addEquivalenceGroup(types.getDeclaredType(mapElement, stringType, stringType)).addEquivalenceGroup(setOfSetOfObject).addEquivalenceGroup(setOfSetOfString).addEquivalenceGroup(setOfSetOfSetOfObject).addEquivalenceGroup(setOfSetOfSetOfString).addEquivalenceGroup(wildcard).addEquivalenceGroup(types.getWildcardType(objectType, null)).addEquivalenceGroup(types.getWildcardType(stringType, null)).addEquivalenceGroup(types.getWildcardType(null, stringType)).addEquivalenceGroup(types.getDeclaredType(mapElement, stringType, types.getDeclaredType(mapElement, stringType, types.getDeclaredType(setElement, objectType)))).addEquivalenceGroup(FAKE_ERROR_TYPE);
for (TypeKind kind : TypeKind.values()) {
if (kind.isPrimitive()) {
PrimitiveType primitiveType = types.getPrimitiveType(kind);
TypeMirror boxedPrimitiveType = types.boxedClass(primitiveType).asType();
tester.addEquivalenceGroup(primitiveType, types.unboxedType(boxedPrimitiveType));
tester.addEquivalenceGroup(boxedPrimitiveType);
tester.addEquivalenceGroup(types.getArrayType(primitiveType));
tester.addEquivalenceGroup(types.getArrayType(boxedPrimitiveType));
}
}
ImmutableSet<Class<?>> testClasses = ImmutableSet.of(ExecutableElementsGroupA.class, ExecutableElementsGroupB.class, ExecutableElementsGroupC.class, ExecutableElementsGroupD.class, ExecutableElementsGroupE.class);
for (Class<?> testClass : testClasses) {
ImmutableList<TypeMirror> equivalenceGroup = FluentIterable.from(elements.getTypeElement(testClass.getCanonicalName()).getEnclosedElements()).transform(Element::asType).toList();
tester.addEquivalenceGroup(equivalenceGroup);
}
tester.test();
}
Aggregations