Search in sources :

Example 81 with Types

use of javax.lang.model.util.Types in project auto by google.

the class TypeVariables method rewriteReturnTypes.

/**
 * Returns a map from methods to return types, where the return types are not necessarily the
 * original return types of the methods. Consider this example:
 *
 * <pre>
 * &#64;AutoValue class {@code Foo<T>} {
 *   abstract T getFoo();
 *
 *   &#64;AutoValue.Builder
 *   abstract class {@code Builder<T>} {
 *     abstract Builder setFoo(T t);
 *     abstract {@code Foo<T>} build();
 *   }
 * }
 * </pre>
 *
 * We want to be able to check that the parameter type of {@code setFoo} is the same as the return
 * type of {@code getFoo}. But in fact it isn't, because the {@code T} of {@code Foo<T>} is not
 * the same as the {@code T} of {@code Foo.Builder<T>}. So we create a parallel {@code Foo<T>}
 * where the {@code T} <i>is</i> the one from {@code Foo.Builder<T>}. That way the types do
 * correspond. This method then returns the return types of the given methods as they appear in
 * that parallel class, meaning the type given for {@code getFoo()} is the {@code T} of {@code
 * Foo.Builder<T>}.
 *
 * <p>We do the rewrite this way around (applying the type parameter from {@code Foo.Builder} to
 * {@code Foo}) because if we hit one of the historical Eclipse bugs with {@link Types#asMemberOf}
 * then {@link EclipseHack#methodReturnType} can use fallback logic, which only works for methods
 * with no arguments.
 *
 * @param methods the methods whose return types are to be rewritten.
 * @param sourceType the class containing those methods ({@code Foo} in the example).
 * @param targetType the class to translate the methods into ({@code Foo.Builder<T>}) in the
 *     example.
 */
static ImmutableMap<ExecutableElement, TypeMirror> rewriteReturnTypes(Elements elementUtils, Types typeUtils, Collection<ExecutableElement> methods, TypeElement sourceType, TypeElement targetType) {
    List<? extends TypeParameterElement> sourceTypeParameters = sourceType.getTypeParameters();
    List<? extends TypeParameterElement> targetTypeParameters = targetType.getTypeParameters();
    Preconditions.checkArgument(sourceTypeParameters.toString().equals(targetTypeParameters.toString()), "%s != %s", sourceTypeParameters, targetTypeParameters);
    // What we're doing is only valid if the type parameters are "the same". The check here even
    // requires the names to be the same. The logic would still work without that, but we impose
    // that requirement elsewhere and it means we can check in this simple way.
    EclipseHack eclipseHack = new EclipseHack(elementUtils, typeUtils);
    TypeMirror[] targetTypeParameterMirrors = new TypeMirror[targetTypeParameters.size()];
    for (int i = 0; i < targetTypeParameters.size(); i++) {
        targetTypeParameterMirrors[i] = targetTypeParameters.get(i).asType();
    }
    DeclaredType parallelSource = typeUtils.getDeclaredType(sourceType, targetTypeParameterMirrors);
    return methods.stream().collect(toImmutableMap(m -> m, m -> eclipseHack.methodReturnType(m, parallelSource)));
}
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) TypeMirror(javax.lang.model.type.TypeMirror) DeclaredType(javax.lang.model.type.DeclaredType)

Example 82 with Types

use of javax.lang.model.util.Types 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 83 with Types

use of javax.lang.model.util.Types in project auto by google.

the class MoreElementsTest method getMethod.

private ExecutableElement getMethod(Class<?> c, String methodName, TypeMirror... parameterTypes) {
    TypeElement type = elements.getTypeElement(c.getCanonicalName());
    Types types = compilation.getTypes();
    ExecutableElement found = null;
    for (ExecutableElement method : ElementFilter.methodsIn(type.getEnclosedElements())) {
        if (method.getSimpleName().contentEquals(methodName) && method.getParameters().size() == parameterTypes.length) {
            boolean match = true;
            for (int i = 0; i < parameterTypes.length; i++) {
                TypeMirror expectedType = parameterTypes[i];
                TypeMirror actualType = method.getParameters().get(i).asType();
                match &= types.isSameType(expectedType, actualType);
            }
            if (match) {
                assertThat(found).isNull();
                found = method;
            }
        }
    }
    assertWithMessage(methodName + Arrays.toString(parameterTypes)).that(found).isNotNull();
    return requireNonNull(found);
}
Also used : Types(javax.lang.model.util.Types) TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement)

