diff --git a/java/dagger/internal/codegen/binding/CancellationPolicy.java b/java/dagger/internal/codegen/binding/CancellationPolicy.java new file mode 100644 index 00000000000..7be42ffbbe1 --- /dev/null +++ b/java/dagger/internal/codegen/binding/CancellationPolicy.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 The Dagger Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package dagger.internal.codegen.binding; + +import static com.google.common.base.Preconditions.checkArgument; +import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; + +import androidx.room.compiler.processing.XAnnotation; +import dagger.internal.codegen.javapoet.TypeNames; +import dagger.internal.codegen.xprocessing.XAnnotations; + +/** + * The cancellation policy for a {@link dagger.producers.ProductionComponent}. + * + *

@see dagger.producers.CancellationPolicy + */ +public enum CancellationPolicy { + PROPAGATE, + IGNORE; + + static CancellationPolicy from(XAnnotation annotation) { + checkArgument(XAnnotations.getClassName(annotation).equals(TypeNames.CANCELLATION_POLICY)); + return valueOf(getSimpleName(annotation.getAsEnum("fromSubcomponents"))); + } +} diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java index a105608b71d..2e5d6b545d9 100644 --- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java +++ b/java/dagger/internal/codegen/binding/ComponentDescriptor.java @@ -21,14 +21,27 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; +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.ComponentAnnotation.subcomponentAnnotations; +import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor; +import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation; +import static dagger.internal.codegen.base.Scopes.productionScope; +import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes; +import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static dagger.internal.codegen.javapoet.TypeNames.isFutureType; import static dagger.internal.codegen.xprocessing.XElements.getSimpleName; +import static dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods; +import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; -import androidx.room.compiler.processing.XAnnotation; import androidx.room.compiler.processing.XElement; 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.value.AutoValue; import com.google.auto.value.extension.memoized.Memoized; @@ -45,15 +58,18 @@ import dagger.Module; import dagger.Subcomponent; import dagger.internal.codegen.base.ComponentAnnotation; +import dagger.internal.codegen.base.DaggerSuperficialValidation; +import dagger.internal.codegen.base.ModuleAnnotation; import dagger.internal.codegen.javapoet.TypeNames; import dagger.internal.codegen.model.DependencyRequest; import dagger.internal.codegen.model.Scope; -import dagger.internal.codegen.xprocessing.XAnnotations; +import dagger.internal.codegen.xprocessing.XTypeElements; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; +import javax.inject.Inject; /** * A component declaration. @@ -68,52 +84,54 @@ @CheckReturnValue @AutoValue public abstract class ComponentDescriptor { + /** The annotation that specifies that {@link #typeElement()} is a component. */ + public abstract ComponentAnnotation annotation(); + /** - * The cancellation policy for a {@link dagger.producers.ProductionComponent}. - * - *

@see dagger.producers.CancellationPolicy + * The element that defines the component. This is the element to which the {@link #annotation()} + * was applied. */ - public enum CancellationPolicy { - PROPAGATE, - IGNORE; + public abstract XTypeElement typeElement(); - private static CancellationPolicy from(XAnnotation annotation) { - checkArgument(XAnnotations.getClassName(annotation).equals(TypeNames.CANCELLATION_POLICY)); - return valueOf(getSimpleName(annotation.getAsEnum("fromSubcomponents"))); - } - } + /** + * The set of component dependencies listed in {@link Component#dependencies} or {@link + * dagger.producers.ProductionComponent#dependencies()}. + */ + public abstract ImmutableSet dependencies(); - /** Creates a {@link ComponentDescriptor}. */ - static ComponentDescriptor create( - ComponentAnnotation componentAnnotation, - XTypeElement component, - ImmutableSet componentDependencies, - ImmutableSet transitiveModules, - ImmutableMap dependenciesByDependencyMethod, - ImmutableSet scopes, - ImmutableSet subcomponentsFromModules, - ImmutableBiMap subcomponentsByFactoryMethod, - ImmutableBiMap subcomponentsByBuilderMethod, - ImmutableSet componentMethods, - Optional creator) { - ComponentDescriptor descriptor = - new AutoValue_ComponentDescriptor( - componentAnnotation, - component, - componentDependencies, - transitiveModules, - dependenciesByDependencyMethod, - scopes, - subcomponentsFromModules, - subcomponentsByFactoryMethod, - subcomponentsByBuilderMethod, - componentMethods, - creator); - return descriptor; - } + /** + * The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by + * traversing {@link Module#includes()}. + */ + public abstract ImmutableSet modules(); - /** The annotation that specifies that {@link #typeElement()} is a component. */ - public abstract ComponentAnnotation annotation(); + /** The scopes of the component. */ + public abstract ImmutableSet scopes(); + + /** + * All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain + * Module#subcomponents() module's subcomponents}. + */ + abstract ImmutableSet childComponentsDeclaredByModules(); + + /** + * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent + * factory method. + */ + public abstract ImmutableBiMap + childComponentsDeclaredByFactoryMethods(); + + /** + * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent + * builder method. + */ + abstract ImmutableMap + childComponentsDeclaredByBuilderEntryPoints(); + + public abstract ImmutableSet componentMethods(); + + /** Returns a descriptor for the creator type for this component type, if the user defined one. */ + public abstract Optional creatorDescriptor(); /** Returns {@code true} if this is a subcomponent. */ public final boolean isSubcomponent() { @@ -136,18 +154,6 @@ public final boolean isRealComponent() { return annotation().isRealComponent(); } - /** - * The element that defines the component. This is the element to which the {@link #annotation()} - * was applied. - */ - public abstract XTypeElement typeElement(); - - /** - * The set of component dependencies listed in {@link Component#dependencies} or {@link - * dagger.producers.ProductionComponent#dependencies()}. - */ - public abstract ImmutableSet dependencies(); - /** The non-abstract {@link #modules()} and the {@link #dependencies()}. */ public final ImmutableSet dependenciesAndConcreteModules() { return Stream.concat( @@ -158,12 +164,6 @@ public final ImmutableSet dependenciesAndConcreteModules() .collect(toImmutableSet()); } - /** - * The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by - * traversing {@link Module#includes()}. - */ - public abstract ImmutableSet modules(); - /** The types of the {@link #modules()}. */ public final ImmutableSet moduleTypes() { return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet()); @@ -198,13 +198,21 @@ ImmutableSet requirements() { } /** - * This component's {@linkplain #dependencies() dependencies} keyed by each provision or - * production method defined by that dependency. Note that the dependencies' types are not simply - * the enclosing type of the method; a method may be declared by a supertype of the actual - * dependency. + * Returns this component's dependencies keyed by its provision/production method. + * + *

Note that the dependencies' types are not simply the enclosing type of the method; a method + * may be declared by a supertype of the actual dependency. */ - public abstract ImmutableMap - dependenciesByDependencyMethod(); + @Memoized + public ImmutableMap dependenciesByDependencyMethod() { + ImmutableMap.Builder builder = ImmutableMap.builder(); + for (ComponentRequirement componentDependency : dependencies()) { + XTypeElements.getAllMethods(componentDependency.typeElement()).stream() + .filter(ComponentDescriptor::isComponentContributionMethod) + .forEach(method -> builder.put(method, componentDependency)); + } + return builder.buildOrThrow(); + } /** The {@linkplain #dependencies() component dependency} that defines a method. */ public final ComponentRequirement getDependencyThatDefinesMethod(XElement method) { @@ -216,9 +224,6 @@ public final ComponentRequirement getDependencyThatDefinesMethod(XElement method return dependenciesByDependencyMethod().get(method); } - /** The scopes of the component. */ - public abstract ImmutableSet scopes(); - /** * All {@link Subcomponent}s which are direct children of this component. This includes * subcomponents installed from {@link Module#subcomponents()} as well as subcomponent {@linkplain @@ -233,19 +238,6 @@ public final ImmutableSet childComponents() { .build(); } - /** - * All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain - * Module#subcomponents() module's subcomponents}. - */ - abstract ImmutableSet childComponentsDeclaredByModules(); - - /** - * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent - * factory method. - */ - public abstract ImmutableBiMap - childComponentsDeclaredByFactoryMethods(); - /** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */ @Memoized public ImmutableMap childComponentsByElement() { @@ -259,13 +251,6 @@ final Optional getFactoryMethodForChildComponent( childComponentsDeclaredByFactoryMethods().inverse().get(childComponent)); } - /** - * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent - * builder method. - */ - abstract ImmutableBiMap - childComponentsDeclaredByBuilderEntryPoints(); - private final Supplier> childComponentsByBuilderType = Suppliers.memoize( @@ -285,8 +270,6 @@ final ComponentDescriptor getChildComponentWithBuilderType(XTypeElement builderT builderType.getQualifiedName()); } - public abstract ImmutableSet componentMethods(); - /** Returns the first component method associated with this binding request, if one exists. */ public Optional firstMatchingComponentMethod(BindingRequest request) { return Optional.ofNullable(firstMatchingComponentMethods().get(request)); @@ -308,11 +291,6 @@ public final ImmutableSet entryPointMethods() { .collect(toImmutableSet()); } - // TODO(gak): Consider making this non-optional and revising the - // interaction between the spec & generation - /** Returns a descriptor for the creator type for this component type, if the user defined one. */ - public abstract Optional creatorDescriptor(); - /** * Returns {@code true} for components that have a creator, either because the user {@linkplain * #creatorDescriptor() specified one} or because it's a top-level component with an implicit @@ -408,4 +386,191 @@ static boolean isComponentContributionMethod(XMethodElement method) { static boolean isComponentProductionMethod(XMethodElement method) { return isComponentContributionMethod(method) && isFutureType(method.getReturnType()); } + + /** A factory for creating a {@link ComponentDescriptor}. */ + public static final class Factory { + private final XProcessingEnv processingEnv; + private final DependencyRequestFactory dependencyRequestFactory; + private final ModuleDescriptor.Factory moduleDescriptorFactory; + private final InjectionAnnotations injectionAnnotations; + private final DaggerSuperficialValidation superficialValidation; + + @Inject + Factory( + XProcessingEnv processingEnv, + DependencyRequestFactory dependencyRequestFactory, + ModuleDescriptor.Factory moduleDescriptorFactory, + InjectionAnnotations injectionAnnotations, + DaggerSuperficialValidation superficialValidation) { + this.processingEnv = processingEnv; + this.dependencyRequestFactory = dependencyRequestFactory; + this.moduleDescriptorFactory = moduleDescriptorFactory; + this.injectionAnnotations = injectionAnnotations; + this.superficialValidation = superficialValidation; + } + + /** Returns a descriptor for a root component type. */ + public ComponentDescriptor rootComponentDescriptor(XTypeElement typeElement) { + Optional annotation = + rootComponentAnnotation(typeElement, superficialValidation); + checkArgument(annotation.isPresent(), "%s must have a component annotation", typeElement); + return create(typeElement, annotation.get()); + } + + /** Returns a descriptor for a subcomponent type. */ + public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) { + Optional annotation = + subcomponentAnnotation(typeElement, superficialValidation); + 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) { + Optional annotation = moduleAnnotation(typeElement, superficialValidation); + checkArgument(annotation.isPresent(), "%s must have a module annotation", typeElement); + return create(typeElement, ComponentAnnotation.fromModuleAnnotation(annotation.get())); + } + + private ComponentDescriptor create( + XTypeElement typeElement, ComponentAnnotation componentAnnotation) { + ImmutableSet componentDependencies = + componentAnnotation.dependencyTypes().stream() + .map(ComponentRequirement::forDependency) + .collect(toImmutableSet()); + + // Start with the component's modules. For fictional components built from a module, start + // with that module. + ImmutableSet modules = + componentAnnotation.isRealComponent() + ? componentAnnotation.modules() + : ImmutableSet.of(typeElement); + + ImmutableSet transitiveModules = + moduleDescriptorFactory.transitiveModules(modules); + + ImmutableSet.Builder componentMethodsBuilder = + ImmutableSet.builder(); + ImmutableBiMap.Builder + subcomponentsByFactoryMethod = ImmutableBiMap.builder(); + ImmutableMap.Builder + subcomponentsByBuilderMethod = ImmutableBiMap.builder(); + if (componentAnnotation.isRealComponent()) { + for (XMethodElement componentMethod : getAllUnimplementedMethods(typeElement)) { + ComponentMethodDescriptor componentMethodDescriptor = + getDescriptorForComponentMethod(componentAnnotation, typeElement, componentMethod); + componentMethodsBuilder.add(componentMethodDescriptor); + componentMethodDescriptor + .subcomponent() + .ifPresent( + subcomponent -> { + // If the dependency request is present, that means the method returns the + // subcomponent factory. + if (componentMethodDescriptor.dependencyRequest().isPresent()) { + subcomponentsByBuilderMethod.put(componentMethodDescriptor, subcomponent); + } else { + subcomponentsByFactoryMethod.put(componentMethodDescriptor, subcomponent); + } + }); + } + } + + // Validation should have ensured that this set will have at most one element. + ImmutableSet enclosedCreators = + enclosedAnnotatedTypes(typeElement, creatorAnnotationsFor(componentAnnotation)); + Optional creatorDescriptor = + enclosedCreators.isEmpty() + ? Optional.empty() + : Optional.of( + ComponentCreatorDescriptor.create( + getOnlyElement(enclosedCreators), dependencyRequestFactory)); + + ImmutableSet scopes = injectionAnnotations.getScopes(typeElement); + if (componentAnnotation.isProduction()) { + scopes = + ImmutableSet.builder() + .addAll(scopes).add(productionScope(processingEnv)) + .build(); + } + + ImmutableSet subcomponentsFromModules = + transitiveModules.stream() + .flatMap(transitiveModule -> transitiveModule.subcomponentDeclarations().stream()) + .map(SubcomponentDeclaration::subcomponentType) + .map(this::subcomponentDescriptor) + .collect(toImmutableSet()); + + return new AutoValue_ComponentDescriptor( + componentAnnotation, + typeElement, + componentDependencies, + transitiveModules, + scopes, + subcomponentsFromModules, + subcomponentsByFactoryMethod.buildOrThrow(), + subcomponentsByBuilderMethod.buildOrThrow(), + componentMethodsBuilder.build(), + creatorDescriptor); + } + + private ComponentMethodDescriptor getDescriptorForComponentMethod( + ComponentAnnotation componentAnnotation, + XTypeElement componentElement, + XMethodElement componentMethod) { + ComponentMethodDescriptor.Builder descriptor = + ComponentMethodDescriptor.builder(componentMethod); + + XMethodType resolvedComponentMethod = componentMethod.asMemberOf(componentElement.getType()); + XType returnType = resolvedComponentMethod.getReturnType(); + if (isDeclared(returnType) + && !injectionAnnotations.getQualifier(componentMethod).isPresent()) { + XTypeElement returnTypeElement = returnType.getTypeElement(); + if (returnTypeElement.hasAnyAnnotation(subcomponentAnnotations())) { + // 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(returnTypeElement.getEnclosingTypeElement())); + } + } + + switch (componentMethod.getParameters().size()) { + case 0: + checkArgument( + !isVoid(returnType), "component method cannot be void: %s", componentMethod); + descriptor.dependencyRequest( + componentAnnotation.isProduction() + ? dependencyRequestFactory.forComponentProductionMethod( + componentMethod, resolvedComponentMethod) + : dependencyRequestFactory.forComponentProvisionMethod( + componentMethod, resolvedComponentMethod)); + break; + + case 1: + checkArgument( + isVoid(returnType) + // TODO(bcorso): Replace this with isSameType()? + || returnType + .getTypeName() + .equals(resolvedComponentMethod.getParameterTypes().get(0).getTypeName()), + "members injection method must return void or parameter type: %s", + componentMethod); + descriptor.dependencyRequest( + dependencyRequestFactory.forComponentMembersInjectionMethod( + componentMethod, resolvedComponentMethod)); + break; + + default: + throw new IllegalArgumentException( + "component method has too many parameters: " + componentMethod); + } + + return descriptor.build(); + } + } } diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java b/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java deleted file mode 100644 index 1d094507896..00000000000 --- a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2014 The Dagger Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package dagger.internal.codegen.binding; - -import static androidx.room.compiler.processing.XTypeKt.isVoid; -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.ComponentAnnotation.subcomponentAnnotations; -import static dagger.internal.codegen.base.ComponentCreatorAnnotation.creatorAnnotationsFor; -import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation; -import static dagger.internal.codegen.base.Scopes.productionScope; -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 dagger.internal.codegen.xprocessing.XTypeElements.getAllUnimplementedMethods; -import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; - -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.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.internal.codegen.base.ComponentAnnotation; -import dagger.internal.codegen.base.DaggerSuperficialValidation; -import dagger.internal.codegen.base.ModuleAnnotation; -import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor; -import dagger.internal.codegen.model.Scope; -import dagger.internal.codegen.xprocessing.XTypeElements; -import java.util.Optional; -import javax.inject.Inject; - -/** A factory for {@link ComponentDescriptor}s. */ -public final class ComponentDescriptorFactory { - private final XProcessingEnv processingEnv; - private final DependencyRequestFactory dependencyRequestFactory; - private final ModuleDescriptor.Factory moduleDescriptorFactory; - private final InjectionAnnotations injectionAnnotations; - private final DaggerSuperficialValidation superficialValidation; - - @Inject - ComponentDescriptorFactory( - XProcessingEnv processingEnv, - DependencyRequestFactory dependencyRequestFactory, - ModuleDescriptor.Factory moduleDescriptorFactory, - InjectionAnnotations injectionAnnotations, - DaggerSuperficialValidation superficialValidation) { - this.processingEnv = processingEnv; - this.dependencyRequestFactory = dependencyRequestFactory; - this.moduleDescriptorFactory = moduleDescriptorFactory; - this.injectionAnnotations = injectionAnnotations; - this.superficialValidation = superficialValidation; - } - - /** Returns a descriptor for a root component type. */ - public ComponentDescriptor rootComponentDescriptor(XTypeElement typeElement) { - Optional annotation = - rootComponentAnnotation(typeElement, superficialValidation); - checkArgument(annotation.isPresent(), "%s must have a component annotation", typeElement); - return create(typeElement, annotation.get()); - } - - /** Returns a descriptor for a subcomponent type. */ - public ComponentDescriptor subcomponentDescriptor(XTypeElement typeElement) { - Optional annotation = - subcomponentAnnotation(typeElement, superficialValidation); - 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) { - Optional annotation = moduleAnnotation(typeElement, superficialValidation); - checkArgument(annotation.isPresent(), "%s must have a module annotation", typeElement); - return create(typeElement, ComponentAnnotation.fromModuleAnnotation(annotation.get())); - } - - private ComponentDescriptor create( - XTypeElement typeElement, ComponentAnnotation componentAnnotation) { - ImmutableSet componentDependencies = - componentAnnotation.dependencyTypes().stream() - .map(ComponentRequirement::forDependency) - .collect(toImmutableSet()); - - ImmutableMap.Builder dependenciesByDependencyMethod = - ImmutableMap.builder(); - for (ComponentRequirement componentDependency : componentDependencies) { - XTypeElements.getAllMethods(componentDependency.typeElement()).stream() - .filter(ComponentDescriptor::isComponentContributionMethod) - .forEach(method -> dependenciesByDependencyMethod.put(method, componentDependency)); - } - - // Start with the component's modules. For fictional components built from a module, start with - // that module. - ImmutableSet modules = - componentAnnotation.isRealComponent() - ? componentAnnotation.modules() - : ImmutableSet.of(typeElement); - - ImmutableSet transitiveModules = - moduleDescriptorFactory.transitiveModules(modules); - - ImmutableSet subcomponentsFromModules = - transitiveModules.stream() - .flatMap(transitiveModule -> transitiveModule.subcomponentDeclarations().stream()) - .map(SubcomponentDeclaration::subcomponentType) - .map(this::subcomponentDescriptor) - .collect(toImmutableSet()); - - ImmutableSet.Builder componentMethodsBuilder = - ImmutableSet.builder(); - ImmutableBiMap.Builder - subcomponentsByFactoryMethod = ImmutableBiMap.builder(); - ImmutableBiMap.Builder - subcomponentsByBuilderMethod = ImmutableBiMap.builder(); - if (componentAnnotation.isRealComponent()) { - for (XMethodElement componentMethod : getAllUnimplementedMethods(typeElement)) { - ComponentMethodDescriptor componentMethodDescriptor = - getDescriptorForComponentMethod(componentAnnotation, typeElement, componentMethod); - componentMethodsBuilder.add(componentMethodDescriptor); - componentMethodDescriptor - .subcomponent() - .ifPresent( - subcomponent -> { - // If the dependency request is present, that means the method returns the - // subcomponent factory. - if (componentMethodDescriptor.dependencyRequest().isPresent()) { - subcomponentsByBuilderMethod.put(componentMethodDescriptor, subcomponent); - } else { - subcomponentsByFactoryMethod.put(componentMethodDescriptor, subcomponent); - } - }); - } - } - - // Validation should have ensured that this set will have at most one element. - ImmutableSet enclosedCreators = - enclosedAnnotatedTypes(typeElement, creatorAnnotationsFor(componentAnnotation)); - Optional creatorDescriptor = - enclosedCreators.isEmpty() - ? Optional.empty() - : Optional.of( - ComponentCreatorDescriptor.create( - getOnlyElement(enclosedCreators), dependencyRequestFactory)); - - ImmutableSet scopes = injectionAnnotations.getScopes(typeElement); - if (componentAnnotation.isProduction()) { - scopes = - ImmutableSet.builder().addAll(scopes).add(productionScope(processingEnv)).build(); - } - - return ComponentDescriptor.create( - componentAnnotation, - typeElement, - componentDependencies, - transitiveModules, - dependenciesByDependencyMethod.build(), - scopes, - subcomponentsFromModules, - subcomponentsByFactoryMethod.build(), - subcomponentsByBuilderMethod.build(), - componentMethodsBuilder.build(), - creatorDescriptor); - } - - private ComponentMethodDescriptor getDescriptorForComponentMethod( - ComponentAnnotation componentAnnotation, - XTypeElement componentElement, - XMethodElement componentMethod) { - ComponentMethodDescriptor.Builder descriptor = - ComponentMethodDescriptor.builder(componentMethod); - - XMethodType resolvedComponentMethod = componentMethod.asMemberOf(componentElement.getType()); - XType returnType = resolvedComponentMethod.getReturnType(); - if (isDeclared(returnType) && !injectionAnnotations.getQualifier(componentMethod).isPresent()) { - XTypeElement returnTypeElement = returnType.getTypeElement(); - if (returnTypeElement.hasAnyAnnotation(subcomponentAnnotations())) { - // 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(returnTypeElement.getEnclosingTypeElement())); - } - } - - switch (componentMethod.getParameters().size()) { - case 0: - checkArgument(!isVoid(returnType), "component method cannot be void: %s", componentMethod); - descriptor.dependencyRequest( - componentAnnotation.isProduction() - ? dependencyRequestFactory.forComponentProductionMethod( - componentMethod, resolvedComponentMethod) - : dependencyRequestFactory.forComponentProvisionMethod( - componentMethod, resolvedComponentMethod)); - break; - - case 1: - checkArgument( - isVoid(returnType) - // TODO(bcorso): Replace this with isSameType()? - || returnType - .getTypeName() - .equals(resolvedComponentMethod.getParameterTypes().get(0).getTypeName()), - "members injection method must return void or parameter type: %s", - componentMethod); - descriptor.dependencyRequest( - dependencyRequestFactory.forComponentMembersInjectionMethod( - componentMethod, resolvedComponentMethod)); - break; - - default: - throw new IllegalArgumentException( - "component method has too many parameters: " + componentMethod); - } - - return descriptor.build(); - } -} diff --git a/java/dagger/internal/codegen/javac/BUILD b/java/dagger/internal/codegen/javac/BUILD index ce31e42cec4..325dc99d0dc 100644 --- a/java/dagger/internal/codegen/javac/BUILD +++ b/java/dagger/internal/codegen/javac/BUILD @@ -25,9 +25,7 @@ java_library( plugins = ["//java/dagger/internal/codegen:component-codegen"], deps = [ "//java/dagger:core", - "//java/dagger/internal/codegen/binding", "//java/dagger/internal/codegen/compileroption", - "//java/dagger/internal/codegen/langmodel", "//java/dagger/internal/codegen/xprocessing", "//third_party/java/guava/collect", ], diff --git a/java/dagger/internal/codegen/javac/JavacPluginModule.java b/java/dagger/internal/codegen/javac/JavacPluginModule.java index 5198164409d..f9e6da9bced 100644 --- a/java/dagger/internal/codegen/javac/JavacPluginModule.java +++ b/java/dagger/internal/codegen/javac/JavacPluginModule.java @@ -24,15 +24,13 @@ import dagger.Binds; import dagger.Module; import dagger.Provides; -import dagger.internal.codegen.binding.BindingGraphFactory; -import dagger.internal.codegen.binding.ComponentDescriptorFactory; import dagger.internal.codegen.compileroption.CompilerOptions; import javax.lang.model.util.Elements; // ALLOW_TYPES_ELEMENTS import javax.lang.model.util.Types; // ALLOW_TYPES_ELEMENTS /** - * A module that provides a {@link BindingGraphFactory} and {@link ComponentDescriptorFactory} for - * use in {@code javac} plugins. Requires a binding for the {@code javac} {@link Context}. + * A module that provides a {@link XMessager}, {@link XProcessingEnv}, and {@link CompilerOptions} + * for use in {@code javac} plugins. Requires a binding for the {@code javac} {@link Context}. */ @Module(includes = JavacPluginModule.BindsModule.class) public final class JavacPluginModule { diff --git a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java index 3280b4f79da..0b8a5024bf1 100644 --- a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java +++ b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java @@ -40,7 +40,7 @@ import dagger.internal.codegen.binding.BindingDeclaration; import dagger.internal.codegen.binding.BindingGraphFactory; import dagger.internal.codegen.binding.BindingNode; -import dagger.internal.codegen.binding.ComponentDescriptorFactory; +import dagger.internal.codegen.binding.ComponentDescriptor; import dagger.internal.codegen.binding.ModuleDescriptor; import dagger.internal.codegen.javac.JavacPluginModule; import dagger.internal.codegen.javapoet.TypeNames; @@ -64,7 +64,7 @@ public class DaggerKythePlugin extends Plugin.Scanner { // TODO(ronshapiro): use flogger private static final Logger logger = Logger.getLogger(DaggerKythePlugin.class.getCanonicalName()); private FactEmitter emitter; - @Inject ComponentDescriptorFactory componentDescriptorFactory; + @Inject ComponentDescriptor.Factory componentDescriptorFactory; @Inject BindingGraphFactory bindingGraphFactory; @Inject XProcessingEnv xProcessingEnv; diff --git a/java/dagger/internal/codegen/processingstep/ComponentHjarProcessingStep.java b/java/dagger/internal/codegen/processingstep/ComponentHjarProcessingStep.java index 7a7e180da9d..864bd768d28 100644 --- a/java/dagger/internal/codegen/processingstep/ComponentHjarProcessingStep.java +++ b/java/dagger/internal/codegen/processingstep/ComponentHjarProcessingStep.java @@ -28,7 +28,6 @@ import dagger.internal.codegen.base.SourceFileGenerator; import dagger.internal.codegen.binding.BindingGraph; import dagger.internal.codegen.binding.ComponentDescriptor; -import dagger.internal.codegen.binding.ComponentDescriptorFactory; import dagger.internal.codegen.validation.ComponentCreatorValidator; import dagger.internal.codegen.validation.ComponentValidator; import dagger.internal.codegen.validation.ValidationReport; @@ -52,7 +51,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep componentGenerator; @Inject @@ -60,7 +59,7 @@ final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep componentGenerator) { this.messager = messager; this.componentValidator = componentValidator; diff --git a/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java b/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java index 5b17c0061b3..168e8946f18 100644 --- a/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java +++ b/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java @@ -34,7 +34,6 @@ import dagger.internal.codegen.binding.BindingGraph; import dagger.internal.codegen.binding.BindingGraphFactory; import dagger.internal.codegen.binding.ComponentDescriptor; -import dagger.internal.codegen.binding.ComponentDescriptorFactory; import dagger.internal.codegen.validation.BindingGraphValidator; import dagger.internal.codegen.validation.ComponentCreatorValidator; import dagger.internal.codegen.validation.ComponentDescriptorValidator; @@ -52,7 +51,7 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep componentGenerator; private final BindingGraphValidator bindingGraphValidator; @@ -63,7 +62,7 @@ final class ComponentProcessingStep extends TypeCheckingProcessingStep componentGenerator, BindingGraphValidator bindingGraphValidator) { @@ -132,7 +131,10 @@ private void processSubcomponent(XTypeElement subcomponent) { return; } BindingGraph fullBindingGraph = bindingGraphFactory.create(subcomponentDescriptor, true); - boolean isValid = bindingGraphValidator.isValid(fullBindingGraph.topLevelBindingGraph()); + // In this case, we don't actually care about the return value. The important part here is that + // BindingGraphValidator#isValid() runs all of the SPI plugins and reports any errors. + // TODO(bcorso): Add a separate API with no return value for this particular case. + boolean unusedIsValid = bindingGraphValidator.isValid(fullBindingGraph.topLevelBindingGraph()); } private void generateComponent(BindingGraph bindingGraph) { diff --git a/java/dagger/internal/codegen/validation/ModuleValidator.java b/java/dagger/internal/codegen/validation/ModuleValidator.java index a1d9b0d1167..38bce2b44a1 100644 --- a/java/dagger/internal/codegen/validation/ModuleValidator.java +++ b/java/dagger/internal/codegen/validation/ModuleValidator.java @@ -58,7 +58,7 @@ import dagger.internal.codegen.base.DaggerSuperficialValidation; import dagger.internal.codegen.base.ModuleKind; import dagger.internal.codegen.binding.BindingGraphFactory; -import dagger.internal.codegen.binding.ComponentDescriptorFactory; +import dagger.internal.codegen.binding.ComponentDescriptor; import dagger.internal.codegen.binding.InjectionAnnotations; import dagger.internal.codegen.binding.MethodSignatureFormatter; import dagger.internal.codegen.javapoet.TypeNames; @@ -109,7 +109,7 @@ public final class ModuleValidator { private final AnyBindingMethodValidator anyBindingMethodValidator; private final MethodSignatureFormatter methodSignatureFormatter; - private final ComponentDescriptorFactory componentDescriptorFactory; + private final ComponentDescriptor.Factory componentDescriptorFactory; private final BindingGraphFactory bindingGraphFactory; private final BindingGraphValidator bindingGraphValidator; private final InjectionAnnotations injectionAnnotations; @@ -122,7 +122,7 @@ public final class ModuleValidator { ModuleValidator( AnyBindingMethodValidator anyBindingMethodValidator, MethodSignatureFormatter methodSignatureFormatter, - ComponentDescriptorFactory componentDescriptorFactory, + ComponentDescriptor.Factory componentDescriptorFactory, BindingGraphFactory bindingGraphFactory, BindingGraphValidator bindingGraphValidator, InjectionAnnotations injectionAnnotations, diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java index dc7baf83bdd..5851818251b 100644 --- a/java/dagger/internal/codegen/writing/ComponentImplementation.java +++ b/java/dagger/internal/codegen/writing/ComponentImplementation.java @@ -73,9 +73,9 @@ import dagger.internal.codegen.binding.BindingGraph; import dagger.internal.codegen.binding.BindingNode; import dagger.internal.codegen.binding.BindingRequest; +import dagger.internal.codegen.binding.CancellationPolicy; import dagger.internal.codegen.binding.ComponentCreatorDescriptor; import dagger.internal.codegen.binding.ComponentDescriptor; -import dagger.internal.codegen.binding.ComponentDescriptor.CancellationPolicy; import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor; import dagger.internal.codegen.binding.ComponentRequirement; import dagger.internal.codegen.binding.KeyVariableNamer;