diff options
7 files changed, 97 insertions, 8 deletions
diff --git a/java/dagger/internal/codegen/DelegateComponentProcessor.java b/java/dagger/internal/codegen/DelegateComponentProcessor.java index 8f8d5040b..432daa686 100644 --- a/java/dagger/internal/codegen/DelegateComponentProcessor.java +++ b/java/dagger/internal/codegen/DelegateComponentProcessor.java @@ -34,9 +34,11 @@ import dagger.internal.codegen.base.SourceFileGenerationException; import dagger.internal.codegen.base.SourceFileGenerator; import dagger.internal.codegen.base.SourceFileHjarGenerator; import dagger.internal.codegen.binding.BindingGraphFactory; +import dagger.internal.codegen.binding.ComponentDescriptor; import dagger.internal.codegen.binding.InjectBindingRegistry; import dagger.internal.codegen.binding.MembersInjectionBinding; import dagger.internal.codegen.binding.ModuleDescriptor; +import dagger.internal.codegen.binding.MonitoringModules; import dagger.internal.codegen.binding.ProductionBinding; import dagger.internal.codegen.binding.ProvisionBinding; import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule; @@ -172,6 +174,14 @@ final class DelegateComponentProcessor { @Binds @IntoSet + ClearableCache componentDescriptorFactory(ComponentDescriptor.Factory cache); + + @Binds + @IntoSet + ClearableCache monitoringModules(MonitoringModules cache); + + @Binds + @IntoSet ClearableCache bindingGraphFactory(BindingGraphFactory cache); @Binds diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java index 941001044..f5161c614 100644 --- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java +++ b/java/dagger/internal/codegen/binding/BindingGraphFactory.java @@ -185,7 +185,8 @@ public final class BindingGraphFactory implements ClearableCache { ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations = ImmutableSet.builder(); // Collect transitive module bindings and multibinding declarations. - for (ModuleDescriptor moduleDescriptor : modules(componentDescriptor, parentResolver)) { + ImmutableSet<ModuleDescriptor> modules = modules(componentDescriptor, parentResolver); + for (ModuleDescriptor moduleDescriptor : modules) { explicitBindingsBuilder.addAll(moduleDescriptor.bindings()); multibindingDeclarations.addAll(moduleDescriptor.multibindingDeclarations()); subcomponentDeclarations.addAll(moduleDescriptor.subcomponentDeclarations()); @@ -223,7 +224,7 @@ public final class BindingGraphFactory implements ClearableCache { if (createFullBindingGraph) { // Resolve the keys for all bindings in all modules, stripping any multibinding contribution // identifier so that the multibinding itself is resolved. - modules(componentDescriptor, parentResolver).stream() + modules.stream() .flatMap(module -> module.allBindingKeys().stream()) .map(Key::withoutMultibindingContributionIdentifier) .forEach(requestResolver::resolve); diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java index 2e5d6b545..b0a0183b9 100644 --- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java +++ b/java/dagger/internal/codegen/binding/ComponentDescriptor.java @@ -28,6 +28,7 @@ import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnot 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.base.Util.reentrantComputeIfAbsent; import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes; import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; @@ -57,6 +58,7 @@ import com.squareup.javapoet.TypeName; import dagger.Component; import dagger.Module; import dagger.Subcomponent; +import dagger.internal.codegen.base.ClearableCache; import dagger.internal.codegen.base.ComponentAnnotation; import dagger.internal.codegen.base.DaggerSuperficialValidation; import dagger.internal.codegen.base.ModuleAnnotation; @@ -70,6 +72,7 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; import javax.inject.Inject; +import javax.inject.Singleton; /** * A component declaration. @@ -388,12 +391,14 @@ public abstract class ComponentDescriptor { } /** A factory for creating a {@link ComponentDescriptor}. */ - public static final class Factory { + @Singleton + public static final class Factory implements ClearableCache { private final XProcessingEnv processingEnv; private final DependencyRequestFactory dependencyRequestFactory; private final ModuleDescriptor.Factory moduleDescriptorFactory; private final InjectionAnnotations injectionAnnotations; private final DaggerSuperficialValidation superficialValidation; + private final Map<XTypeElement, ComponentDescriptor> cache = new HashMap<>(); @Inject Factory( @@ -437,6 +442,12 @@ public abstract class ComponentDescriptor { private ComponentDescriptor create( XTypeElement typeElement, ComponentAnnotation componentAnnotation) { + return reentrantComputeIfAbsent( + cache, typeElement, unused -> createUncached(typeElement, componentAnnotation)); + } + + private ComponentDescriptor createUncached( + XTypeElement typeElement, ComponentAnnotation componentAnnotation) { ImmutableSet<ComponentRequirement> componentDependencies = componentAnnotation.dependencyTypes().stream() .map(ComponentRequirement::forDependency) @@ -572,5 +583,10 @@ public abstract class ComponentDescriptor { return descriptor.build(); } + + @Override + public void clearCache() { + cache.clear(); + } } } diff --git a/java/dagger/internal/codegen/binding/MonitoringModules.java b/java/dagger/internal/codegen/binding/MonitoringModules.java new file mode 100644 index 000000000..fc6dc021c --- /dev/null +++ b/java/dagger/internal/codegen/binding/MonitoringModules.java @@ -0,0 +1,46 @@ +/* + * 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 com.squareup.javapoet.ClassName; +import dagger.internal.codegen.base.ClearableCache; +import java.util.HashSet; +import java.util.Set; +import javax.inject.Inject; +import javax.inject.Singleton; + +/** Keeps track of modules generated in the current round by {@link MonitoringModuleGenerator}. */ +@Singleton +public final class MonitoringModules implements ClearableCache { + Set<ClassName> cache = new HashSet<>(); + + @Inject + MonitoringModules() {} + + public void add(ClassName module) { + cache.add(module); + } + + public boolean isEmpty() { + return cache.isEmpty(); + } + + @Override + public void clearCache() { + cache.clear(); + } +} diff --git a/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java b/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java index 00b033d96..3692144cf 100644 --- a/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java +++ b/java/dagger/internal/codegen/processingstep/MonitoringModuleGenerator.java @@ -35,6 +35,7 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; import dagger.Module; import dagger.internal.codegen.base.SourceFileGenerator; +import dagger.internal.codegen.binding.MonitoringModules; import dagger.internal.codegen.binding.SourceFiles; import dagger.internal.codegen.javapoet.TypeNames; import dagger.multibindings.Multibinds; @@ -42,10 +43,15 @@ import javax.inject.Inject; /** Generates a monitoring module for use with production components. */ final class MonitoringModuleGenerator extends SourceFileGenerator<XTypeElement> { + private final MonitoringModules monitoringModules; @Inject - MonitoringModuleGenerator(XFiler filer, XProcessingEnv processingEnv) { + MonitoringModuleGenerator( + XFiler filer, + XProcessingEnv processingEnv, + MonitoringModules monitoringModules) { super(filer, processingEnv); + this.monitoringModules = monitoringModules; } @Override @@ -55,6 +61,7 @@ final class MonitoringModuleGenerator extends SourceFileGenerator<XTypeElement> @Override public ImmutableList<TypeSpec.Builder> topLevelTypes(XTypeElement componentElement) { + monitoringModules.add(SourceFiles.generatedMonitoringModuleName(componentElement)); return ImmutableList.of( classBuilder(SourceFiles.generatedMonitoringModuleName(componentElement)) .addAnnotation(Module.class) diff --git a/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java b/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java index 5d6a64f3d..7ff47532a 100644 --- a/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java +++ b/java/dagger/internal/codegen/processingstep/TypeCheckingProcessingStep.java @@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Maps; import com.squareup.javapoet.ClassName; import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException; +import dagger.internal.codegen.binding.MonitoringModules; import dagger.internal.codegen.compileroption.CompilerOptions; import dagger.internal.codegen.xprocessing.XElements; import java.util.ArrayList; @@ -51,6 +52,7 @@ abstract class TypeCheckingProcessingStep<E extends XElement> implements XProces @Inject XMessager messager; @Inject CompilerOptions compilerOptions; @Inject SuperficialValidator superficialValidator; + @Inject MonitoringModules monitoringModules; @Override public final ImmutableSet<String> annotations() { @@ -70,6 +72,16 @@ abstract class TypeCheckingProcessingStep<E extends XElement> implements XProces .forEach( (element, annotations) -> { try { + if (this instanceof ComponentProcessingStep && !monitoringModules.isEmpty()) { + // If there were any monitoring modules generated by Dagger in this round then we + // should just defer processing the components until the next round. This is an + // optimization to avoid unnecessary processing of components that will likely + // need to be reprocessed next round anyway due to the missing module. We should + // be guaranteed that there will be a next round since the monitoring modules were + // generated in this round. + deferredElements.add(element); + return; + } // The XBasicAnnotationProcessor only validates the element itself. However, we // validate the enclosing type here to keep the previous behavior of // BasicAnnotationProcessor, since Dagger still relies on this behavior. diff --git a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java index 1b0b85bbd..cfcf8ee88 100644 --- a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java +++ b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java @@ -195,14 +195,11 @@ public class ProductionGraphValidationTest { .buildOrThrow()) .compile( subject -> { - subject.hasErrorCount(2); + subject.hasErrorCount(1); subject.hasErrorContaining( "TestClass.A is a provision, which cannot depend on a production.") .onSource(component) .onLineContaining("class AModule"); - subject.hasErrorContaining("test.TestClass.AModule has errors") - .onSource(component) - .onLineContaining("@ProductionComponent"); }); } |