Example 84 with Types

use of javax.lang.model.util.Types in project auto by google.

the class MoreElementsTest method getLocalAndInheritedMethods.

@Test
public void getLocalAndInheritedMethods() {
    Types types = compilation.getTypes();
    TypeMirror intMirror = types.getPrimitiveType(TypeKind.INT);
    TypeMirror longMirror = types.getPrimitiveType(TypeKind.LONG);
    TypeElement childType = elements.getTypeElement(Child.class.getCanonicalName());
    @SuppressWarnings("deprecation") Set<ExecutableElement> childTypeMethods = MoreElements.getLocalAndInheritedMethods(childType, types, elements);
    Set<ExecutableElement> objectMethods = visibleMethodsFromObject();
    assertThat(childTypeMethods).containsAtLeastElementsIn(objectMethods);
    Set<ExecutableElement> nonObjectMethods = Sets.difference(childTypeMethods, objectMethods);
    assertThat(nonObjectMethods).containsExactly(getMethod(ParentInterface.class, "bar", longMirror), getMethod(ParentClass.class, "foo"), getMethod(Child.class, "bar"), getMethod(Child.class, "baz"), getMethod(Child.class, "buh", intMirror), getMethod(Child.class, "buh", intMirror, intMirror)).inOrder();
}
Also used : Types(javax.lang.model.util.Types) TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Test(org.junit.Test)

Example 85 with Types

use of javax.lang.model.util.Types in project auto by google.

the class MoreElementsTest method allMethodsFromObject.

private Set<ExecutableElement> allMethodsFromObject() {
    Types types = compilation.getTypes();
    TypeMirror intMirror = types.getPrimitiveType(TypeKind.INT);
    TypeMirror longMirror = types.getPrimitiveType(TypeKind.LONG);
    Set<ExecutableElement> methods = new HashSet<>();
    methods.addAll(ElementFilter.methodsIn(objectElement.getEnclosedElements()));
    assertThat(methods).containsAtLeast(getMethod(Object.class, "clone"), getMethod(Object.class, "registerNatives"), getMethod(Object.class, "finalize"), getMethod(Object.class, "wait"), getMethod(Object.class, "wait", longMirror), getMethod(Object.class, "wait", longMirror, intMirror));
    return methods;
}
Also used : Types(javax.lang.model.util.Types) TypeMirror(javax.lang.model.type.TypeMirror) ExecutableElement(javax.lang.model.element.ExecutableElement) HashSet(java.util.HashSet)

Aggregations

Types (javax.lang.model.util.Types)113 TypeMirror (javax.lang.model.type.TypeMirror)77 TypeElement (javax.lang.model.element.TypeElement)52 Elements (javax.lang.model.util.Elements)48 ExecutableElement (javax.lang.model.element.ExecutableElement)34 Element (javax.lang.model.element.Element)30 SupportedAnnotationTypes (javax.annotation.processing.SupportedAnnotationTypes)27 DeclaredType (javax.lang.model.type.DeclaredType)26 ArrayList (java.util.ArrayList)25 Map (java.util.Map)24 VariableElement (javax.lang.model.element.VariableElement)24 List (java.util.List)21 AnnotationMirror (javax.lang.model.element.AnnotationMirror)20 TypeKind (javax.lang.model.type.TypeKind)18 Set (java.util.Set)16 Collection (java.util.Collection)15 HashMap (java.util.HashMap)13 ElementKind (javax.lang.model.element.ElementKind)13 Modifier (javax.lang.model.element.Modifier)13 IOException (java.io.IOException)12