diff options
author | Brad Corso <bcorso@google.com> | 2021-04-02 16:11:49 -0700 |
---|---|---|
committer | Dagger Team <dagger-dev+copybara@google.com> | 2021-04-02 16:13:07 -0700 |
commit | 64ac597811d450b5ae510ce260426bb0d2311ba0 (patch) | |
tree | 2290146e2561b5a1669a77c7ac94f98849506af3 /java/dagger/hilt | |
parent | faebc3c66129c50ccbc32d73383c3fd78b0deb08 (diff) | |
download | dagger2-64ac597811d450b5ae510ce260426bb0d2311ba0.tar.gz |
Pull AggregatedDepsMetadata into its own source file.
RELNOTES=N/A
PiperOrigin-RevId: 366531336
Diffstat (limited to 'java/dagger/hilt')
3 files changed, 227 insertions, 200 deletions
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java new file mode 100644 index 000000000..db8a10a2c --- /dev/null +++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2021 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.hilt.processor.internal.aggregateddeps; + +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.extension.DaggerStreams.toImmutableSet; + +import com.google.auto.common.MoreElements; +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import dagger.hilt.processor.internal.AnnotationValues; +import dagger.hilt.processor.internal.ClassNames; +import dagger.hilt.processor.internal.ProcessorErrors; +import dagger.hilt.processor.internal.Processors; +import java.util.List; +import java.util.Optional; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; + +/** + * A class that represents the values stored in an {@link + * dagger.hilt.processor.internal.aggregateddeps.AggregatedDeps} annotation. + */ +@AutoValue +abstract class AggregatedDepsMetadata { + private static final String AGGREGATED_DEPS_PACKAGE = "hilt_aggregated_deps"; + + enum DependencyType { + MODULE, + ENTRY_POINT, + COMPONENT_ENTRY_POINT + } + + abstract Optional<TypeElement> testElement(); + + abstract ImmutableSet<TypeElement> componentElements(); + + abstract DependencyType dependencyType(); + + abstract TypeElement dependency(); + + abstract ImmutableSet<TypeElement> replacedDependencies(); + + /** Returns all aggregated deps in the aggregating package. */ + public static ImmutableSet<AggregatedDepsMetadata> from(Elements elements) { + PackageElement packageElement = elements.getPackageElement(AGGREGATED_DEPS_PACKAGE); + checkState( + packageElement != null, + "Couldn't find package %s. Did you mark your @Module classes with @InstallIn annotations?", + AGGREGATED_DEPS_PACKAGE); + + List<? extends Element> aggregatedDepsElements = packageElement.getEnclosedElements(); + checkState( + !aggregatedDepsElements.isEmpty(), + "No dependencies found. Did you mark your @Module classes with @InstallIn annotations?"); + + ImmutableSet.Builder<AggregatedDepsMetadata> builder = ImmutableSet.builder(); + for (Element element : aggregatedDepsElements) { + ProcessorErrors.checkState( + element.getKind() == ElementKind.CLASS, + element, + "Only classes may be in package %s. Did you add custom code in the package?", + AGGREGATED_DEPS_PACKAGE); + + builder.add(create(MoreElements.asType(element), elements)); + } + return builder.build(); + } + + private static AggregatedDepsMetadata create(TypeElement element, Elements elements) { + AnnotationMirror aggregatedDeps = + Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_DEPS); + + ProcessorErrors.checkState( + aggregatedDeps != null, + element, + "Classes in package %s must be annotated with @AggregatedDeps: %s. Found: %s.", + AGGREGATED_DEPS_PACKAGE, + element.getSimpleName(), + element.getAnnotationMirrors()); + + ImmutableMap<String, AnnotationValue> aggregatedDepsValues = + Processors.getAnnotationValues(elements, aggregatedDeps); + + return new AutoValue_AggregatedDepsMetadata( + getTestElement(aggregatedDepsValues.get("test"), elements), + getComponents(aggregatedDepsValues.get("components"), elements), + getDependencyType( + aggregatedDepsValues.get("modules"), + aggregatedDepsValues.get("entryPoints"), + aggregatedDepsValues.get("componentEntryPoints")), + getDependency( + aggregatedDepsValues.get("modules"), + aggregatedDepsValues.get("entryPoints"), + aggregatedDepsValues.get("componentEntryPoints"), + elements), + getReplacedDependencies(aggregatedDepsValues.get("replaces"), elements)); + } + + private static Optional<TypeElement> getTestElement( + AnnotationValue testValue, Elements elements) { + checkNotNull(testValue); + String test = AnnotationValues.getString(testValue); + return test.isEmpty() ? Optional.empty() : Optional.of(elements.getTypeElement(test)); + } + + private static ImmutableSet<TypeElement> getComponents( + AnnotationValue componentsValue, Elements elements) { + checkNotNull(componentsValue); + ImmutableSet<TypeElement> componentNames = + AnnotationValues.getAnnotationValues(componentsValue).stream() + .map(AnnotationValues::getString) + .map( + // This is a temporary hack to map the old ApplicationComponent to the new + // SingletonComponent. Technically, this is only needed for backwards compatibility + // with libraries using the old processor since new processors should convert to the + // new SingletonComponent when generating the metadata class. + componentName -> + componentName.contentEquals( + "dagger.hilt.android.components.ApplicationComponent") + ? ClassNames.SINGLETON_COMPONENT.canonicalName() + : componentName) + .map(elements::getTypeElement) + .collect(toImmutableSet()); + checkState(!componentNames.isEmpty()); + return componentNames; + } + + private static DependencyType getDependencyType( + AnnotationValue modulesValue, + AnnotationValue entryPointsValue, + AnnotationValue componentEntryPointsValue) { + checkNotNull(modulesValue); + checkNotNull(entryPointsValue); + checkNotNull(componentEntryPointsValue); + + ImmutableSet.Builder<DependencyType> dependencyTypes = ImmutableSet.builder(); + if (!AnnotationValues.getAnnotationValues(modulesValue).isEmpty()) { + dependencyTypes.add(DependencyType.MODULE); + } + if (!AnnotationValues.getAnnotationValues(entryPointsValue).isEmpty()) { + dependencyTypes.add(DependencyType.ENTRY_POINT); + } + if (!AnnotationValues.getAnnotationValues(componentEntryPointsValue).isEmpty()) { + dependencyTypes.add(DependencyType.COMPONENT_ENTRY_POINT); + } + return getOnlyElement(dependencyTypes.build()); + } + + private static TypeElement getDependency( + AnnotationValue modulesValue, + AnnotationValue entryPointsValue, + AnnotationValue componentEntryPointsValue, + Elements elements) { + checkNotNull(modulesValue); + checkNotNull(entryPointsValue); + checkNotNull(componentEntryPointsValue); + + return elements.getTypeElement( + AnnotationValues.getString( + getOnlyElement( + ImmutableSet.<AnnotationValue>builder() + .addAll(AnnotationValues.getAnnotationValues(modulesValue)) + .addAll(AnnotationValues.getAnnotationValues(entryPointsValue)) + .addAll(AnnotationValues.getAnnotationValues(componentEntryPointsValue)) + .build()))); + } + + private static ImmutableSet<TypeElement> getReplacedDependencies( + AnnotationValue replacedDependenciesValue, Elements elements) { + // Allow null values to support libraries using a Hilt version before @TestInstallIn was added + return replacedDependenciesValue == null + ? ImmutableSet.of() + : AnnotationValues.getAnnotationValues(replacedDependenciesValue).stream() + .map(AnnotationValues::getString) + .map(elements::getTypeElement) + .map(replacedDep -> getPublicDependency(replacedDep, elements)) + .collect(toImmutableSet()); + } + + /** Returns the public Hilt wrapper module, or the module itself if its already public. */ + private static TypeElement getPublicDependency(TypeElement dependency, Elements elements) { + return PkgPrivateMetadata.of(elements, dependency, ClassNames.MODULE) + .map(metadata -> elements.getTypeElement(metadata.generatedClassName().toString())) + .orElse(dependency); + } +} diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD index 3155e4aa8..e3bc9d651 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD +++ b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD @@ -66,6 +66,7 @@ java_library( java_library( name = "component_dependencies", srcs = [ + "AggregatedDepsMetadata.java", "ComponentDependencies.java", ], deps = [ @@ -79,6 +80,7 @@ java_library( "//java/dagger/internal/guava:collect", "@google_bazel_common//third_party/java/auto:value", "@google_bazel_common//third_party/java/javapoet", + "@maven//:com_google_auto_auto_common", ], ) diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java index 00c2ab9f6..01ad0f2ff 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java +++ b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java @@ -16,11 +16,9 @@ package dagger.hilt.processor.internal.aggregateddeps; -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.hilt.processor.internal.aggregateddeps.AggregatedDepsGenerator.AGGREGATING_PACKAGE; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; +import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import com.google.auto.value.AutoValue; @@ -32,21 +30,11 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.SetMultimap; import com.squareup.javapoet.ClassName; -import dagger.hilt.processor.internal.AnnotationValues; import dagger.hilt.processor.internal.BadInputException; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.ComponentDescriptor; -import dagger.hilt.processor.internal.ProcessorErrors; import dagger.hilt.processor.internal.Processors; -import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies.AggregatedDepMetadata.DependencyType; -import java.util.List; -import java.util.Map; import java.util.Optional; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; @@ -70,8 +58,7 @@ public abstract class ComponentDependencies { @Memoized public boolean hasEarlySingletonEntryPoints() { return entryPoints().getGlobalSingletonDeps().stream() - .anyMatch( - entryPoint -> Processors.hasAnnotation(entryPoint, ClassNames.EARLY_ENTRY_POINT)); + .anyMatch(entryPoint -> Processors.hasAnnotation(entryPoint, ClassNames.EARLY_ENTRY_POINT)); } /** @@ -204,14 +191,13 @@ public abstract class ComponentDependencies { */ public static ComponentDependencies from( ImmutableSet<ComponentDescriptor> descriptors, Elements elements) { - Map<String, ComponentDescriptor> descriptorLookup = descriptorLookupMap(descriptors); - ImmutableList<AggregatedDepMetadata> metadatas = - getAggregatedDeps(elements).stream() - .map(deps -> AggregatedDepMetadata.create(deps, descriptorLookup, elements)) - .collect(toImmutableList()); + ImmutableMap<ClassName, ComponentDescriptor> descriptorLookup = + descriptors.stream() + .collect(toImmutableMap(ComponentDescriptor::component, descriptor -> descriptor)); + ImmutableSet<AggregatedDepsMetadata> metadatas = AggregatedDepsMetadata.from(elements); ComponentDependencies.Builder componentDependencies = ComponentDependencies.builder(); - for (AggregatedDepMetadata metadata : metadatas) { + for (AggregatedDepsMetadata metadata : metadatas) { Dependencies.Builder builder = null; switch (metadata.dependencyType()) { case MODULE: @@ -224,22 +210,25 @@ public abstract class ComponentDependencies { builder = componentDependencies.componentEntryPointsBuilder(); break; } - - for (ComponentDescriptor componentDescriptor : metadata.componentDescriptors()) { - ClassName component = componentDescriptor.component(); + for (TypeElement componentElement : metadata.componentElements()) { + ClassName componentName = ClassName.get(componentElement); + checkState( + descriptorLookup.containsKey(componentName), + "%s is not a valid Component.", + componentName); if (metadata.testElement().isPresent()) { // In this case the @InstallIn or @TestInstallIn applies to only the given test root. ClassName test = ClassName.get(metadata.testElement().get()); - builder.testDepsBuilder().put(TestDepKey.of(component, test), metadata.dependency()); + builder.testDepsBuilder().put(TestDepKey.of(componentName, test), metadata.dependency()); builder.uninstalledTestDepsBuilder().putAll(test, metadata.replacedDependencies()); } else { // In this case the @InstallIn or @TestInstallIn applies to all roots if (!metadata.replacedDependencies().isEmpty()) { // If there are replacedDependencies() it means this is a @TestInstallIn - builder.globalTestDepsBuilder().put(component, metadata.dependency()); + builder.globalTestDepsBuilder().put(componentName, metadata.dependency()); builder.globalUninstalledTestDepsBuilder().addAll(metadata.replacedDependencies()); } else { - builder.globalDepsBuilder().put(component, metadata.dependency()); + builder.globalDepsBuilder().put(componentName, metadata.dependency()); } } } @@ -263,22 +252,6 @@ public abstract class ComponentDependencies { return componentDependencies.build(elements); } - private static ImmutableMap<String, ComponentDescriptor> descriptorLookupMap( - ImmutableSet<ComponentDescriptor> descriptors) { - ImmutableMap.Builder<String, ComponentDescriptor> builder = ImmutableMap.builder(); - for (ComponentDescriptor descriptor : descriptors) { - // This is a temporary hack to map the old ApplicationComponent to the new SingletonComponent. - // Technically, this is only needed for backwards compatibility with libraries using the old - // processor since new processors should convert to the new SingletonComponent when generating - // the metadata class. - if (descriptor.component().equals(ClassNames.SINGLETON_COMPONENT)) { - builder.put("dagger.hilt.android.components.ApplicationComponent", descriptor); - } - builder.put(descriptor.component().toString(), descriptor); - } - return builder.build(); - } - // Validate that the @UninstallModules doesn't contain any test modules. private static Dependencies validateModules(Dependencies moduleDeps, Elements elements) { SetMultimap<ClassName, TypeElement> invalidTestModules = HashMultimap.create(); @@ -328,161 +301,4 @@ public abstract class ComponentDependencies { .map(metadata -> elements.getTypeElement(metadata.generatedClassName().toString())) .orElse(dependency); } - - /** Returns the top-level elements of the aggregated deps package. */ - private static ImmutableList<AnnotationMirror> getAggregatedDeps(Elements elements) { - PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE); - checkState( - packageElement != null, - "Couldn't find package %s. Did you mark your @Module classes with @InstallIn annotations?", - AGGREGATING_PACKAGE); - - List<? extends Element> aggregatedDepsElements = packageElement.getEnclosedElements(); - checkState( - !aggregatedDepsElements.isEmpty(), - "No dependencies found. Did you mark your @Module classes with @InstallIn annotations?"); - - ImmutableList.Builder<AnnotationMirror> builder = ImmutableList.builder(); - for (Element element : aggregatedDepsElements) { - ProcessorErrors.checkState( - element.getKind() == ElementKind.CLASS, - element, - "Only classes may be in package %s. Did you add custom code in the package?", - AGGREGATING_PACKAGE); - - AnnotationMirror aggregatedDeps = - Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_DEPS); - ProcessorErrors.checkState( - aggregatedDeps != null, - element, - "Classes in package %s must be annotated with @AggregatedDeps: %s. Found: %s.", - AGGREGATING_PACKAGE, - element.getSimpleName(), - element.getAnnotationMirrors()); - - builder.add(aggregatedDeps); - } - return builder.build(); - } - - @AutoValue - abstract static class AggregatedDepMetadata { - static AggregatedDepMetadata create( - AnnotationMirror aggregatedDeps, - Map<String, ComponentDescriptor> descriptorLookup, - Elements elements) { - ImmutableMap<String, AnnotationValue> aggregatedDepsValues = - Processors.getAnnotationValues(elements, aggregatedDeps); - - return new AutoValue_ComponentDependencies_AggregatedDepMetadata( - getTestElement(aggregatedDepsValues.get("test"), elements), - getComponents(aggregatedDepsValues.get("components"), descriptorLookup), - getDependencyType( - aggregatedDepsValues.get("modules"), - aggregatedDepsValues.get("entryPoints"), - aggregatedDepsValues.get("componentEntryPoints")), - getDependency( - aggregatedDepsValues.get("modules"), - aggregatedDepsValues.get("entryPoints"), - aggregatedDepsValues.get("componentEntryPoints"), - elements), - getReplacedDependencies(aggregatedDepsValues.get("replaces"), elements)); - } - - enum DependencyType { - MODULE, - ENTRY_POINT, - COMPONENT_ENTRY_POINT - } - - abstract Optional<TypeElement> testElement(); - - abstract ImmutableList<ComponentDescriptor> componentDescriptors(); - - abstract DependencyType dependencyType(); - - abstract TypeElement dependency(); - - abstract ImmutableSet<TypeElement> replacedDependencies(); - - private static Optional<TypeElement> getTestElement( - AnnotationValue testValue, Elements elements) { - checkNotNull(testValue); - String test = AnnotationValues.getString(testValue); - return test.isEmpty() ? Optional.empty() : Optional.of(elements.getTypeElement(test)); - } - - private static ImmutableList<ComponentDescriptor> getComponents( - AnnotationValue componentsValue, Map<String, ComponentDescriptor> descriptorLookup) { - checkNotNull(componentsValue); - ImmutableList<String> componentNames = - AnnotationValues.getAnnotationValues(componentsValue).stream() - .map(AnnotationValues::getString) - .collect(toImmutableList()); - - checkState(!componentNames.isEmpty()); - ImmutableList.Builder<ComponentDescriptor> components = ImmutableList.builder(); - for (String componentName : componentNames) { - checkState( - descriptorLookup.containsKey(componentName), - "%s is not a valid Component. Did you add or remove code in package %s?", - componentName, - AGGREGATING_PACKAGE); - components.add(descriptorLookup.get(componentName)); - } - return components.build(); - } - - private static DependencyType getDependencyType( - AnnotationValue modulesValue, - AnnotationValue entryPointsValue, - AnnotationValue componentEntryPointsValue) { - checkNotNull(modulesValue); - checkNotNull(entryPointsValue); - checkNotNull(componentEntryPointsValue); - - ImmutableSet.Builder<DependencyType> dependencyTypes = ImmutableSet.builder(); - if (!AnnotationValues.getAnnotationValues(modulesValue).isEmpty()) { - dependencyTypes.add(DependencyType.MODULE); - } - if (!AnnotationValues.getAnnotationValues(entryPointsValue).isEmpty()) { - dependencyTypes.add(DependencyType.ENTRY_POINT); - } - if (!AnnotationValues.getAnnotationValues(componentEntryPointsValue).isEmpty()) { - dependencyTypes.add(DependencyType.COMPONENT_ENTRY_POINT); - } - return getOnlyElement(dependencyTypes.build()); - } - - private static TypeElement getDependency( - AnnotationValue modulesValue, - AnnotationValue entryPointsValue, - AnnotationValue componentEntryPointsValue, - Elements elements) { - checkNotNull(modulesValue); - checkNotNull(entryPointsValue); - checkNotNull(componentEntryPointsValue); - - return elements.getTypeElement( - AnnotationValues.getString( - getOnlyElement( - ImmutableList.<AnnotationValue>builder() - .addAll(AnnotationValues.getAnnotationValues(modulesValue)) - .addAll(AnnotationValues.getAnnotationValues(entryPointsValue)) - .addAll(AnnotationValues.getAnnotationValues(componentEntryPointsValue)) - .build()))); - } - - private static ImmutableSet<TypeElement> getReplacedDependencies( - AnnotationValue replacedDependenciesValue, Elements elements) { - // Allow null values to support libraries using a Hilt version before @TestInstallIn was added - return replacedDependenciesValue == null - ? ImmutableSet.of() - : AnnotationValues.getAnnotationValues(replacedDependenciesValue).stream() - .map(AnnotationValues::getString) - .map(elements::getTypeElement) - .map(replacedDep -> getPublicDependency(replacedDep, elements)) - .collect(toImmutableSet()); - } - } } |