use of javax.lang.model.type.DeclaredType in project auto by google.
the class PropertyBuilderClassifier method makePropertyBuilder.
// Our @AutoValue class `Foo` has a property `Bar bar()` or `Bar getBar()` and we've encountered
// a builder method like `BarBuilder barBuilder()`. Here `BarBuilder` can have any name (its name
// doesn't have to be the name of `Bar` with `Builder` stuck on the end), but `barBuilder()` does
// have to be the name of the property with `Builder` stuck on the end. The requirements for the
// `BarBuilder` type are:
// (1) It must have an instance method called `build()` that returns `Bar`. If the type of
// `bar()` is `Bar<String>` then the type of `build()` must be `Bar<String>`.
// (2) `BarBuilder` must have a public no-arg constructor, or `Bar` must have a static method
// `builder()` or `newBuilder()` that returns `BarBuilder`.
// (3) `Bar` must have an instance method `BarBuilder toBuilder()`, or `BarBuilder` must be a
// Guava immutable builder like `ImmutableSet.Builder`. (See TODO below for relaxing the
// requirement on having a `toBuilder()`.
//
// This method outputs an error and returns Optional.absent() if the barBuilder() method has a
// problem.
Optional<PropertyBuilder> makePropertyBuilder(ExecutableElement method, String property) {
TypeMirror barBuilderTypeMirror = builderMethodClassifier.builderMethodReturnType(method);
if (barBuilderTypeMirror.getKind() != TypeKind.DECLARED) {
errorReporter.reportError("Method looks like a property builder, but its return type " + "is not a class or interface", method);
return Optional.absent();
}
DeclaredType barBuilderDeclaredType = MoreTypes.asDeclared(barBuilderTypeMirror);
TypeElement barBuilderTypeElement = MoreTypes.asTypeElement(barBuilderTypeMirror);
Map<String, ExecutableElement> barBuilderNoArgMethods = noArgMethodsOf(barBuilderTypeElement);
ExecutableElement barGetter = getterToPropertyName.inverse().get(property);
TypeMirror barTypeMirror = barGetter.getReturnType();
if (barTypeMirror.getKind() != TypeKind.DECLARED) {
errorReporter.reportError("Method looks like a property builder, but the type of property " + property + " is not a class or interface", method);
return Optional.absent();
}
if (isNullable(barGetter)) {
errorReporter.reportError("Property " + property + " has a property builder so it cannot " + "be @Nullable", barGetter);
}
TypeElement barTypeElement = MoreTypes.asTypeElement(barTypeMirror);
Map<String, ExecutableElement> barNoArgMethods = noArgMethodsOf(barTypeElement);
// Condition (1), must have build() method returning Bar.
ExecutableElement build = barBuilderNoArgMethods.get("build");
if (build == null || build.getModifiers().contains(Modifier.STATIC)) {
errorReporter.reportError("Method looks like a property builder, but it returns " + barBuilderTypeElement + " which does not have a non-static build() method", method);
return Optional.absent();
}
// We've determined that `BarBuilder` has a method `build()`. But it must return `Bar`.
// And if the type of `bar()` is Bar<String> then `BarBuilder.build()` must return Bar<String>.
TypeMirror buildType = eclipseHack.methodReturnType(build, barBuilderDeclaredType);
if (!MoreTypes.equivalence().equivalent(barTypeMirror, buildType)) {
errorReporter.reportError("Property builder for " + property + " has type " + barBuilderTypeElement + " whose build() method returns " + buildType + " instead of " + barTypeMirror, method);
return Optional.absent();
}
Optional<ExecutableElement> maybeBuilderMaker = builderMaker(barNoArgMethods, barBuilderTypeElement);
if (!maybeBuilderMaker.isPresent()) {
errorReporter.reportError("Method looks like a property builder, but its type " + barBuilderTypeElement + " does not have a public constructor and " + barTypeElement + " does not have a static builder() or newBuilder() method that returns " + barBuilderTypeElement, method);
return Optional.absent();
}
ExecutableElement builderMaker = maybeBuilderMaker.get();
String barBuilderType = typeSimplifier.simplify(barBuilderTypeMirror);
String rawBarType = typeSimplifier.simplifyRaw(barTypeMirror);
String initializer = (builderMaker.getKind() == ElementKind.CONSTRUCTOR) ? "new " + barBuilderType + "()" : rawBarType + "." + builderMaker.getSimpleName() + "()";
String builtToBuilder = null;
String copyAll = null;
ExecutableElement toBuilder = barNoArgMethods.get("toBuilder");
if (toBuilder != null && !toBuilder.getModifiers().contains(Modifier.STATIC) && typeUtils.isAssignable(typeUtils.erasure(toBuilder.getReturnType()), typeUtils.erasure(barBuilderTypeMirror))) {
builtToBuilder = toBuilder.getSimpleName().toString();
} else {
boolean isGuavaBuilder = barBuilderTypeMirror.toString().startsWith(COM_GOOGLE_COMMON_COLLECT_IMMUTABLE) && barBuilderType.contains(".Builder<");
Optional<ExecutableElement> maybeCopyAll = addAllPutAll(barBuilderTypeElement);
if (maybeCopyAll.isPresent() && isGuavaBuilder) {
copyAll = maybeCopyAll.get().getSimpleName().toString();
}
}
ExecutableElement barOf = barNoArgMethods.get("of");
boolean hasOf = (barOf != null && barOf.getModifiers().contains(Modifier.STATIC));
// An expression (initDefault) to make a default one of these, plus optionally a statement
// (beforeInitDefault) that prepares the expression. For a collection, beforeInitDefault is
// empty and initDefault is (e.g.) `ImmutableList.of()`. For a nested value type,
// beforeInitDefault is (e.g.)
// `NestedAutoValueType.Builder foo$builder = NestedAutoValueType.builder();`
// and initDefault is `foo$builder.build();`. The reason for the separate statement is to
// exploit type inference rather than having to write `NestedAutoValueType.<Bar>build();`.
String beforeInitDefault;
String initDefault;
if (hasOf) {
beforeInitDefault = "";
initDefault = rawBarType + ".of()";
} else {
String localBuilder = property + "$builder";
beforeInitDefault = barBuilderType + " " + localBuilder + " = " + initializer + ";";
initDefault = localBuilder + ".build()";
}
PropertyBuilder propertyBuilder = new PropertyBuilder(method, barBuilderType, initializer, beforeInitDefault, initDefault, builtToBuilder, copyAll);
return Optional.of(propertyBuilder);
}
use of javax.lang.model.type.DeclaredType in project auto by google.
the class AutoAnnotationProcessor method wrapperTypesUsedInCollections.
/**
* Returns the wrapper types ({@code Integer.class} etc) that are used in collection parameters
* like {@code List<Integer>}. This is needed because we will emit a helper method for each such
* type, for example to convert {@code Collection<Integer>} into {@code int[]}.
*/
private Set<Class<?>> wrapperTypesUsedInCollections(ExecutableElement method) {
TypeElement javaUtilCollection = processingEnv.getElementUtils().getTypeElement(Collection.class.getName());
ImmutableSet.Builder<Class<?>> usedInCollections = ImmutableSet.builder();
for (Class<?> wrapper : Primitives.allWrapperTypes()) {
DeclaredType collectionOfWrapper = typeUtils.getDeclaredType(javaUtilCollection, getTypeMirror(wrapper));
for (VariableElement parameter : method.getParameters()) {
if (typeUtils.isAssignable(parameter.asType(), collectionOfWrapper)) {
usedInCollections.add(wrapper);
break;
}
}
}
return usedInCollections.build();
}
use of javax.lang.model.type.DeclaredType in project auto by google.
the class AutoServiceProcessor method processAnnotations.
private void processAnnotations(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(AutoService.class);
log(annotations.toString());
log(elements.toString());
for (Element e : elements) {
// TODO(gak): check for error trees?
TypeElement providerImplementer = (TypeElement) e;
AnnotationMirror providerAnnotation = getAnnotationMirror(e, AutoService.class).get();
DeclaredType providerInterface = getProviderInterface(providerAnnotation);
TypeElement providerType = (TypeElement) providerInterface.asElement();
log("provider interface: " + providerType.getQualifiedName());
log("provider implementer: " + providerImplementer.getQualifiedName());
if (!checkImplementer(providerImplementer, providerType)) {
String message = "ServiceProviders must implement their service provider interface. " + providerImplementer.getQualifiedName() + " does not implement " + providerType.getQualifiedName();
error(message, e, providerAnnotation);
}
String providerTypeName = getBinaryName(providerType);
String providerImplementerName = getBinaryName(providerImplementer);
log("provider interface binary name: " + providerTypeName);
log("provider implementer binary name: " + providerImplementerName);
providers.put(providerTypeName, providerImplementerName);
}
}
use of javax.lang.model.type.DeclaredType in project j2objc by google.
the class AbstractMethodRewriter method addReturnTypeNarrowingDeclarations.
// Adds declarations for any methods where the known return type is more
// specific than what is already declared in inherited types.
private void addReturnTypeNarrowingDeclarations(AbstractTypeDeclaration node) {
TypeElement type = node.getTypeElement();
// No need to run this if the entire class is dead.
if (deadCodeMap != null && deadCodeMap.containsClass(type, elementUtil)) {
return;
}
Map<String, ExecutablePair> newDeclarations = new HashMap<>();
Map<String, TypeMirror> resolvedReturnTypes = new HashMap<>();
for (DeclaredType inheritedType : typeUtil.getObjcOrderedInheritedTypes(type.asType())) {
TypeElement inheritedElem = (TypeElement) inheritedType.asElement();
for (ExecutableElement methodElem : ElementUtil.getMethods(inheritedElem)) {
if (ElementUtil.isPrivate(methodElem)) {
continue;
}
TypeMirror declaredReturnType = typeUtil.erasure(methodElem.getReturnType());
if (!TypeUtil.isReferenceType(declaredReturnType)) {
// Short circuit
continue;
}
String selector = nameTable.getMethodSelector(methodElem);
ExecutableType methodType = typeUtil.asMemberOf(inheritedType, methodElem);
TypeMirror returnType = typeUtil.erasure(methodType.getReturnType());
TypeMirror resolvedReturnType = resolvedReturnTypes.get(selector);
if (resolvedReturnType == null) {
resolvedReturnType = declaredReturnType;
resolvedReturnTypes.put(selector, resolvedReturnType);
} else if (!typeUtil.isSubtype(returnType, resolvedReturnType)) {
continue;
}
if (resolvedReturnType != returnType && !nameTable.getObjCType(resolvedReturnType).equals(nameTable.getObjCType(returnType))) {
newDeclarations.put(selector, new ExecutablePair(methodElem, methodType));
resolvedReturnTypes.put(selector, returnType);
}
}
}
for (Map.Entry<String, ExecutablePair> newDecl : newDeclarations.entrySet()) {
if (deadCodeMap != null && deadCodeMap.containsMethod(newDecl.getValue().element(), typeUtil)) {
continue;
}
node.addBodyDeclaration(newReturnTypeNarrowingDeclaration(newDecl.getKey(), newDecl.getValue(), type));
}
}
use of javax.lang.model.type.DeclaredType in project j2objc by google.
the class TreeConverter method addImplicitSuperCall.
private static void addImplicitSuperCall(MethodDeclaration node) {
ExecutableElement method = node.getExecutableElement();
DeclaredType superType = (DeclaredType) ElementUtil.getDeclaringClass(method).getSuperclass();
TypeElement superClass = TypeUtil.asTypeElement(superType);
ExecutableElement superConstructor = findDefaultConstructorElement(superClass);
SuperConstructorInvocation invocation = new SuperConstructorInvocation(new ExecutablePair(superConstructor, (ExecutableType) JdtTypes.asMemberOfInternal(superType, superConstructor))).setVarargsType(getVarargsType(BindingConverter.unwrapExecutableElement(superConstructor), Collections.emptyList()));
node.getBody().addStatement(0, invocation);
}
Aggregations