Search in sources :

Example 26 with WildcardType

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);
}
Also used : ArrayType(javax.lang.model.type.ArrayType) MoreElements(com.google.auto.common.MoreElements) SimpleTypeVisitor8(javax.lang.model.util.SimpleTypeVisitor8) MoreTypes(com.google.auto.common.MoreTypes) Equivalence(com.google.common.base.Equivalence) ImmutableMap(com.google.common.collect.ImmutableMap) Modifier(javax.lang.model.element.Modifier) Collection(java.util.Collection) ExecutableElement(javax.lang.model.element.ExecutableElement) MoreStreams.toImmutableMap(com.google.auto.common.MoreStreams.toImmutableMap) TypeElement(javax.lang.model.element.TypeElement) Types(javax.lang.model.util.Types) Function(java.util.function.Function) Elements(javax.lang.model.util.Elements) TypeParameterElement(javax.lang.model.element.TypeParameterElement) TypeKind(javax.lang.model.type.TypeKind) LinkedHashMap(java.util.LinkedHashMap) List(java.util.List) TypeMirror(javax.lang.model.type.TypeMirror) Map(java.util.Map) DeclaredType(javax.lang.model.type.DeclaredType) TypeVariable(javax.lang.model.type.TypeVariable) Preconditions(com.google.common.base.Preconditions) WildcardType(javax.lang.model.type.WildcardType) WildcardType(javax.lang.model.type.WildcardType) TypeMirror(javax.lang.model.type.TypeMirror) TypeVariable(javax.lang.model.type.TypeVariable) LinkedHashMap(java.util.LinkedHashMap)

Example 27 with WildcardType

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));
}
Also used : Types(javax.lang.model.util.Types) WildcardType(javax.lang.model.type.WildcardType) TypeMirror(javax.lang.model.type.TypeMirror) PrimitiveType(javax.lang.model.type.PrimitiveType) Test(org.junit.Test)

Example 28 with 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();
}
Also used : Types(javax.lang.model.util.Types) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) TypeElement(javax.lang.model.element.TypeElement) TypeKind(javax.lang.model.type.TypeKind) Elements(javax.lang.model.util.Elements) WildcardType(javax.lang.model.type.WildcardType) TypeMirror(javax.lang.model.type.TypeMirror) PrimitiveType(javax.lang.model.type.PrimitiveType) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) DeclaredType(javax.lang.model.type.DeclaredType) Test(org.junit.Test)

Aggregations

WildcardType (javax.lang.model.type.WildcardType)28 TypeMirror (javax.lang.model.type.TypeMirror)12 Test (org.junit.Test)9 DeclaredType (javax.lang.model.type.DeclaredType)8 Elements (javax.lang.model.util.Elements)7 TypeVariable (javax.lang.model.type.TypeVariable)6 ArrayType (javax.lang.model.type.ArrayType)5 Types (javax.lang.model.util.Types)5 Type (com.sun.tools.javac.code.Type)3 JavacProcessingEnvironment (com.sun.tools.javac.processing.JavacProcessingEnvironment)3 TypeElement (javax.lang.model.element.TypeElement)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 Types (com.sun.tools.javac.code.Types)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 PrimitiveType (javax.lang.model.type.PrimitiveType)2 TypeKind (javax.lang.model.type.TypeKind)2 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)2 AnnotatedWildcardType (org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedWildcardType)2 MoreElements (com.google.auto.common.MoreElements)1