Skip to content

Commit

Permalink
Migrate ComponentDescriptorFactory to XProcessing.
Browse files Browse the repository at this point in the history
RELNOTES=N/A
PiperOrigin-RevId: 404635165
  • Loading branch information
bcorso authored and Dagger Team committed Oct 20, 2021
1 parent e1da8e2 commit 8a4a277
Show file tree
Hide file tree
Showing 13 changed files with 150 additions and 118 deletions.
7 changes: 6 additions & 1 deletion java/dagger/internal/codegen/base/ComponentAnnotation.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private ClassName annotationClassName() {
* Returns an object representing a root component annotation, not a subcomponent annotation, if
* one is present on {@code typeElement}.
*/
public static Optional<ComponentAnnotation> rootComponentAnnotation(TypeElement typeElement) {
public static Optional<ComponentAnnotation> rootComponentAnnotation(XTypeElement typeElement) {
return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS);
}

Expand Down Expand Up @@ -212,6 +212,11 @@ public static Optional<ComponentAnnotation> anyComponentAnnotation(XElement elem
return anyComponentAnnotation(toJavac(element), ALL_COMPONENT_ANNOTATIONS);
}

private static Optional<ComponentAnnotation> anyComponentAnnotation(
XElement element, Collection<ClassName> annotations) {
return anyComponentAnnotation(toJavac(element), annotations);
}

private static Optional<ComponentAnnotation> anyComponentAnnotation(
Element element, Collection<ClassName> annotations) {
return getAnyAnnotation(element, annotations).map(ComponentAnnotation::componentAnnotation);
Expand Down
7 changes: 6 additions & 1 deletion java/dagger/internal/codegen/base/ModuleAnnotation.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ public abstract class ModuleAnnotation {

/** The simple name of the annotation. */
public String annotationName() {
return annotation().getAnnotationType().asElement().getSimpleName().toString();
return className().simpleName();
}

/** Returns the {@link ClassName} name of the annotation. */
public ClassName className() {
return ClassName.get(asTypeElement(annotation().getAnnotationType()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package dagger.internal.codegen.binding;

import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.collect.Sets.immutableEnumSet;
import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
Expand Down Expand Up @@ -102,7 +103,7 @@ public String format(BindingDeclaration bindingDeclaration) {
private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
ImmutableList<TypeElement> moduleSubcomponents =
subcomponentDeclaration.moduleAnnotation().subcomponents();
int index = moduleSubcomponents.indexOf(subcomponentDeclaration.subcomponentType());
int index = moduleSubcomponents.indexOf(toJavac(subcomponentDeclaration.subcomponentType()));
StringBuilder annotationValue = new StringBuilder();
if (moduleSubcomponents.size() != 1) {
annotationValue.append("{");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package dagger.internal.codegen.binding;

import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.isAnnotationPresent;
import static com.google.auto.common.MoreTypes.asDeclared;
import static com.google.auto.common.MoreTypes.asTypeElement;
Expand All @@ -25,6 +26,7 @@
import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;

import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreTypes;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
Expand Down Expand Up @@ -155,10 +157,11 @@ final Element elementForRequirement(ComponentRequirement requirement) {

/** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */
public static ComponentCreatorDescriptor create(
TypeElement typeElement,
XTypeElement xTypeElement,
DaggerElements elements,
DaggerTypes types,
DependencyRequestFactory dependencyRequestFactory) {
TypeElement typeElement = toJavac(xTypeElement);
TypeMirror componentType = typeElement.getEnclosingElement().asType();

ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods =
Expand Down
6 changes: 4 additions & 2 deletions java/dagger/internal/codegen/binding/ComponentDescriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package dagger.internal.codegen.binding;

import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
Expand All @@ -26,6 +27,7 @@
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.type.TypeKind.VOID;

import androidx.room.compiler.processing.XMethodElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Supplier;
Expand Down Expand Up @@ -357,9 +359,9 @@ public TypeMirror resolvedReturnType(DaggerTypes types) {
}

/** A {@link ComponentMethodDescriptor}builder for a method. */
public static Builder builder(ExecutableElement method) {
public static Builder builder(XMethodElement method) {
return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder()
.methodElement(method);
.methodElement(toJavac(method));
}

/** A builder of {@link ComponentMethodDescriptor}s. */
Expand Down
146 changes: 60 additions & 86 deletions java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,29 @@

package dagger.internal.codegen.binding;

import static androidx.room.compiler.processing.XTypeKt.isVoid;
import static androidx.room.compiler.processing.compat.XConverters.toJavac;
import static com.google.auto.common.MoreElements.asType;
import static com.google.auto.common.MoreTypes.asTypeElement;
import static androidx.room.compiler.processing.compat.XConverters.toXProcessing;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotation;
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
import static dagger.internal.codegen.base.Scopes.productionScope;
import static dagger.internal.codegen.base.Scopes.scopesOf;
import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.creatorAnnotationsFor;
import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentContributionMethod;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.lang.model.type.TypeKind.DECLARED;
import static javax.lang.model.type.TypeKind.VOID;
import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static javax.lang.model.util.ElementFilter.methodsIn;

import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XMethodType;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableBiMap;
Expand All @@ -46,12 +51,9 @@
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.spi.model.Scope;
import java.util.Optional;
import java.util.function.Function;
import javax.inject.Inject;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;

/** A factory for {@link ComponentDescriptor}s. */
public final class ComponentDescriptorFactory {
Expand Down Expand Up @@ -79,59 +81,31 @@ public final class ComponentDescriptorFactory {
}

/** Returns a descriptor for a root component type. */
public ComponentDescriptor rootComponentDescriptor(XTypeElement xTypeElement) {
return rootComponentDescriptor(toJavac(xTypeElement));
}

/** Returns a descriptor for a root component type. */
public ComponentDescriptor rootComponentDescriptor(TypeElement typeElement) {
return create(
typeElement,
checkAnnotation(
typeElement,
ComponentAnnotation::rootComponentAnnotation,
"must have a component annotation"));
}

public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) {
return subcomponentDescriptor(toJavac(typeElement));
public ComponentDescriptor rootComponentDescriptor(XTypeElement typeElement) {
Optional<ComponentAnnotation> annotation = rootComponentAnnotation(typeElement);
checkArgument(annotation.isPresent(), "%s must have a component annotation", typeElement);
return create(typeElement, annotation.get());
}

/** Returns a descriptor for a subcomponent type. */
private ComponentDescriptor subcomponentDescriptor(TypeElement typeElement) {
return create(
typeElement,
checkAnnotation(
typeElement,
ComponentAnnotation::subcomponentAnnotation,
"must have a subcomponent annotation"));
public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) {
Optional<ComponentAnnotation> annotation = subcomponentAnnotation(typeElement);
checkArgument(annotation.isPresent(), "%s must have a subcomponent annotation", typeElement);
return create(typeElement, annotation.get());
}

/**
* Returns a descriptor for a fictional component based on a module type in order to validate its
* bindings.
*/
public ComponentDescriptor moduleComponentDescriptor(XTypeElement typeElement) {
return create(
toJavac(typeElement),
ComponentAnnotation.fromModuleAnnotation(
checkAnnotation(
toJavac(typeElement),
ModuleAnnotation::moduleAnnotation,
"must have a module annotation")));
}

private static <A> A checkAnnotation(
TypeElement typeElement,
Function<TypeElement, Optional<A>> annotationFunction,
String message) {
return annotationFunction
.apply(typeElement)
.orElseThrow(() -> new IllegalArgumentException(typeElement + " " + message));
Optional<ModuleAnnotation> annotation = moduleAnnotation(typeElement);
checkArgument(annotation.isPresent(), "%s must have a module annotation", typeElement);
return create(typeElement, ComponentAnnotation.fromModuleAnnotation(annotation.get()));
}

private ComponentDescriptor create(
TypeElement typeElement, ComponentAnnotation componentAnnotation) {
XTypeElement typeElement, ComponentAnnotation componentAnnotation) {
ImmutableSet<ComponentRequirement> componentDependencies =
componentAnnotation.dependencyTypes().stream()
.map(ComponentRequirement::forDependency)
Expand All @@ -151,21 +125,22 @@ private ComponentDescriptor create(

// Start with the component's modules. For fictional components built from a module, start with
// that module.
ImmutableSet<TypeElement> modules =
ImmutableSet<XTypeElement> modules =
componentAnnotation.isRealComponent()
? componentAnnotation.modules()
? componentAnnotation.modules().stream()
.map(module -> toXProcessing(module, processingEnv))
.collect(toImmutableSet())
: ImmutableSet.of(typeElement);

ImmutableSet<ModuleDescriptor> transitiveModules =
moduleDescriptorFactory.transitiveModules(modules);

ImmutableSet.Builder<ComponentDescriptor> subcomponentsFromModules = ImmutableSet.builder();
for (ModuleDescriptor module : transitiveModules) {
for (SubcomponentDeclaration subcomponentDeclaration : module.subcomponentDeclarations()) {
TypeElement subcomponent = subcomponentDeclaration.subcomponentType();
subcomponentsFromModules.add(subcomponentDescriptor(subcomponent));
}
}
ImmutableSet<ComponentDescriptor> subcomponentsFromModules =
transitiveModules.stream()
.flatMap(transitiveModule -> transitiveModule.subcomponentDeclarations().stream())
.map(SubcomponentDeclaration::subcomponentType)
.map(this::subcomponentDescriptor)
.collect(toImmutableSet());

ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
ImmutableSet.builder();
Expand All @@ -174,11 +149,9 @@ private ComponentDescriptor create(
ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor>
subcomponentsByBuilderMethod = ImmutableBiMap.builder();
if (componentAnnotation.isRealComponent()) {
ImmutableSet<ExecutableElement> unimplementedMethods =
elements.getUnimplementedMethods(typeElement);
for (ExecutableElement componentMethod : unimplementedMethods) {
for (XMethodElement componentMethod : getAllUnimplementedMethods(typeElement)) {
ComponentMethodDescriptor componentMethodDescriptor =
getDescriptorForComponentMethod(typeElement, componentAnnotation, componentMethod);
getDescriptorForComponentMethod(componentAnnotation, typeElement, componentMethod);
componentMethodsBuilder.add(componentMethodDescriptor);
componentMethodDescriptor
.subcomponent()
Expand All @@ -196,7 +169,7 @@ private ComponentDescriptor create(
}

// Validation should have ensured that this set will have at most one element.
ImmutableSet<TypeElement> enclosedCreators =
ImmutableSet<XTypeElement> enclosedCreators =
enclosedAnnotatedTypes(typeElement, creatorAnnotationsFor(componentAnnotation));
Optional<ComponentCreatorDescriptor> creatorDescriptor =
enclosedCreators.isEmpty()
Expand All @@ -208,75 +181,76 @@ private ComponentDescriptor create(
ImmutableSet<Scope> scopes = scopesOf(typeElement);
if (componentAnnotation.isProduction()) {
scopes =
ImmutableSet.<Scope>builder()
.addAll(scopes)
.add(productionScope(processingEnv))
.build();
ImmutableSet.<Scope>builder().addAll(scopes).add(productionScope(processingEnv)).build();
}

return ComponentDescriptor.create(
componentAnnotation,
typeElement,
toJavac(typeElement),
componentDependencies,
transitiveModules,
dependenciesByDependencyMethod.build(),
scopes,
subcomponentsFromModules.build(),
subcomponentsFromModules,
subcomponentsByFactoryMethod.build(),
subcomponentsByBuilderMethod.build(),
componentMethodsBuilder.build(),
creatorDescriptor);
}

private ComponentMethodDescriptor getDescriptorForComponentMethod(
TypeElement componentElement,
ComponentAnnotation componentAnnotation,
ExecutableElement componentMethod) {
XTypeElement componentElement,
XMethodElement componentMethod) {
ComponentMethodDescriptor.Builder descriptor =
ComponentMethodDescriptor.builder(componentMethod);

ExecutableType resolvedComponentMethod =
MoreTypes.asExecutable(
types.asMemberOf(MoreTypes.asDeclared(componentElement.asType()), componentMethod));
TypeMirror returnType = resolvedComponentMethod.getReturnType();
if (returnType.getKind().equals(DECLARED)
&& !injectionAnnotations.getQualifier(componentMethod).isPresent()) {
TypeElement returnTypeElement = asTypeElement(returnType);
XMethodType resolvedComponentMethod = componentMethod.asMemberOf(componentElement.getType());
XType returnType = resolvedComponentMethod.getReturnType();
if (isDeclared(returnType) && !injectionAnnotations.getQualifier(componentMethod).isPresent()) {
XTypeElement returnTypeElement = returnType.getTypeElement();
if (subcomponentAnnotation(returnTypeElement).isPresent()) {
// It's a subcomponent factory method. There is no dependency request, and there could be
// any number of parameters. Just return the descriptor.
return descriptor.subcomponent(subcomponentDescriptor(returnTypeElement)).build();
}
if (isSubcomponentCreator(returnTypeElement)) {
descriptor.subcomponent(
subcomponentDescriptor(asType(returnTypeElement.getEnclosingElement())));
subcomponentDescriptor(returnTypeElement.getEnclosingTypeElement()));
}
}

// TODO(bcorso): Add an XConverters.toJavac() method to convert between XMethodType and
// ExecutableType so that we don't have to recalculate the method type for cases like this.
ExecutableType javaResolvedComponentMethod =
MoreTypes.asExecutable(
types.asMemberOf(
MoreTypes.asDeclared(toJavac(componentElement.getType())),
toJavac(componentMethod)));
switch (componentMethod.getParameters().size()) {
case 0:
checkArgument(
!returnType.getKind().equals(VOID),
"component method cannot be void: %s",
componentMethod);
checkArgument(!isVoid(returnType), "component method cannot be void: %s", componentMethod);
descriptor.dependencyRequest(
componentAnnotation.isProduction()
? dependencyRequestFactory.forComponentProductionMethod(
componentMethod, resolvedComponentMethod)
componentMethod, javaResolvedComponentMethod)
: dependencyRequestFactory.forComponentProvisionMethod(
componentMethod, resolvedComponentMethod));
componentMethod, javaResolvedComponentMethod));
break;

case 1:
checkArgument(
returnType.getKind().equals(VOID)
isVoid(returnType)
// TODO(bcorso): Replace this with isSameType()?
|| MoreTypes.equivalence()
.equivalent(returnType, resolvedComponentMethod.getParameterTypes().get(0)),
.equivalent(
toJavac(returnType),
javaResolvedComponentMethod.getParameterTypes().get(0)),
"members injection method must return void or parameter type: %s",
componentMethod);
descriptor.dependencyRequest(
dependencyRequestFactory.forComponentMembersInjectionMethod(
componentMethod, resolvedComponentMethod));
componentMethod, javaResolvedComponentMethod));
break;

default:
Expand Down
Loading

0 comments on commit 8a4a277

Please sign in to comment.