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>
* @AutoValue class {@code Foo<T>} {
* abstract T getFoo();
*
* @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)));
}
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);
}
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);
}
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();
}
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;
}
Aggregations