Files
Android11/external/dagger2/java/dagger/internal/codegen/ComponentImplementationFactory.java
2023-10-13 14:01:41 +00:00

163 lines
7.2 KiB
Java

/*
* Copyright (C) 2015 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;
import static com.google.common.base.Preconditions.checkState;
import static dagger.internal.codegen.ComponentGenerator.componentName;
import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
import static javax.tools.Diagnostic.Kind.WARNING;
import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.serialization.ProtoSerialization.InconsistentSerializedProtoException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.annotation.processing.Messager;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.lang.model.element.TypeElement;
/** Factory for {@link ComponentImplementation}s. */
@Singleton
final class ComponentImplementationFactory implements ClearableCache {
private final Map<TypeElement, ComponentImplementation> topLevelComponentCache = new HashMap<>();
private final KeyFactory keyFactory;
private final CompilerOptions compilerOptions;
private final BindingGraphFactory bindingGraphFactory;
private final TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder;
private final DeserializedComponentImplementationBuilder
deserializedComponentImplementationBuilder;
private final DaggerElements elements;
private final Messager messager;
@Inject
ComponentImplementationFactory(
KeyFactory keyFactory,
CompilerOptions compilerOptions,
BindingGraphFactory bindingGraphFactory,
TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder,
DeserializedComponentImplementationBuilder deserializedComponentImplementationBuilder,
DaggerElements elements,
Messager messager) {
this.keyFactory = keyFactory;
this.compilerOptions = compilerOptions;
this.bindingGraphFactory = bindingGraphFactory;
this.topLevelImplementationComponentBuilder = topLevelImplementationComponentBuilder;
this.deserializedComponentImplementationBuilder = deserializedComponentImplementationBuilder;
this.elements = elements;
this.messager = messager;
}
/**
* Returns a top-level (non-nested) component implementation for a binding graph.
*
* @throws IllegalStateException if the binding graph is for a subcomponent and
* ahead-of-time-subcomponents mode is not enabled
*/
ComponentImplementation createComponentImplementation(BindingGraph bindingGraph) {
return reentrantComputeIfAbsent(
topLevelComponentCache,
bindingGraph.componentTypeElement(),
component -> createComponentImplementationUncached(bindingGraph));
}
private ComponentImplementation createComponentImplementationUncached(BindingGraph bindingGraph) {
ComponentImplementation componentImplementation =
ComponentImplementation.topLevelComponentImplementation(
bindingGraph,
componentName(bindingGraph.componentTypeElement()),
new SubcomponentNames(bindingGraph, keyFactory),
compilerOptions);
// TODO(dpb): explore using optional bindings for the "parent" bindings
CurrentImplementationSubcomponent currentImplementationSubcomponent =
topLevelImplementationComponentBuilder
.topLevelComponent(componentImplementation)
.build()
.currentImplementationSubcomponentBuilder()
.componentImplementation(componentImplementation)
.bindingGraph(bindingGraph)
.parentBuilder(Optional.empty())
.parentBindingExpressions(Optional.empty())
.parentRequirementExpressions(Optional.empty())
.build();
if (componentImplementation.isAbstract()) {
checkState(
compilerOptions.aheadOfTimeSubcomponents(),
"Calling 'componentImplementation()' on %s when not generating ahead-of-time "
+ "subcomponents.",
bindingGraph.componentTypeElement());
return currentImplementationSubcomponent.subcomponentBuilder().build();
} else {
return currentImplementationSubcomponent.rootComponentBuilder().build();
}
}
/** Returns the superclass of the child nested within a superclass of the parent component. */
ComponentImplementation findChildSuperclassImplementation(
ComponentDescriptor child, ComponentImplementation parentImplementation) {
// If the current component has superclass implementations, a superclass may contain a
// reference to the child. Traverse this component's superimplementation hierarchy looking for
// the child's implementation. The child superclass implementation may not be present in the
// direct superclass implementations if the subcomponent builder was previously a pruned
// binding.
for (Optional<ComponentImplementation> parent = parentImplementation.superclassImplementation();
parent.isPresent();
parent = parent.get().superclassImplementation()) {
Optional<ComponentImplementation> superclass = parent.get().childImplementation(child);
if (superclass.isPresent()) {
return superclass.get();
}
}
if (compilerOptions.emitModifiableMetadataAnnotations()) {
ClassName childSuperclassName = componentName(child.typeElement());
TypeElement generatedChildSuperclassImplementation =
elements.getTypeElement(childSuperclassName);
if (generatedChildSuperclassImplementation != null) {
try {
return deserializedComponentImplementationBuilder.create(
child, generatedChildSuperclassImplementation);
} catch (InconsistentSerializedProtoException e) {
messager.printMessage(
WARNING,
String.format(
"%s was compiled with a different version of Dagger than the version in this "
+ "compilation. To ensure the validity of Dagger's generated code, compile "
+ "all Dagger code with the same version.",
child.typeElement().getQualifiedName()));
}
} else if (compilerOptions.forceUseSerializedComponentImplementations()) {
throw new TypeNotPresentException(childSuperclassName.toString(), null);
}
}
// Otherwise, the superclass implementation is top-level, so we must recreate the
// implementation object for the base implementation of the child by truncating the binding
// graph at the child.
BindingGraph truncatedBindingGraph = bindingGraphFactory.create(child, false);
return createComponentImplementation(truncatedBindingGraph);
}
@Override
public void clearCache() {
topLevelComponentCache.clear();
}
}