diff options
author | Aurimas Liutikas <aurimas@google.com> | 2021-05-12 21:55:46 +0000 |
---|---|---|
committer | Aurimas Liutikas <aurimas@google.com> | 2021-05-12 21:55:46 +0000 |
commit | 2fee426653cd72c87c78c6ddd91d01d1e8d1e66a (patch) | |
tree | 6f59a75348d07612173246ac6c4fca04bde0df2c /java/dagger/hilt/processor | |
parent | 399f4f61132f363e9479e59c550a7bcf005922d8 (diff) | |
download | dagger2-2fee426653cd72c87c78c6ddd91d01d1e8d1e66a.tar.gz |
Revert "Merge commit 'upstream/dagger-2.35.1^'"
This reverts commit 399f4f61132f363e9479e59c550a7bcf005922d8.
Reason for revert: b/187908823
Change-Id: I81f7cd3672e65ce1f7e1fa846b6c3e2f87147a26
Diffstat (limited to 'java/dagger/hilt/processor')
53 files changed, 828 insertions, 2297 deletions
diff --git a/java/dagger/hilt/processor/BUILD b/java/dagger/hilt/processor/BUILD index 1f75d0a34..87adcf34f 100644 --- a/java/dagger/hilt/processor/BUILD +++ b/java/dagger/hilt/processor/BUILD @@ -15,7 +15,7 @@ # Description: # Hilt android processors. -load("//:build_defs.bzl", "POM_VERSION") +load("//:build_defs.bzl", "POM_VERSION_ALPHA") load("//tools:maven.bzl", "gen_maven_artifact") package(default_visibility = ["//:src"]) @@ -27,23 +27,22 @@ java_library( "//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib", "//java/dagger/hilt/android/processor/internal/bindvalue:bind_value_processor_lib", "//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib", + "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor_lib", "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib", "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib", "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib", "//java/dagger/hilt/processor/internal/aliasof:processor_lib", "//java/dagger/hilt/processor/internal/definecomponent:processor_lib", - "//java/dagger/hilt/processor/internal/earlyentrypoint:processor_lib", "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib", "//java/dagger/hilt/processor/internal/originatingelement:processor_lib", "//java/dagger/hilt/processor/internal/root:processor_lib", - "//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib", "//java/dagger/internal/codegen:processor", ], ) java_library( name = "artifact-lib", - tags = ["maven_coordinates=com.google.dagger:hilt-compiler:" + POM_VERSION], + tags = ["maven_coordinates=com.google.dagger:hilt-compiler:" + POM_VERSION_ALPHA], visibility = ["//visibility:private"], exports = [ ":artifact-lib-shared", @@ -52,23 +51,23 @@ java_library( gen_maven_artifact( name = "artifact", - artifact_coordinates = "com.google.dagger:hilt-compiler:" + POM_VERSION, + artifact_coordinates = "com.google.dagger:hilt-compiler:" + POM_VERSION_ALPHA, artifact_name = "Hilt Processor", artifact_target = ":artifact-lib", artifact_target_libs = [ "//java/dagger/hilt/android/processor/internal:android_classnames", "//java/dagger/hilt/android/processor/internal:utils", "//java/dagger/hilt/android/processor/internal/androidentrypoint:android_generators", + "//java/dagger/hilt/android/processor/internal/androidentrypoint:compiler_options", "//java/dagger/hilt/android/processor/internal/androidentrypoint:metadata", "//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib", "//java/dagger/hilt/android/processor/internal/bindvalue:bind_value_processor_lib", "//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib", "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib", + "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor_lib", "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib", - "//java/dagger/hilt/processor/internal:aggregated_elements", "//java/dagger/hilt/processor/internal:base_processor", "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:compiler_options", "//java/dagger/hilt/processor/internal:component_descriptor", "//java/dagger/hilt/processor/internal:component_names", "//java/dagger/hilt/processor/internal:components", @@ -76,22 +75,17 @@ gen_maven_artifact( "//java/dagger/hilt/processor/internal:processor_errors", "//java/dagger/hilt/processor/internal:processors", "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies", - "//java/dagger/hilt/processor/internal/aggregateddeps:pkg_private_metadata", "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib", "//java/dagger/hilt/processor/internal/aliasof:alias_ofs", "//java/dagger/hilt/processor/internal/aliasof:processor_lib", "//java/dagger/hilt/processor/internal/definecomponent:define_components", "//java/dagger/hilt/processor/internal/definecomponent:processor_lib", - "//java/dagger/hilt/processor/internal/earlyentrypoint:aggregated_early_entry_point_metadata", - "//java/dagger/hilt/processor/internal/earlyentrypoint:processor_lib", "//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs", "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib", "//java/dagger/hilt/processor/internal/originatingelement:processor_lib", "//java/dagger/hilt/processor/internal/root:processor_lib", "//java/dagger/hilt/processor/internal/root:root_metadata", "//java/dagger/hilt/processor/internal/root:root_type", - "//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib", - "//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata", ], artifact_target_maven_deps = [ "com.google.auto:auto-common", diff --git a/java/dagger/hilt/processor/internal/AggregatedElements.java b/java/dagger/hilt/processor/internal/AggregatedElements.java deleted file mode 100644 index 8ee820fbd..000000000 --- a/java/dagger/hilt/processor/internal/AggregatedElements.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.common.MoreElements; -import com.google.common.collect.ImmutableSet; -import com.squareup.javapoet.ClassName; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** Utility class for aggregating metadata. */ -public final class AggregatedElements { - - /** Returns all aggregated elements in the aggregating package after validating them. */ - public static ImmutableSet<TypeElement> from( - String aggregatingPackage, ClassName aggregatingAnnotation, Elements elements) { - PackageElement packageElement = elements.getPackageElement(aggregatingPackage); - - if (packageElement == null) { - return ImmutableSet.of(); - } - - ImmutableSet<TypeElement> aggregatedElements = - packageElement.getEnclosedElements().stream() - .map(MoreElements::asType) - .collect(toImmutableSet()); - - ProcessorErrors.checkState( - !aggregatedElements.isEmpty(), - packageElement, - "No dependencies found. Did you remove code in package %s?", - packageElement); - - for (TypeElement aggregatedElement : aggregatedElements) { - ProcessorErrors.checkState( - Processors.hasAnnotation(aggregatedElement, aggregatingAnnotation), - aggregatedElement, - "Expected element, %s, to be annotated with @%s, but only found: %s.", - aggregatedElement.getSimpleName(), - aggregatingAnnotation, - aggregatedElement.getAnnotationMirrors()); - } - - return aggregatedElements; - } - - private AggregatedElements() {} -} diff --git a/java/dagger/hilt/processor/internal/AnnotationValues.java b/java/dagger/hilt/processor/internal/AnnotationValues.java index 9ebeeebca..584d8f950 100644 --- a/java/dagger/hilt/processor/internal/AnnotationValues.java +++ b/java/dagger/hilt/processor/internal/AnnotationValues.java @@ -18,19 +18,15 @@ package dagger.hilt.processor.internal; import static com.google.auto.common.AnnotationMirrors.getAnnotationValue; import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults; -import static com.google.auto.common.MoreTypes.asTypeElement; import static com.google.common.base.Preconditions.checkNotNull; -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import com.google.auto.common.MoreTypes; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; 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.AnnotationValueVisitor; -import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; @@ -91,18 +87,6 @@ public final class AnnotationValues { } } - /** Returns a class array value as a set of {@link TypeElement}. */ - public static ImmutableSet<TypeElement> getTypeElements(AnnotationValue value) { - return getAnnotationValues(value).stream() - .map(AnnotationValues::getTypeElement) - .collect(toImmutableSet()); - } - - /** Returns a class value as a {@link TypeElement}. */ - public static TypeElement getTypeElement(AnnotationValue value) { - return asTypeElement(getTypeMirror(value)); - } - /** * Returns the value as a VariableElement. * @@ -112,13 +96,6 @@ public final class AnnotationValues { return EnumVisitor.INSTANCE.visit(value); } - /** Returns a string array value as a set of strings. */ - public static ImmutableSet<String> getStrings(AnnotationValue value) { - return getAnnotationValues(value).stream() - .map(AnnotationValues::getString) - .collect(toImmutableSet()); - } - /** * Returns the value as a string. * @@ -128,15 +105,6 @@ public final class AnnotationValues { return valueOfType(value, String.class); } - /** - * Returns the value as a boolean. - * - * @throws IllegalArgumentException if the value is not a boolean. - */ - public static boolean getBoolean(AnnotationValue value) { - return valueOfType(value, Boolean.class); - } - private static <T> T valueOfType(AnnotationValue annotationValue, Class<T> type) { Object value = annotationValue.getValue(); if (!type.isInstance(value)) { diff --git a/java/dagger/hilt/processor/internal/BUILD b/java/dagger/hilt/processor/internal/BUILD index 978655dea..baff1d823 100644 --- a/java/dagger/hilt/processor/internal/BUILD +++ b/java/dagger/hilt/processor/internal/BUILD @@ -24,7 +24,6 @@ java_library( "ProcessorErrorHandler.java", ], deps = [ - ":compiler_options", ":processor_errors", ":processors", "//java/dagger/internal/guava:base", @@ -63,9 +62,11 @@ java_library( ":processor_errors", "//java/dagger/internal/codegen/extension", "//java/dagger/internal/codegen/kotlin", + "//java/dagger/internal/codegen/langmodel", "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", "@google_bazel_common//third_party/java/javapoet", + "@google_bazel_common//third_party/java/jsr305_annotations", "@google_bazel_common//third_party/java/jsr330_inject", "@maven//:com_google_auto_auto_common", "@maven//:org_jetbrains_kotlin_kotlin_stdlib", @@ -89,34 +90,25 @@ java_library( "ComponentNames.java", ], deps = [ - ":classnames", ":processors", - "//java/dagger/internal/guava:base", - "//java/dagger/internal/guava:collect", "@google_bazel_common//third_party/java/javapoet", ], ) java_library( - name = "aggregated_elements", + name = "component_descriptor", srcs = [ - "AggregatedElements.java", + "ComponentDescriptor.java", + "ComponentGenerator.java", + "ComponentTree.java", ], deps = [ - ":processor_errors", + ":classnames", ":processors", "//java/dagger/internal/codegen/extension", + "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/javapoet", - "@maven//:com_google_auto_auto_common", - ], -) - -java_library( - name = "component_descriptor", - srcs = ["ComponentDescriptor.java"], - deps = [ - "//java/dagger/internal/guava:collect", + "//java/dagger/internal/guava:graph", "@google_bazel_common//third_party/java/auto:value", "@google_bazel_common//third_party/java/javapoet", ], @@ -151,16 +143,6 @@ java_library( ], ) -java_library( - name = "compiler_options", - srcs = ["HiltCompilerOptions.java"], - deps = [ - ":processor_errors", - "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/javapoet", - ], -) - filegroup( name = "srcs_filegroup", srcs = glob(["*"]), diff --git a/java/dagger/hilt/processor/internal/BadInputException.java b/java/dagger/hilt/processor/internal/BadInputException.java index f57a34a5e..d9617688e 100644 --- a/java/dagger/hilt/processor/internal/BadInputException.java +++ b/java/dagger/hilt/processor/internal/BadInputException.java @@ -36,11 +36,6 @@ public final class BadInputException extends RuntimeException { this.badElements = ImmutableList.copyOf(badElements); } - public BadInputException(String message) { - super(message); - this.badElements = ImmutableList.of(); - } - public ImmutableList<Element> getBadElements() { return badElements; } diff --git a/java/dagger/hilt/processor/internal/BaseProcessor.java b/java/dagger/hilt/processor/internal/BaseProcessor.java index 1a63f8b47..4961cd570 100644 --- a/java/dagger/hilt/processor/internal/BaseProcessor.java +++ b/java/dagger/hilt/processor/internal/BaseProcessor.java @@ -96,15 +96,6 @@ public abstract class BaseProcessor extends AbstractProcessor { private Messager messager; private ProcessorErrorHandler errorHandler; - @Override - public final Set<String> getSupportedOptions() { - // This is declared here rather than in the actual processors because KAPT will issue a - // warning if any used option is not unsupported. This can happen when there is a module - // which uses Hilt but lacks any @AndroidEntryPoint annotations. - // See: https://github.com/google/dagger/issues/2040 - return HiltCompilerOptions.getProcessorOptions(); - } - /** Used to perform initialization before each round of processing. */ protected void preRoundProcess(RoundEnvironment roundEnv) {}; diff --git a/java/dagger/hilt/processor/internal/ClassNames.java b/java/dagger/hilt/processor/internal/ClassNames.java index 093e1b3d5..234ea7b45 100644 --- a/java/dagger/hilt/processor/internal/ClassNames.java +++ b/java/dagger/hilt/processor/internal/ClassNames.java @@ -22,26 +22,6 @@ import com.squareup.javapoet.ClassName; /** Holder for commonly used class names. */ public final class ClassNames { - public static final String AGGREGATED_ROOT_PACKAGE = - "dagger.hilt.internal.aggregatedroot.codegen"; - public static final ClassName AGGREGATED_ROOT = - get("dagger.hilt.internal.aggregatedroot", "AggregatedRoot"); - public static final String PROCESSED_ROOT_SENTINEL_PACKAGE = - "dagger.hilt.internal.processedrootsentinel.codegen"; - public static final ClassName PROCESSED_ROOT_SENTINEL = - get("dagger.hilt.internal.processedrootsentinel", "ProcessedRootSentinel"); - - public static final String AGGREGATED_EARLY_ENTRY_POINT_PACKAGE = - "dagger.hilt.android.internal.earlyentrypoint.codegen"; - public static final ClassName AGGREGATED_EARLY_ENTRY_POINT = - get("dagger.hilt.android.internal.earlyentrypoint", "AggregatedEarlyEntryPoint"); - public static final ClassName EARLY_ENTRY_POINT = get("dagger.hilt.android", "EarlyEntryPoint"); - - public static final String AGGREGATED_UNINSTALL_MODULES_PACKAGE = - "dagger.hilt.android.internal.uninstallmodules.codegen"; - public static final ClassName AGGREGATED_UNINSTALL_MODULES = - get("dagger.hilt.android.internal.uninstallmodules", "AggregatedUninstallModules"); - public static final ClassName ORIGINATING_ELEMENT = get("dagger.hilt.codegen", "OriginatingElement"); public static final ClassName AGGREGATED_DEPS = @@ -52,11 +32,9 @@ public final class ClassNames { get("dagger.hilt.internal", "GeneratedComponentManager"); public static final ClassName GENERATED_COMPONENT_MANAGER_HOLDER = get("dagger.hilt.internal", "GeneratedComponentManagerHolder"); - public static final ClassName UNINSTALL_MODULES = + public static final ClassName IGNORE_MODULES = get("dagger.hilt.android.testing", "UninstallModules"); - public static final String DEFINE_COMPONENT_CLASSES_PACKAGE = - "dagger.hilt.processor.internal.definecomponent.codegen"; public static final ClassName DEFINE_COMPONENT = get("dagger.hilt", "DefineComponent"); public static final ClassName DEFINE_COMPONENT_BUILDER = get("dagger.hilt", "DefineComponent", "Builder"); @@ -101,8 +79,6 @@ public final class ClassNames { public static final ClassName ALIAS_OF = get("dagger.hilt.migration", "AliasOf"); public static final ClassName ALIAS_OF_PROPAGATED_DATA = get("dagger.hilt.internal.aliasof", "AliasOfPropagatedData"); - public static final String ALIAS_OF_PROPAGATED_DATA_PACKAGE = - "dagger.hilt.processor.internal.aliasof.codegen"; public static final ClassName GENERATES_ROOT_INPUT = get("dagger.hilt", "GeneratesRootInput"); public static final ClassName GENERATES_ROOT_INPUT_PROPAGATED_DATA = @@ -146,12 +122,12 @@ public final class ClassNames { get("dagger.hilt.android.internal.managers", "ComponentSupplier"); public static final ClassName APPLICATION_CONTEXT_MODULE = get("dagger.hilt.android.internal.modules", "ApplicationContextModule"); - public static final ClassName DEFAULT_ROOT = - ClassName.get("dagger.hilt.android.internal.testing.root", "Default"); public static final ClassName INTERNAL_TEST_ROOT = get("dagger.hilt.android.internal.testing", "InternalTestRoot"); public static final ClassName TEST_INJECTOR = get("dagger.hilt.android.internal.testing", "TestInjector"); + public static final ClassName TEST_APPLICATION_INJECTOR = + get("dagger.hilt.android.internal.testing", "TestApplicationInjector"); public static final ClassName TEST_APPLICATION_COMPONENT_MANAGER = get("dagger.hilt.android.internal.testing", "TestApplicationComponentManager"); public static final ClassName TEST_APPLICATION_COMPONENT_MANAGER_HOLDER = @@ -176,8 +152,6 @@ public final class ClassNames { get("dagger.hilt.android.testing", "BindValueIntoSet"); public static final ClassName APPLICATION_CONTEXT = get("dagger.hilt.android.qualifiers", "ApplicationContext"); - public static final ClassName TEST_SINGLETON_COMPONENT = - get("dagger.hilt.internal", "TestSingletonComponent"); public static final ClassName TEST_COMPONENT_DATA = get("dagger.hilt.android.internal.testing", "TestComponentData"); public static final ClassName TEST_COMPONENT_DATA_SUPPLIER = diff --git a/java/dagger/hilt/processor/internal/root/ComponentGenerator.java b/java/dagger/hilt/processor/internal/ComponentGenerator.java index 0e8d0ad80..3a4bf1e78 100644 --- a/java/dagger/hilt/processor/internal/root/ComponentGenerator.java +++ b/java/dagger/hilt/processor/internal/ComponentGenerator.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package dagger.hilt.processor.internal.root; +package dagger.hilt.processor.internal; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; import static java.util.Comparator.comparing; @@ -28,8 +28,6 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; import java.io.IOException; import java.util.ArrayList; import java.util.Comparator; @@ -38,9 +36,11 @@ import java.util.Optional; import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; /** Generates a Dagger component or subcomponent interface. */ -final class ComponentGenerator { +// TODO(bcorso): Make this non-public +public final class ComponentGenerator { private static final Joiner JOINER = Joiner.on("."); private static final Comparator<ClassName> SIMPLE_NAME_SORTER = Comparator.comparing((ClassName c) -> JOINER.join(c.simpleNames())) @@ -49,6 +49,7 @@ final class ComponentGenerator { private final ProcessingEnvironment processingEnv; private final ClassName name; + private final TypeElement rootElement; private final Optional<ClassName> superclass; private final ImmutableList<ClassName> modules; private final ImmutableList<TypeName> entryPoints; @@ -60,6 +61,7 @@ final class ComponentGenerator { public ComponentGenerator( ProcessingEnvironment processingEnv, ClassName name, + TypeElement rootElement, Optional<ClassName> superclass, Set<? extends ClassName> modules, Set<? extends TypeName> entryPoints, @@ -69,6 +71,7 @@ final class ComponentGenerator { Optional<TypeSpec> componentBuilder) { this.processingEnv = processingEnv; this.name = name; + this.rootElement = rootElement; this.superclass = superclass; this.modules = modules.stream().sorted(SIMPLE_NAME_SORTER).collect(toImmutableList()); this.entryPoints = entryPoints.stream().sorted(TYPE_NAME_SORTER).collect(toImmutableList()); @@ -78,24 +81,25 @@ final class ComponentGenerator { this.componentBuilder = componentBuilder; } - public TypeSpec.Builder typeSpecBuilder() throws IOException { - TypeSpec.Builder builder = + public TypeSpec generate() throws IOException { + TypeSpec.Builder generator = TypeSpec.classBuilder(name) // Public because components from a scope below must reference to create .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) + .addOriginatingElement(rootElement) .addAnnotation(getComponentAnnotation()); - componentBuilder.ifPresent(builder::addType); + componentBuilder.ifPresent(generator::addType); - scopes.forEach(builder::addAnnotation); + scopes.forEach(generator::addAnnotation); - addEntryPoints(builder); + addEntryPoints(generator); - superclass.ifPresent(builder::superclass); + superclass.ifPresent(generator::superclass); - builder.addAnnotations(extraAnnotations); + generator.addAnnotations(extraAnnotations); - return builder; + return generator.build(); } /** Returns the component annotation with the list of modules to install for the component. */ @@ -156,6 +160,7 @@ final class ComponentGenerator { Processors.getEnclosedClassName(name), "_EntryPointPartition" + partitionIndex); TypeSpec.Builder builder = TypeSpec.interfaceBuilder(partitionName) + .addOriginatingElement(rootElement) .addModifiers(Modifier.ABSTRACT) .addSuperinterfaces(partition); diff --git a/java/dagger/hilt/processor/internal/ComponentNames.java b/java/dagger/hilt/processor/internal/ComponentNames.java index eeaa5f44b..fab4d1995 100644 --- a/java/dagger/hilt/processor/internal/ComponentNames.java +++ b/java/dagger/hilt/processor/internal/ComponentNames.java @@ -16,25 +16,7 @@ package dagger.hilt.processor.internal; -import static java.lang.Character.isUpperCase; -import static java.lang.String.format; -import static java.util.Comparator.comparing; - -import com.google.common.base.CharMatcher; -import com.google.common.base.Preconditions; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableListMultimap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.Multimaps; import com.squareup.javapoet.ClassName; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; /** * Utility class for getting the generated component name. @@ -42,45 +24,15 @@ import javax.lang.model.element.TypeElement; * <p>This should not be used externally. */ public final class ComponentNames { - private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.'); - - private final boolean renameTestComponents; - private final String destinationPackage; - private final ImmutableMap<ClassName, String> simpleNameByClassName; - - public static ComponentNames withoutRenaming() { - return new ComponentNames( - /*renameTestComponents=*/ false, /*destinationPackage=*/ null, ImmutableMap.of()); - } - - public static ComponentNames withRenamingIntoPackage( - String destinationPackage, ImmutableList<TypeElement> roots) { - ImmutableMap.Builder<ClassName, String> builder = ImmutableMap.builder(); - ImmutableListMultimap<String, TypeElement> rootsBySimpleName = - Multimaps.index(roots, typeElement -> typeElement.getSimpleName().toString()); - rootsBySimpleName.asMap().values().stream() - .map(ComponentNames::disambiguateConflictingSimpleNames) - .forEach(builder::putAll); - return new ComponentNames(/*renameTestComponents=*/ true, destinationPackage, builder.build()); - } - - private ComponentNames( - boolean renameTestComponents, - String destinationPackage, - ImmutableMap<ClassName, String> simpleNameByClassName) { - this.renameTestComponents = renameTestComponents; - this.destinationPackage = destinationPackage; - this.simpleNameByClassName = simpleNameByClassName; - } + private ComponentNames() {} /** Returns the name of the generated component wrapper. */ - public ClassName generatedComponentsWrapper(ClassName root) { - return Processors.append( - Processors.getEnclosedClassName(maybeRenameComponent(root)), "_HiltComponents"); + public static ClassName generatedComponentsWrapper(ClassName root) { + return Processors.append(Processors.getEnclosedClassName(root), "_HiltComponents"); } /** Returns the name of the generated component. */ - public ClassName generatedComponent(ClassName root, ClassName component) { + public static ClassName generatedComponent(ClassName root, ClassName component) { return generatedComponentsWrapper(root).nestedClass(componentName(component)); } @@ -98,82 +50,4 @@ public final class ComponentNames { // Note: This uses regex matching so we only match if the name ends in "Component" return Processors.getEnclosedName(component).replaceAll("Component$", "C"); } - - /** - * Rewrites the provided HiltAndroidTest-annotated class name using the shared component - * directory. - */ - private ClassName maybeRenameComponent(ClassName className) { - return (renameTestComponents && !className.equals(ClassNames.DEFAULT_ROOT)) - ? ClassName.get(destinationPackage, dedupeSimpleName(className)) - : className; - } - - /** - * Derives a new generated component base name, should the simple names of two roots have - * conflicting simple names. - * - * <p>This is lifted nearly verbatim (albeit with new different struct types) from {@link - * dagger.internal.codegen.writing.SubcomponentNames}. - */ - private String dedupeSimpleName(ClassName className) { - Preconditions.checkState( - simpleNameByClassName.containsKey(className), - "Class name %s not found in simple name map", - className.canonicalName()); - return simpleNameByClassName.get(className); - } - - private static ImmutableMap<ClassName, String> disambiguateConflictingSimpleNames( - Collection<TypeElement> rootsWithConflictingNames) { - // If there's only 1 root there's nothing to disambiguate so return the simple name. - if (rootsWithConflictingNames.size() == 1) { - TypeElement root = Iterables.getOnlyElement(rootsWithConflictingNames); - return ImmutableMap.of(ClassName.get(root), root.getSimpleName().toString()); - } - - // There are conflicting simple names, so disambiguate them with a unique prefix. - // We keep them small to fix https://github.com/google/dagger/issues/421. - // Sorted in order to guarantee determinism if this is invoked by different processors. - ImmutableList<TypeElement> sortedRootsWithConflictingNames = - ImmutableList.sortedCopyOf( - comparing(typeElement -> typeElement.getQualifiedName().toString()), - rootsWithConflictingNames); - Set<String> usedNames = new HashSet<>(); - ImmutableMap.Builder<ClassName, String> uniqueNames = ImmutableMap.builder(); - for (TypeElement root : sortedRootsWithConflictingNames) { - String basePrefix = uniquingPrefix(root); - String uniqueName = basePrefix; - for (int differentiator = 2; !usedNames.add(uniqueName); differentiator++) { - uniqueName = basePrefix + differentiator; - } - uniqueNames.put(ClassName.get(root), format("%s_%s", uniqueName, root.getSimpleName())); - } - return uniqueNames.build(); - } - - /** Returns a prefix that could make the component's simple name more unique. */ - private static String uniquingPrefix(TypeElement typeElement) { - String containerName = typeElement.getEnclosingElement().getSimpleName().toString(); - - // If parent element looks like a class, use its initials as a prefix. - if (!containerName.isEmpty() && isUpperCase(containerName.charAt(0))) { - return CharMatcher.javaLowerCase().removeFrom(containerName); - } - - // Not in a normally named class. Prefix with the initials of the elements leading here. - Name qualifiedName = typeElement.getQualifiedName(); - Iterator<String> pieces = QUALIFIED_NAME_SPLITTER.split(qualifiedName).iterator(); - StringBuilder b = new StringBuilder(); - - while (pieces.hasNext()) { - String next = pieces.next(); - if (pieces.hasNext()) { - b.append(next.charAt(0)); - } - } - - // Note that a top level class in the root package will be prefixed "$_". - return b.length() > 0 ? b.toString() : "$"; - } } diff --git a/java/dagger/hilt/processor/internal/root/ComponentTree.java b/java/dagger/hilt/processor/internal/ComponentTree.java index fe3d4b133..6d2137a02 100644 --- a/java/dagger/hilt/processor/internal/root/ComponentTree.java +++ b/java/dagger/hilt/processor/internal/ComponentTree.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package dagger.hilt.processor.internal.root; +package dagger.hilt.processor.internal; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; @@ -27,18 +27,17 @@ import com.google.common.graph.Graphs; import com.google.common.graph.ImmutableGraph; import com.google.common.graph.MutableGraph; import com.squareup.javapoet.ClassName; -import dagger.hilt.processor.internal.ComponentDescriptor; import java.util.HashMap; import java.util.Map; import java.util.Set; /** A representation of the full tree of scopes. */ -final class ComponentTree { +public final class ComponentTree { private final ImmutableGraph<ComponentDescriptor> graph; private final ComponentDescriptor root; /** Creates a new tree from a set of descriptors. */ - static ComponentTree from(Set<ComponentDescriptor> descriptors) { + public static ComponentTree from(Set<ComponentDescriptor> descriptors) { MutableGraph<ComponentDescriptor> graph = GraphBuilder.directed().allowsSelfLoops(false).build(); @@ -89,19 +88,19 @@ final class ComponentTree { root = Iterables.getOnlyElement(roots); } - ImmutableSet<ComponentDescriptor> getComponentDescriptors() { + public ImmutableSet<ComponentDescriptor> getComponentDescriptors() { return ImmutableSet.copyOf(graph.nodes()); } - ImmutableSet<ComponentDescriptor> childrenOf(ComponentDescriptor componentDescriptor) { + public ImmutableSet<ComponentDescriptor> childrenOf(ComponentDescriptor componentDescriptor) { return ImmutableSet.copyOf(graph.successors(componentDescriptor)); } - ImmutableGraph<ComponentDescriptor> graph() { + public ImmutableGraph<ComponentDescriptor> graph() { return graph; } - ComponentDescriptor root() { + public ComponentDescriptor root() { return root; } } diff --git a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java deleted file mode 100644 index 0d248239b..000000000 --- a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2020 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; - -import com.google.common.collect.ImmutableSet; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; - -/** Hilt annotation processor options. */ -// TODO(danysantiago): Consider consolidating with Dagger compiler options logic. -public final class HiltCompilerOptions { - - /** - * Returns {@code true} if the superclass validation is disabled for - * {@link dagger.hilt.android.AndroidEntryPoint}-annotated classes. - * - * This flag is for internal use only! The superclass validation checks that the super class is a - * generated {@code Hilt_} class. This flag is disabled by the Hilt Gradle plugin to enable - * bytecode transformation to change the superclass. - */ - public static boolean isAndroidSuperclassValidationDisabled( - TypeElement element, ProcessingEnvironment env) { - BooleanOption option = BooleanOption.DISABLE_ANDROID_SUPERCLASS_VALIDATION; - return option.get(env); - } - - /** - * Returns {@code true} if cross-compilation root validation is disabled. - * - * <p>This flag should rarely be needed, but may be used for legacy/migration purposes if - * tests require the use of {@link dagger.hilt.android.HiltAndroidApp} rather than - * {@link dagger.hilt.android.testing.HiltAndroidTest}. - * - * <p>Note that Hilt still does validation within a single compilation unit. In particular, - * a compilation unit that contains a {@code HiltAndroidApp} usage cannot have other - * {@code HiltAndroidApp} or {@code HiltAndroidTest} usages in the same compilation unit. - */ - public static boolean isCrossCompilationRootValidationDisabled( - ImmutableSet<TypeElement> rootElements, ProcessingEnvironment env) { - BooleanOption option = BooleanOption.DISABLE_CROSS_COMPILATION_ROOT_VALIDATION; - return option.get(env); - } - - /** Returns {@code true} if the check for {@link dagger.hilt.InstallIn} is disabled. */ - public static boolean isModuleInstallInCheckDisabled(ProcessingEnvironment env) { - return BooleanOption.DISABLE_MODULES_HAVE_INSTALL_IN_CHECK.get(env); - } - - /** - * Returns {@code true} of unit tests should try to share generated components, rather than using - * separate generated components per Hilt test root. - * - * <p>Tests that provide their own test bindings (e.g. using {@link - * dagger.hilt.android.testing.BindValue} or a test {@link dagger.Module}) cannot use the shared - * component. In these cases, a component will be generated for the test. - */ - public static boolean isSharedTestComponentsEnabled(ProcessingEnvironment env) { - return BooleanOption.SHARE_TEST_COMPONENTS.get(env); - } - - /** Processor options which can have true or false values. */ - private enum BooleanOption { - DISABLE_ANDROID_SUPERCLASS_VALIDATION( - "android.internal.disableAndroidSuperclassValidation", false), - - DISABLE_CROSS_COMPILATION_ROOT_VALIDATION("disableCrossCompilationRootValidation", false), - - DISABLE_MODULES_HAVE_INSTALL_IN_CHECK("disableModulesHaveInstallInCheck", false), - - SHARE_TEST_COMPONENTS("shareTestComponents", false); - - private final String name; - private final boolean defaultValue; - - BooleanOption(String name, boolean defaultValue) { - this.name = name; - this.defaultValue = defaultValue; - } - - boolean get(ProcessingEnvironment env) { - String value = env.getOptions().get(getQualifiedName()); - if (value == null) { - return defaultValue; - } - // TODO(danysantiago): Strictly verify input, either 'true' or 'false' and nothing else. - return Boolean.parseBoolean(value); - } - - String getQualifiedName() { - return "dagger.hilt." + name; - } - } - - public static Set<String> getProcessorOptions() { - return Arrays.stream(BooleanOption.values()) - .map(BooleanOption::getQualifiedName) - .collect(Collectors.toSet()); - } -} diff --git a/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java b/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java index 64d5892c4..ec5ddf871 100644 --- a/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java +++ b/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java @@ -20,11 +20,7 @@ import dagger.Component; import dagger.internal.codegen.kotlin.KotlinMetadataUtil; import javax.inject.Singleton; -/** - * A single-use provider of {@link KotlinMetadataUtil}. Since the returned util has a cache, it is - * better to reuse the same instance as much as possible, except for going across processor rounds - * because the cache contains elements. - */ +/** A single-use provider of {@link KotlinMetadataUtil}. */ // TODO(erichang): Revert this, should be wrapped with a Dagger module. public final class KotlinMetadataUtils { diff --git a/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java b/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java index 2ecc0f098..460e8a946 100644 --- a/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java +++ b/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java @@ -62,9 +62,6 @@ final class ProcessorErrorHandler { if (t instanceof BadInputException) { BadInputException badInput = (BadInputException) t; - if (badInput.getBadElements().isEmpty()) { - hiltErrors.add(HiltError.of(badInput.getMessage())); - } for (Element element : badInput.getBadElements()) { hiltErrors.add(HiltError.of(badInput.getMessage(), element)); } diff --git a/java/dagger/hilt/processor/internal/ProcessorErrors.java b/java/dagger/hilt/processor/internal/ProcessorErrors.java index d75bb625e..b1578daa3 100644 --- a/java/dagger/hilt/processor/internal/ProcessorErrors.java +++ b/java/dagger/hilt/processor/internal/ProcessorErrors.java @@ -36,49 +36,6 @@ public final class ProcessorErrors { * involving any parameters to the calling method. * * @param expression a boolean expression - * @param errorMessage the exception message to use if the check fails; will be converted to a - * string using {@link String#valueOf(Object)} - * @throws BadInputException if {@code expression} is false - */ - public static void checkState( - boolean expression, - @Nullable Object errorMessage) { - if (!expression) { - throw new BadInputException(String.valueOf(errorMessage)); - } - } - - /** - * Ensures the truth of an expression involving the state of the calling instance, but not - * involving any parameters to the calling method. - * - * @param expression a boolean expression - * @param errorMessageTemplate a template for the exception message should the check fail. The - * message is formed by replacing each {@code %s} placeholder in the template with an - * argument. These are matched by position - the first {@code %s} gets {@code - * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in - * square braces. Unmatched placeholders will be left as-is. - * @param errorMessageArgs the arguments to be substituted into the message template. Arguments - * are converted to strings using {@link String#valueOf(Object)}. - * @throws BadInputException if {@code expression} is false - * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or - * {@code errorMessageArgs} is null (don't let this happen) - */ - @FormatMethod - public static void checkState( - boolean expression, - @Nullable @FormatString String errorMessageTemplate, - @Nullable Object... errorMessageArgs) { - if (!expression) { - throw new BadInputException(String.format(errorMessageTemplate, errorMessageArgs)); - } - } - - /** - * Ensures the truth of an expression involving the state of the calling instance, but not - * involving any parameters to the calling method. - * - * @param expression a boolean expression * @param badElement the element that was at fault * @param errorMessage the exception message to use if the check fails; will be converted to a * string using {@link String#valueOf(Object)} diff --git a/java/dagger/hilt/processor/internal/Processors.java b/java/dagger/hilt/processor/internal/Processors.java index 8740bd6a0..b33c19d67 100644 --- a/java/dagger/hilt/processor/internal/Processors.java +++ b/java/dagger/hilt/processor/internal/Processors.java @@ -17,12 +17,10 @@ package dagger.hilt.processor.internal; import static com.google.auto.common.MoreElements.asPackage; -import static com.google.auto.common.MoreElements.asType; import static com.google.auto.common.MoreElements.asVariable; import static com.google.common.base.Preconditions.checkNotNull; import static dagger.internal.codegen.extension.DaggerCollectors.toOptional; import static javax.lang.model.element.Modifier.ABSTRACT; -import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; import com.google.auto.common.AnnotationMirrors; @@ -43,7 +41,6 @@ import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; @@ -51,7 +48,6 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import dagger.internal.codegen.extension.DaggerStreams; import dagger.internal.codegen.kotlin.KotlinMetadataUtil; -import java.io.IOException; import java.lang.annotation.Annotation; import java.util.LinkedHashSet; import java.util.List; @@ -92,26 +88,6 @@ public final class Processors { private static final String JAVA_CLASS = "java.lang.Class"; - public static void generateAggregatingClass( - String aggregatingPackage, - AnnotationSpec aggregatingAnnotation, - TypeElement element, - Class<?> generatedAnnotationClass, - ProcessingEnvironment env) throws IOException { - ClassName name = ClassName.get(aggregatingPackage, "_" + getFullEnclosedName(element)); - TypeSpec.Builder builder = - TypeSpec.classBuilder(name) - .addModifiers(PUBLIC) - .addOriginatingElement(element) - .addAnnotation(aggregatingAnnotation) - .addJavadoc("This class should only be referenced by generated code!") - .addJavadoc("This class aggregates information across multiple compilations.\n");; - - addGeneratedAnnotation(builder, env, generatedAnnotationClass); - - JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler()); - } - /** Returns a map from {@link AnnotationMirror} attribute name to {@link AnnotationValue}s */ public static ImmutableMap<String, AnnotationValue> getAnnotationValues(Elements elements, AnnotationMirror annotation) { @@ -535,14 +511,6 @@ public final class Processors { return ClassName.get(className.packageName(), getEnclosedName(className)); } - /** - * Returns an equivalent class name with the {@code .} (dots) used for inner classes replaced with - * {@code _}. - */ - public static ClassName getEnclosedClassName(TypeElement typeElement) { - return getEnclosedClassName(ClassName.get(typeElement)); - } - /** Returns the fully qualified class name, with _ instead of . */ public static String getFullyQualifiedEnclosedClassName(ClassName className) { return className.packageName().replace('.', '_') + getEnclosedName(className); @@ -925,10 +893,7 @@ public final class Processors { return ElementFilter.methodsIn(elements.getAllMembers(module)).stream() .filter(Processors::isBindingMethod) .map(ExecutableElement::getModifiers) - .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC)) - // TODO(erichang): Getting a new KotlinMetadataUtil each time isn't great here, but until - // we have some sort of dependency management it will be difficult to share the instance. - && !KotlinMetadataUtils.getMetadataUtil().isObjectOrCompanionObjectClass(module); + .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC)); } private static boolean isBindingMethod(ExecutableElement method) { @@ -971,27 +936,5 @@ public final class Processors { : typeName; } - public static Optional<TypeElement> getOriginatingTestElement( - Element element, Elements elements) { - TypeElement topLevelType = getOriginatingTopLevelType(element, elements); - return hasAnnotation(topLevelType, ClassNames.HILT_ANDROID_TEST) - ? Optional.of(asType(topLevelType)) - : Optional.empty(); - } - - private static TypeElement getOriginatingTopLevelType(Element element, Elements elements) { - TypeElement topLevelType = getTopLevelType(element); - if (hasAnnotation(topLevelType, ClassNames.ORIGINATING_ELEMENT)) { - return getOriginatingTopLevelType( - getAnnotationClassValue( - elements, - getAnnotationMirror(topLevelType, ClassNames.ORIGINATING_ELEMENT), - "topLevelClass"), - elements); - } - - return topLevelType; - } - private Processors() {} } diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java index 84fb5a1ee..bcc2dfe04 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java +++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java @@ -19,6 +19,8 @@ package dagger.hilt.processor.internal.aggregateddeps; import com.google.common.collect.ImmutableSet; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.TypeSpec; import dagger.hilt.processor.internal.Processors; import java.io.IOException; import java.util.Optional; @@ -57,8 +59,20 @@ final class AggregatedDepsGenerator { } void generate() throws IOException { - Processors.generateAggregatingClass( - AGGREGATING_PACKAGE, aggregatedDepsAnnotation(), dependency, getClass(), processingEnv); + ClassName name = + ClassName.get( + AGGREGATING_PACKAGE, Processors.getFullEnclosedName(dependency) + "ModuleDeps"); + TypeSpec.Builder generator = + TypeSpec.classBuilder(name.simpleName()) + .addOriginatingElement(dependency) + .addAnnotation(aggregatedDepsAnnotation()) + .addJavadoc("Generated class to pass information through multiple javac runs.\n"); + + Processors.addGeneratedAnnotation(generator, processingEnv, getClass()); + + JavaFile.builder(name.packageName(), generator.build()) + .build() + .writeTo(processingEnv.getFiler()); } private AnnotationSpec aggregatedDepsAnnotation() { diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java deleted file mode 100644 index 09e1651fe..000000000 --- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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.value.AutoValue; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -import dagger.hilt.processor.internal.AnnotationValues; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import java.util.Optional; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -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) { - return AggregatedElements.from(AGGREGATED_DEPS_PACKAGE, ClassNames.AGGREGATED_DEPS, elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static AggregatedDepsMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_DEPS); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - return new AutoValue_AggregatedDepsMetadata( - getTestElement(values.get("test"), elements), - getComponents(values.get("components"), elements), - getDependencyType( - values.get("modules"), - values.get("entryPoints"), - values.get("componentEntryPoints")), - getDependency( - values.get("modules"), - values.get("entryPoints"), - values.get("componentEntryPoints"), - elements), - getReplacedDependencies(values.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/AggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java index 151401e60..58c938f88 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java +++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java @@ -20,7 +20,7 @@ import static com.google.auto.common.AnnotationMirrors.getAnnotationValue; import static com.google.auto.common.MoreElements.asType; import static com.google.auto.common.MoreElements.getPackage; import static com.google.common.collect.Iterables.getOnlyElement; -import static dagger.hilt.processor.internal.HiltCompilerOptions.isModuleInstallInCheckDisabled; +import static dagger.hilt.android.processor.internal.androidentrypoint.HiltCompilerOptions.BooleanOption.DISABLE_MODULES_HAVE_INSTALL_IN_CHECK; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static javax.lang.model.element.ElementKind.CLASS; @@ -37,8 +37,10 @@ import com.squareup.javapoet.ClassName; import dagger.hilt.processor.internal.BaseProcessor; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.Components; +import dagger.hilt.processor.internal.KotlinMetadataUtils; import dagger.hilt.processor.internal.ProcessorErrors; import dagger.hilt.processor.internal.Processors; +import dagger.internal.codegen.kotlin.KotlinMetadataUtil; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -63,7 +65,6 @@ public final class AggregatedDepsProcessor extends BaseProcessor { private static final ImmutableSet<ClassName> ENTRY_POINT_ANNOTATIONS = ImmutableSet.of( ClassNames.ENTRY_POINT, - ClassNames.EARLY_ENTRY_POINT, ClassNames.GENERATED_ENTRY_POINT, ClassNames.COMPONENT_ENTRY_POINT); @@ -165,10 +166,7 @@ public final class AggregatedDepsProcessor extends BaseProcessor { // Check that if Dagger needs an instance of the module, Hilt can provide it automatically by // calling a visible empty constructor. ProcessorErrors.checkState( - // Skip ApplicationContextModule, since Hilt manages this module internally. - ClassNames.APPLICATION_CONTEXT_MODULE.equals(ClassName.get(module)) - || !Processors.requiresModuleInstance(getElementUtils(), module) - || hasVisibleEmptyConstructor(module), + !daggerRequiresModuleInstance(module) || hasVisibleEmptyConstructor(module), module, "Modules that need to be instantiated by Hilt must have a visible, empty constructor."); @@ -188,14 +186,13 @@ public final class AggregatedDepsProcessor extends BaseProcessor { ImmutableList<TypeElement> replacedModules = ImmutableList.of(); if (Processors.hasAnnotation(module, ClassNames.TEST_INSTALL_IN)) { - Optional<TypeElement> originatingTestElement = - Processors.getOriginatingTestElement(module, getElementUtils()); + Optional<TypeElement> originatingTestElement = getOriginatingTestElement(module); ProcessorErrors.checkState( !originatingTestElement.isPresent(), // TODO(b/152801981): this should really error on the annotation value module, "@TestInstallIn modules cannot be nested in (or originate from) a " - + "@HiltAndroidTest-annotated class: %s", + + "@HiltAndroidTest-annotated class: %s", originatingTestElement .map(testElement -> testElement.getQualifiedName().toString()) .orElse("")); @@ -265,10 +262,7 @@ public final class AggregatedDepsProcessor extends BaseProcessor { // Prevent users from uninstalling test-specific @InstallIn modules. ImmutableList<TypeElement> replacedTestSpecificInstallIn = replacedModules.stream() - .filter( - replacedModule -> - Processors.getOriginatingTestElement(replacedModule, getElementUtils()) - .isPresent()) + .filter(replacedModule -> getOriginatingTestElement(replacedModule).isPresent()) .collect(toImmutableList()); ProcessorErrors.checkState( @@ -310,28 +304,6 @@ public final class AggregatedDepsProcessor extends BaseProcessor { element); TypeElement entryPoint = asType(element); - if (entryPointAnnotation.equals(ClassNames.EARLY_ENTRY_POINT)) { - ImmutableSet<ClassName> components = Components.getComponents(getElementUtils(), element); - ProcessorErrors.checkState( - components.equals(ImmutableSet.of(ClassNames.SINGLETON_COMPONENT)), - element, - "@EarlyEntryPoint can only be installed into the SingletonComponent. Found: %s", - components); - - Optional<TypeElement> optionalTestElement = - Processors.getOriginatingTestElement(element, getElementUtils()); - ProcessorErrors.checkState( - !optionalTestElement.isPresent(), - element, - "@EarlyEntryPoint-annotated entry point, %s, cannot be nested in (or originate from) " - + "a @HiltAndroidTest-annotated class, %s. This requirement is to avoid confusion " - + "with other, test-specific entry points.", - asType(element).getQualifiedName().toString(), - optionalTestElement - .map(testElement -> testElement.getQualifiedName().toString()) - .orElse("")); - } - generateAggregatedDeps( entryPointAnnotation.equals(ClassNames.COMPONENT_ENTRY_POINT) ? "componentEntryPoints" @@ -361,8 +333,7 @@ public final class AggregatedDepsProcessor extends BaseProcessor { .generate(); } } else { - Optional<ClassName> testName = - Processors.getOriginatingTestElement(element, getElementUtils()).map(ClassName::get); + Optional<ClassName> testName = getOriginatingTestElement(element).map(ClassName::get); new AggregatedDepsGenerator( key, element, testName, components, replacedModules, getProcessingEnv()) .generate(); @@ -391,6 +362,25 @@ public final class AggregatedDepsProcessor extends BaseProcessor { return Optional.of(getOnlyElement(usedAnnotations)); } + private Optional<TypeElement> getOriginatingTestElement(Element element) { + TypeElement topLevelType = getOriginatingTopLevelType(element); + return Processors.hasAnnotation(topLevelType, ClassNames.HILT_ANDROID_TEST) + ? Optional.of(asType(topLevelType)) + : Optional.empty(); + } + + private TypeElement getOriginatingTopLevelType(Element element) { + TypeElement topLevelType = Processors.getTopLevelType(element); + if (Processors.hasAnnotation(topLevelType, ClassNames.ORIGINATING_ELEMENT)) { + return getOriginatingTopLevelType( + Processors.getAnnotationClassValue( + getElementUtils(), + Processors.getAnnotationMirror(topLevelType, ClassNames.ORIGINATING_ELEMENT), + "topLevelClass")); + } + return topLevelType; + } + private static boolean isValidKind(Element element) { // don't go down the rabbit hole of analyzing undefined types. N.B. we don't issue // an error here because javac already has and we don't want to spam the user. @@ -398,7 +388,7 @@ public final class AggregatedDepsProcessor extends BaseProcessor { } private boolean installInCheckDisabled(Element element) { - return isModuleInstallInCheckDisabled(getProcessingEnv()) + return DISABLE_MODULES_HAVE_INSTALL_IN_CHECK.get(getProcessingEnv()) || Processors.hasAnnotation(element, ClassNames.DISABLE_INSTALL_IN_CHECK); } @@ -445,6 +435,27 @@ public final class AggregatedDepsProcessor extends BaseProcessor { || name.contentEquals("javax.annotation.processing.Generated"); } + private static boolean daggerRequiresModuleInstance(TypeElement module) { + return !module.getModifiers().contains(ABSTRACT) + && !hasOnlyStaticProvides(module) + // Skip ApplicationContextModule, since Hilt manages this module internally. + && !ClassNames.APPLICATION_CONTEXT_MODULE.equals(ClassName.get(module)) + // Skip Kotlin object modules since all their provision methods are static + && !isKotlinObject(module); + } + + private static boolean isKotlinObject(TypeElement type) { + KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil(); + return metadataUtil.isObjectClass(type) || metadataUtil.isCompanionObjectClass(type); + } + + private static boolean hasOnlyStaticProvides(TypeElement module) { + // TODO(erichang): Check for @Produces too when we have a producers story + return ElementFilter.methodsIn(module.getEnclosedElements()).stream() + .filter(method -> Processors.hasAnnotation(method, ClassNames.PROVIDES)) + .allMatch(method -> method.getModifiers().contains(STATIC)); + } + private static boolean hasVisibleEmptyConstructor(TypeElement type) { List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); return constructors.isEmpty() diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD index 5da2241f5..ebbc941bc 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD +++ b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD @@ -39,13 +39,14 @@ java_library( "AggregatedDepsGenerator.java", "AggregatedDepsProcessor.java", "PkgPrivateEntryPointGenerator.java", + "PkgPrivateMetadata.java", "PkgPrivateModuleGenerator.java", ], deps = [ - ":pkg_private_metadata", + "//:dagger_with_compiler", + "//java/dagger/hilt/android/processor/internal/androidentrypoint:compiler_options", "//java/dagger/hilt/processor/internal:base_processor", "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:compiler_options", "//java/dagger/hilt/processor/internal:components", "//java/dagger/hilt/processor/internal:kotlin", "//java/dagger/hilt/processor/internal:processor_errors", @@ -54,21 +55,10 @@ java_library( "//java/dagger/internal/codegen/kotlin", "//java/dagger/internal/guava:collect", "@google_bazel_common//third_party/java/auto:service", - "@google_bazel_common//third_party/java/incap", - "@google_bazel_common//third_party/java/javapoet", - "@maven//:com_google_auto_auto_common", - ], -) - -java_library( - name = "pkg_private_metadata", - srcs = ["PkgPrivateMetadata.java"], - deps = [ - "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:kotlin", - "//java/dagger/hilt/processor/internal:processors", "@google_bazel_common//third_party/java/auto:value", + "@google_bazel_common//third_party/java/incap", "@google_bazel_common//third_party/java/javapoet", + "@google_bazel_common//third_party/java/jsr250_annotations", "@maven//:com_google_auto_auto_common", ], ) @@ -76,17 +66,14 @@ java_library( java_library( name = "component_dependencies", srcs = [ - "AggregatedDepsMetadata.java", "ComponentDependencies.java", ], deps = [ - ":pkg_private_metadata", - "//java/dagger/hilt/processor/internal:aggregated_elements", + ":processor_lib", "//java/dagger/hilt/processor/internal:classnames", "//java/dagger/hilt/processor/internal:component_descriptor", + "//java/dagger/hilt/processor/internal:processor_errors", "//java/dagger/hilt/processor/internal:processors", - "//java/dagger/hilt/processor/internal/earlyentrypoint:aggregated_early_entry_point_metadata", - "//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata", "//java/dagger/internal/codegen/extension", "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java index 897ffd144..23ed148c0 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java +++ b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java @@ -16,17 +16,36 @@ 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.toImmutableSet; import com.google.auto.value.AutoValue; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; 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.earlyentrypoint.AggregatedEarlyEntryPointMetadata; -import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata; +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; @@ -46,23 +65,6 @@ public abstract class ComponentDependencies { /** Returns the component entry point associated with the given a component. */ public abstract Dependencies componentEntryPoints(); - /** Returns the set of early entry points */ - public abstract ImmutableSet<ClassName> earlyEntryPoints(); - - /** Returns {@code true} if any entry points are annotated with {@code EarlyEntryPoints}. */ - public boolean hasEarlyEntryPoints() { - return !earlyEntryPoints().isEmpty(); - } - - /** - * Returns {@code true} if the test binds or uninstalls test-specific bindings that would prevent - * it from sharing components with other test roots. - */ - public final boolean includesTestDeps(ClassName root) { - return modules().testDeps().keySet().stream().anyMatch((key) -> key.test().equals(root)) - || modules().uninstalledTestDeps().containsKey(root); - } - @AutoValue.Builder abstract static class Builder { abstract Dependencies.Builder modulesBuilder(); @@ -71,9 +73,12 @@ public abstract class ComponentDependencies { abstract Dependencies.Builder componentEntryPointsBuilder(); - abstract ImmutableSet.Builder<ClassName> earlyEntryPointsBuilder(); + abstract ComponentDependencies autoBuild(); - abstract ComponentDependencies build(); + ComponentDependencies build(Elements elements) { + validateModules(modulesBuilder().build(), elements); + return autoBuild(); + } } /** A key used for grouping a test dependency by both its component and test name. */ @@ -118,17 +123,6 @@ public abstract class ComponentDependencies { /** Returns the global uninstalled test deps. */ abstract ImmutableSet<TypeElement> globalUninstalledTestDeps(); - /** Returns the dependencies to be installed in the global singleton component. */ - ImmutableSet<TypeElement> getGlobalSingletonDeps() { - return ImmutableSet.<TypeElement>builder() - .addAll( - globalDeps().get(ClassNames.SINGLETON_COMPONENT).stream() - .filter(dep -> !globalUninstalledTestDeps().contains(dep)) - .collect(toImmutableSet())) - .addAll(globalTestDeps().get(ClassNames.SINGLETON_COMPONENT)) - .build(); - } - /** Returns the dependencies to be installed in the given component for the given root. */ public ImmutableSet<TypeElement> get(ClassName component, ClassName root, boolean isTestRoot) { if (!isTestRoot) { @@ -181,10 +175,14 @@ public abstract class ComponentDependencies { */ public static ComponentDependencies from( ImmutableSet<ComponentDescriptor> descriptors, Elements elements) { - ImmutableSet<ClassName> componentNames = - descriptors.stream().map(ComponentDescriptor::component).collect(toImmutableSet()); + Map<String, ComponentDescriptor> descriptorLookup = descriptorLookupMap(descriptors); + ImmutableList<AggregatedDepMetadata> metadatas = + getAggregatedDeps(elements).stream() + .map(deps -> AggregatedDepMetadata.create(deps, descriptorLookup, elements)) + .collect(toImmutableList()); + ComponentDependencies.Builder componentDependencies = ComponentDependencies.builder(); - for (AggregatedDepsMetadata metadata : AggregatedDepsMetadata.from(elements)) { + for (AggregatedDepMetadata metadata : metadatas) { Dependencies.Builder builder = null; switch (metadata.dependencyType()) { case MODULE: @@ -197,46 +195,265 @@ public abstract class ComponentDependencies { builder = componentDependencies.componentEntryPointsBuilder(); break; } - for (TypeElement componentElement : metadata.componentElements()) { - ClassName componentName = ClassName.get(componentElement); - checkState( - componentNames.contains(componentName), "%s is not a valid Component.", componentName); + + for (ComponentDescriptor componentDescriptor : metadata.componentDescriptors()) { + ClassName component = componentDescriptor.component(); 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(componentName, test), metadata.dependency()); + builder.testDepsBuilder().put(TestDepKey.of(component, 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(componentName, metadata.dependency()); + builder.globalTestDepsBuilder().put(component, metadata.dependency()); builder.globalUninstalledTestDepsBuilder().addAll(metadata.replacedDependencies()); } else { - builder.globalDepsBuilder().put(componentName, metadata.dependency()); + builder.globalDepsBuilder().put(component, metadata.dependency()); } } } } - AggregatedUninstallModulesMetadata.from(elements) + // Collect all @UninstallModules. + // TODO(b/176438516): Filter @UninstallModules at the root. + metadatas.stream() + .filter(metadata -> metadata.testElement().isPresent()) + .map(metadata -> metadata.testElement().get()) + .distinct() + .filter(testElement -> Processors.hasAnnotation(testElement, ClassNames.IGNORE_MODULES)) .forEach( - metadata -> + testElement -> componentDependencies .modulesBuilder() .uninstalledTestDepsBuilder() .putAll( - ClassName.get(metadata.testElement()), - metadata.uninstallModuleElements().stream() - .map(module -> PkgPrivateMetadata.publicModule(module, elements)) - .collect(toImmutableSet()))); - - AggregatedEarlyEntryPointMetadata.from(elements).stream() - .map(AggregatedEarlyEntryPointMetadata::earlyEntryPoint) - .map(entryPoint -> PkgPrivateMetadata.publicEarlyEntryPoint(entryPoint, elements)) - .map(ClassName::get) - .forEach(componentDependencies.earlyEntryPointsBuilder()::add); - - return componentDependencies.build(); + ClassName.get(testElement), getUninstalledModules(testElement, elements))); + + 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(); + moduleDeps.testDeps().entries().stream() + .filter( + e -> moduleDeps.uninstalledTestDeps().containsEntry(e.getKey().test(), e.getValue())) + .forEach(e -> invalidTestModules.put(e.getKey().test(), e.getValue())); + + // Currently we don't have a good way to throw an error for all tests, so we sort (to keep the + // error reporting order stable) and then choose the first test. + // TODO(bcorso): Consider using ProcessorErrorHandler directly to report all errors at once? + Optional<ClassName> invalidTest = + invalidTestModules.keySet().stream() + .min((test1, test2) -> test1.toString().compareTo(test2.toString())); + if (invalidTest.isPresent()) { + throw new BadInputException( + String.format( + "@UninstallModules on test, %s, should not containing test modules, " + + "but found: %s", + invalidTest.get(), + invalidTestModules.get(invalidTest.get()).stream() + // Sort modules to keep stable error messages. + .sorted((test1, test2) -> test1.toString().compareTo(test2.toString())) + .collect(toImmutableList())), + elements.getTypeElement(invalidTest.get().toString())); + } + return moduleDeps; + } + + private static ImmutableSet<TypeElement> getUninstalledModules( + TypeElement testElement, Elements elements) { + ImmutableList<TypeElement> userUninstallModules = + Processors.getAnnotationClassValues( + elements, + Processors.getAnnotationMirror(testElement, ClassNames.IGNORE_MODULES), + "value"); + + // For pkg-private modules, find the generated wrapper class and uninstall that instead. + return userUninstallModules.stream() + .map(uninstallModule -> getPublicDependency(uninstallModule, 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); + } + + /** 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()); + } } } diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java index ff344a651..66f175151 100644 --- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java +++ b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java @@ -24,35 +24,16 @@ import com.google.auto.value.AutoValue; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.KotlinMetadataUtils; import dagger.hilt.processor.internal.Processors; import java.util.Optional; import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; /** PkgPrivateModuleMetadata contains a set of utilities for processing package private modules. */ @AutoValue -public abstract class PkgPrivateMetadata { - /** Returns the public Hilt wrapped type or the type itself if it is already public. */ - public static TypeElement publicModule(TypeElement element, Elements elements) { - return publicDep(element, elements, ClassNames.MODULE); - } - - /** Returns the public Hilt wrapped type or the type itself if it is already public. */ - public static TypeElement publicEarlyEntryPoint(TypeElement element, Elements elements) { - return publicDep(element, elements, ClassNames.EARLY_ENTRY_POINT); - } - - private static TypeElement publicDep( - TypeElement element, Elements elements, ClassName annotation) { - return of(elements, element, annotation) - .map(PkgPrivateMetadata::generatedClassName) - .map(ClassName::canonicalName) - .map(elements::getTypeElement) - .orElse(element); - } - +abstract class PkgPrivateMetadata { private static final String PREFIX = "HiltWrapper_"; /** Returns the base class name of the elemenet. */ @@ -82,11 +63,9 @@ public abstract class PkgPrivateMetadata { * Returns an Optional PkgPrivateMetadata requiring Hilt processing, otherwise returns an empty * Optional. */ - static Optional<PkgPrivateMetadata> of( - Elements elements, TypeElement element, ClassName annotation) { + static Optional<PkgPrivateMetadata> of(Elements elements, Element element, ClassName annotation) { // If this is a public element no wrapping is needed - if (effectiveVisibilityOfElement(element) == Visibility.PUBLIC - && !KotlinMetadataUtils.getMetadataUtil().isVisibilityInternal(element)) { + if (effectiveVisibilityOfElement(element) == Visibility.PUBLIC) { return Optional.empty(); } diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java index 02e7f5d56..6efd6431e 100644 --- a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java +++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java @@ -16,7 +16,6 @@ package dagger.hilt.processor.internal.aliasof; -import static com.google.auto.common.MoreElements.asType; import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING; import com.google.auto.service.AutoService; @@ -49,14 +48,13 @@ public final class AliasOfProcessor extends BaseProcessor { "%s should only be used on scopes." + " However, it was found annotating %s", annotation, element); - AnnotationMirror annotationMirror = Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF); - TypeElement defineComponentScope = + Element defineComponentScope = Processors.getAnnotationClassValue(getElementUtils(), annotationMirror, "value"); - new AliasOfPropagatedDataGenerator(getProcessingEnv(), asType(element), defineComponentScope) + new AliasOfPropagatedDataGenerator(getProcessingEnv(), element, defineComponentScope) .generate(); } } diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java index 1d7edf285..75c4c15ac 100644 --- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java +++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java @@ -17,37 +17,43 @@ package dagger.hilt.processor.internal.aliasof; import com.squareup.javapoet.AnnotationSpec; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.TypeSpec; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.Processors; import java.io.IOException; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; +import javax.lang.model.element.Element; /** Generates resource files for {@link dagger.hilt.migration.AliasOf}. */ final class AliasOfPropagatedDataGenerator { private final ProcessingEnvironment processingEnv; - private final TypeElement aliasScope; - private final TypeElement defineComponentScope; + private final Element aliasScope; + private final Element defineComponentScope; AliasOfPropagatedDataGenerator( - ProcessingEnvironment processingEnv, - TypeElement aliasScope, - TypeElement defineComponentScope) { + ProcessingEnvironment processingEnv, Element aliasScope, Element defineComponentScope) { this.processingEnv = processingEnv; this.aliasScope = aliasScope; this.defineComponentScope = defineComponentScope; } void generate() throws IOException { - Processors.generateAggregatingClass( - ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE, - AnnotationSpec.builder(ClassNames.ALIAS_OF_PROPAGATED_DATA) + TypeSpec.Builder generator = + TypeSpec.classBuilder(Processors.getFullEnclosedName(aliasScope)) + .addOriginatingElement(aliasScope) + .addAnnotation( + AnnotationSpec.builder(ClassNames.ALIAS_OF_PROPAGATED_DATA) .addMember("defineComponentScope", "$T.class", defineComponentScope) .addMember("alias", "$T.class", aliasScope) - .build(), - aliasScope, - getClass(), - processingEnv); + .build()) + .addJavadoc("Generated class for aggregating scope aliases. \n"); + + Processors.addGeneratedAnnotation(generator, processingEnv, getClass()); + + JavaFile.builder(AliasOfs.AGGREGATING_PACKAGE, generator.build()) + .build() + .writeTo(processingEnv.getFiler()); } } diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java deleted file mode 100644 index 30a2c70c6..000000000 --- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.aliasof; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -import dagger.hilt.processor.internal.AnnotationValues; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** - * A class that represents the values stored in an {@link - * dagger.hilt.internal.aliasof.AliasOfPropagatedData} annotation. - */ -@AutoValue -abstract class AliasOfPropagatedDataMetadata { - - abstract TypeElement defineComponentScopeElement(); - - abstract TypeElement aliasElement(); - - static ImmutableSet<AliasOfPropagatedDataMetadata> from(Elements elements) { - return AggregatedElements.from( - ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE, - ClassNames.ALIAS_OF_PROPAGATED_DATA, - elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static AliasOfPropagatedDataMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF_PROPAGATED_DATA); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - return new AutoValue_AliasOfPropagatedDataMetadata( - AnnotationValues.getTypeElement(values.get("defineComponentScope")), - AnnotationValues.getTypeElement(values.get("alias"))); - } -} diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java index 18951bdf9..930a72e27 100644 --- a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java +++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java @@ -16,11 +16,23 @@ package dagger.hilt.processor.internal.aliasof; +import static com.google.common.base.Suppliers.memoize; +import com.google.common.base.Preconditions; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSetMultimap; import com.squareup.javapoet.ClassName; +import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.ProcessorErrors; +import dagger.hilt.processor.internal.Processors; +import java.util.List; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.AnnotationMirror; +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; /** @@ -28,33 +40,69 @@ import javax.lang.model.util.Elements; * to scopes they are alias of. */ public final class AliasOfs { - public static AliasOfs create(Elements elements, ImmutableSet<ClassName> defineComponentScopes) { - ImmutableSetMultimap.Builder<ClassName, ClassName> builder = ImmutableSetMultimap.builder(); - AliasOfPropagatedDataMetadata.from(elements) - .forEach( - metadata -> { - ClassName defineComponentScopeName = - ClassName.get(metadata.defineComponentScopeElement()); - ClassName aliasScopeName = ClassName.get(metadata.aliasElement()); - ProcessorErrors.checkState( - defineComponentScopes.contains(defineComponentScopeName), - metadata.aliasElement(), - "The scope %s cannot be an alias for %s. You can only have aliases of a scope" - + " defined directly on a @DefineComponent type.", - aliasScopeName, - defineComponentScopeName); - builder.put(defineComponentScopeName, aliasScopeName); - }); - return new AliasOfs(builder.build()); - } + static final String AGGREGATING_PACKAGE = AliasOfs.class.getPackage().getName() + ".codegen"; - private final ImmutableSetMultimap<ClassName, ClassName> defineComponentScopeToAliases; + private final ProcessingEnvironment processingEnvironment; + private final ImmutableSet<ClassName> defineComponentScopes; + private final Supplier<ImmutableMultimap<ClassName, ClassName>> aliases = + memoize(() -> getAliases()); - private AliasOfs(ImmutableSetMultimap<ClassName, ClassName> defineComponentScopeToAliases) { - this.defineComponentScopeToAliases = defineComponentScopeToAliases; + public AliasOfs( + ProcessingEnvironment processingEnvironment, ImmutableSet<ClassName> defineComponentScopes) { + this.defineComponentScopes = defineComponentScopes; + this.processingEnvironment = processingEnvironment; } public ImmutableSet<ClassName> getAliasesFor(ClassName defineComponentScope) { - return defineComponentScopeToAliases.get(defineComponentScope); + return ImmutableSet.copyOf(aliases.get().get(defineComponentScope)); + } + + private ImmutableMultimap<ClassName, ClassName> getAliases() { + Elements elements = processingEnvironment.getElementUtils(); + PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE); + if (packageElement == null) { + return ImmutableMultimap.of(); + } + List<? extends Element> scopeAliasElements = packageElement.getEnclosedElements(); + Preconditions.checkState( + !scopeAliasElements.isEmpty(), "No scope aliases Found in package %s.", packageElement); + + ImmutableMultimap.Builder<ClassName, ClassName> builder = ImmutableMultimap.builder(); + for (Element element : scopeAliasElements) { + ProcessorErrors.checkState( + element.getKind() == ElementKind.CLASS, + element, + "Only classes may be in package %s. Did you add custom code in the package?", + packageElement); + + AnnotationMirror annotationMirror = + Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF_PROPAGATED_DATA); + + ProcessorErrors.checkState( + annotationMirror != null, + element, + "Classes in package %s must be annotated with @%s: %s." + + " Found: %s. Files in this package are generated, did you add custom code in the" + + " package? ", + packageElement, + ClassNames.ALIAS_OF_PROPAGATED_DATA, + element.getSimpleName(), + element.getAnnotationMirrors()); + + TypeElement defineComponentScope = + Processors.getAnnotationClassValue(elements, annotationMirror, "defineComponentScope"); + TypeElement alias = Processors.getAnnotationClassValue(elements, annotationMirror, "alias"); + + Preconditions.checkState( + defineComponentScopes.contains(ClassName.get(defineComponentScope)), + "The scope %s cannot be an alias for %s. You can only have aliases of a scope defined" + + " directly on a @DefineComponent type.", + ClassName.get(alias), + ClassName.get(defineComponentScope)); + + builder.put(ClassName.get(defineComponentScope), ClassName.get(alias)); + } + + return builder.build(); } } diff --git a/java/dagger/hilt/processor/internal/aliasof/BUILD b/java/dagger/hilt/processor/internal/aliasof/BUILD index ffd0c9ae8..d3f90f2fa 100644 --- a/java/dagger/hilt/processor/internal/aliasof/BUILD +++ b/java/dagger/hilt/processor/internal/aliasof/BUILD @@ -31,6 +31,7 @@ java_library( "AliasOfPropagatedDataGenerator.java", ], deps = [ + ":alias_ofs", "//java/dagger/hilt/processor/internal:base_processor", "//java/dagger/hilt/processor/internal:classnames", "//java/dagger/hilt/processor/internal:processor_errors", @@ -39,24 +40,20 @@ java_library( "@google_bazel_common//third_party/java/auto:service", "@google_bazel_common//third_party/java/incap", "@google_bazel_common//third_party/java/javapoet", - "@maven//:com_google_auto_auto_common", ], ) java_library( name = "alias_ofs", srcs = [ - "AliasOfPropagatedDataMetadata.java", "AliasOfs.java", ], deps = [ - "//java/dagger/hilt/processor/internal:aggregated_elements", "//java/dagger/hilt/processor/internal:classnames", "//java/dagger/hilt/processor/internal:processor_errors", "//java/dagger/hilt/processor/internal:processors", - "//java/dagger/internal/codegen/extension", + "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/auto:value", "@google_bazel_common//third_party/java/javapoet", ], ) diff --git a/java/dagger/hilt/processor/internal/definecomponent/BUILD b/java/dagger/hilt/processor/internal/definecomponent/BUILD index 43f4dfda0..7edec1cba 100644 --- a/java/dagger/hilt/processor/internal/definecomponent/BUILD +++ b/java/dagger/hilt/processor/internal/definecomponent/BUILD @@ -45,18 +45,18 @@ java_library( name = "define_components", srcs = [ "DefineComponentBuilderMetadatas.java", - "DefineComponentClassesMetadata.java", "DefineComponentMetadatas.java", "DefineComponents.java", ], deps = [ - "//java/dagger/hilt/processor/internal:aggregated_elements", "//java/dagger/hilt/processor/internal:classnames", "//java/dagger/hilt/processor/internal:component_descriptor", "//java/dagger/hilt/processor/internal:processor_errors", "//java/dagger/hilt/processor/internal:processors", "//java/dagger/internal/codegen/extension", + "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", + "//java/dagger/internal/guava:graph", "@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/definecomponent/DefineComponentClassesMetadata.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java deleted file mode 100644 index 36ac28fb3..000000000 --- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.definecomponent; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -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 javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** - * A class that represents the values stored in an {@link - * dagger.hilt.internal.definecomponent.DefineComponentClasses} annotation. - */ -@AutoValue -abstract class DefineComponentClassesMetadata { - - /** - * Returns the element annotated with {@code dagger.hilt.internal.definecomponent.DefineComponent} - * or {@code dagger.hilt.internal.definecomponent.DefineComponent.Builder}. - */ - abstract TypeElement element(); - - /** Returns {@code true} if this element represents a component. */ - abstract boolean isComponent(); - - /** Returns {@code true} if this element represents a component builder. */ - boolean isComponentBuilder() { - return !isComponent(); - } - - static ImmutableSet<DefineComponentClassesMetadata> from(Elements elements) { - return AggregatedElements.from( - ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE, - ClassNames.DEFINE_COMPONENT_CLASSES, - elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static DefineComponentClassesMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.DEFINE_COMPONENT_CLASSES); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - String componentName = AnnotationValues.getString(values.get("component")); - String builderName = AnnotationValues.getString(values.get("builder")); - - ProcessorErrors.checkState( - !(componentName.isEmpty() && builderName.isEmpty()), - element, - "@DefineComponentClasses missing both `component` and `builder` members."); - - ProcessorErrors.checkState( - componentName.isEmpty() || builderName.isEmpty(), - element, - "@DefineComponentClasses should not include both `component` and `builder` members."); - - boolean isComponent = !componentName.isEmpty(); - String componentOrBuilderName = isComponent ? componentName : builderName; - TypeElement componentOrBuilderElement = elements.getTypeElement(componentOrBuilderName); - ProcessorErrors.checkState( - componentOrBuilderElement != null, - componentOrBuilderElement, - "%s.%s(), has invalid value: `%s`.", - ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(), - isComponent ? "component" : "builder", - componentOrBuilderName); - return new AutoValue_DefineComponentClassesMetadata(componentOrBuilderElement, isComponent); - } -} diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java index 60864c2c2..aa69e40e1 100644 --- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java +++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java @@ -163,25 +163,15 @@ final class DefineComponentMetadatas { ? Optional.empty() : Optional.of(get(parent, childPath)); - ClassName componentClassName = ClassName.get(component); - ProcessorErrors.checkState( parentComponent.isPresent() - || componentClassName.equals(ClassNames.SINGLETON_COMPONENT), + || ClassName.get(component).equals(ClassNames.SINGLETON_COMPONENT), component, "@DefineComponent %s is missing a parent declaration.\n" + "Please declare the parent, for example: @DefineComponent(parent =" + " SingletonComponent.class)", component); - ProcessorErrors.checkState( - componentClassName.equals(ClassNames.SINGLETON_COMPONENT) - || !componentClassName.simpleName().equals(ClassNames.SINGLETON_COMPONENT.simpleName()), - component, - "Cannot have a component with the same simple name as the reserved %s: %s", - ClassNames.SINGLETON_COMPONENT.simpleName(), - componentClassName); - return new AutoValue_DefineComponentMetadatas_DefineComponentMetadata( component, scopes, parentComponent); } diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java index f7e54a0a7..e0bfca930 100644 --- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java +++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java @@ -22,6 +22,8 @@ import com.google.auto.service.AutoService; import com.google.common.collect.ImmutableSet; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.TypeSpec; import dagger.hilt.processor.internal.BaseProcessor; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.Processors; @@ -68,13 +70,18 @@ public final class DefineComponentProcessor extends BaseProcessor { } private void generateFile(String member, TypeElement typeElement) throws IOException { - Processors.generateAggregatingClass( - ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE, - AnnotationSpec.builder(ClassNames.DEFINE_COMPONENT_CLASSES) - .addMember(member, "$S", typeElement.getQualifiedName()) - .build(), - typeElement, - getClass(), - getProcessingEnv()); + TypeSpec.Builder builder = + TypeSpec.interfaceBuilder(Processors.getFullEnclosedName(typeElement)) + .addOriginatingElement(typeElement) + .addAnnotation( + AnnotationSpec.builder(ClassNames.DEFINE_COMPONENT_CLASSES) + .addMember(member, "$S", typeElement.getQualifiedName()) + .build()); + + Processors.addGeneratedAnnotation(builder, processingEnv, getClass()); + + JavaFile.builder(DefineComponents.AGGREGATING_PACKAGE, builder.build()) + .build() + .writeTo(processingEnv.getFiler()); } } diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java index efa501191..0b330111a 100644 --- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java +++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java @@ -16,22 +16,32 @@ package dagger.hilt.processor.internal.definecomponent; +import static com.google.auto.common.AnnotationMirrors.getAnnotationElementAndValue; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; 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.ArrayListMultimap; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ListMultimap; import com.squareup.javapoet.ClassName; +import dagger.hilt.processor.internal.AnnotationValues; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.ComponentDescriptor; +import dagger.hilt.processor.internal.ComponentTree; import dagger.hilt.processor.internal.ProcessorErrors; +import dagger.hilt.processor.internal.Processors; import dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas.DefineComponentBuilderMetadata; import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata; import java.util.HashMap; import java.util.LinkedHashMap; 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.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; @@ -40,6 +50,8 @@ import javax.lang.model.util.Elements; * DefineComponentBuilderMetadata}. */ public final class DefineComponents { + static final String AGGREGATING_PACKAGE = + DefineComponents.class.getPackage().getName() + ".codegen"; public static DefineComponents create() { return new DefineComponents(); @@ -77,28 +89,14 @@ public final class DefineComponents { return builder.build(); } - /** Returns the set of aggregated {@link ComponentDescriptor}s. */ - public ImmutableSet<ComponentDescriptor> getComponentDescriptors(Elements elements) { - ImmutableSet<DefineComponentClassesMetadata> aggregatedMetadatas = - DefineComponentClassesMetadata.from(elements); - - ImmutableSet<DefineComponentMetadata> components = - aggregatedMetadatas.stream() - .filter(DefineComponentClassesMetadata::isComponent) - .map(DefineComponentClassesMetadata::element) - .map(componentMetadatas::get) - .collect(toImmutableSet()); - - ImmutableSet<DefineComponentBuilderMetadata> builders = - aggregatedMetadatas.stream() - .filter(DefineComponentClassesMetadata::isComponentBuilder) - .map(DefineComponentClassesMetadata::element) - .map(componentBuilderMetadatas::get) - .collect(toImmutableSet()); - + /** Returns the {@link ComponentTree} from the aggregated {@link ComponentDescriptor}s. */ + public ComponentTree getComponentTree(Elements elements) { + AggregatedMetadata aggregatedMetadata = + AggregatedMetadata.from(elements, componentMetadatas, componentBuilderMetadatas); ListMultimap<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMultimap = ArrayListMultimap.create(); - builders.forEach(builder -> builderMultimap.put(builder.componentMetadata(), builder)); + aggregatedMetadata.builders() + .forEach(builder -> builderMultimap.put(builder.componentMetadata(), builder)); // Check that there are not multiple builders per component for (DefineComponentMetadata componentMetadata : builderMultimap.keySet()) { @@ -121,9 +119,10 @@ public final class DefineComponents { Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap = new LinkedHashMap<>(); builderMultimap.entries().forEach(e -> builderMap.put(e.getKey(), e.getValue())); - return components.stream() + + return ComponentTree.from(aggregatedMetadata.components().stream() .map(componentMetadata -> toComponentDescriptor(componentMetadata, builderMap)) - .collect(toImmutableSet()); + .collect(toImmutableSet())); } private static ComponentDescriptor toComponentDescriptor( @@ -147,4 +146,80 @@ public final class DefineComponents { return builder.build(); } + + @AutoValue + abstract static class AggregatedMetadata { + /** Returns the aggregated metadata for {@link DefineComponentClasses#component()}. */ + abstract ImmutableList<DefineComponentMetadata> components(); + + /** Returns the aggregated metadata for {@link DefineComponentClasses#builder()}. */ + abstract ImmutableList<DefineComponentBuilderMetadata> builders(); + + static AggregatedMetadata from( + Elements elements, + DefineComponentMetadatas componentMetadatas, + DefineComponentBuilderMetadatas componentBuilderMetadatas) { + PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE); + + if (packageElement == null) { + return new AutoValue_DefineComponents_AggregatedMetadata( + ImmutableList.of(), ImmutableList.of()); + } + + ImmutableList.Builder<DefineComponentMetadata> components = ImmutableList.builder(); + ImmutableList.Builder<DefineComponentBuilderMetadata> builders = ImmutableList.builder(); + for (Element element : packageElement.getEnclosedElements()) { + ProcessorErrors.checkState( + MoreElements.isType(element), + element, + "Only types may be in package %s. Did you add custom code in the package?", + packageElement); + + TypeElement typeElement = MoreElements.asType(element); + ProcessorErrors.checkState( + Processors.hasAnnotation(typeElement, ClassNames.DEFINE_COMPONENT_CLASSES), + typeElement, + "Class, %s, must be annotated with @%s. Found: %s.", + typeElement, + ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(), + typeElement.getAnnotationMirrors()); + + Optional<TypeElement> component = defineComponentClass(elements, typeElement, "component"); + Optional<TypeElement> builder = defineComponentClass(elements, typeElement, "builder"); + ProcessorErrors.checkState( + component.isPresent() || builder.isPresent(), + typeElement, + "@DefineComponentClasses missing both `component` and `builder` members."); + + component.map(componentMetadatas::get).ifPresent(components::add); + builder.map(componentBuilderMetadatas::get).ifPresent(builders::add); + } + + return new AutoValue_DefineComponents_AggregatedMetadata( + components.build(), builders.build()); + } + + private static Optional<TypeElement> defineComponentClass( + Elements elements, Element element, String annotationMember) { + AnnotationMirror mirror = + Processors.getAnnotationMirror(element, ClassNames.DEFINE_COMPONENT_CLASSES); + AnnotationValue value = getAnnotationElementAndValue(mirror, annotationMember).getValue(); + String className = AnnotationValues.getString(value); + + if (className.isEmpty()) { // The default value. + return Optional.empty(); + } + + TypeElement type = elements.getTypeElement(className); + ProcessorErrors.checkState( + type != null, + element, + "%s.%s(), has invalid value: `%s`.", + ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(), + annotationMember, + className); + + return Optional.of(type); + } + } } diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java deleted file mode 100644 index ae341189c..000000000 --- a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.earlyentrypoint; - -import com.squareup.javapoet.AnnotationSpec; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import java.io.IOException; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; - -/** - * Generates an {@link dagger.hilt.android.internal.earlyentrypoint.AggregatedEarlyEntryPoint} - * annotation. - */ -final class AggregatedEarlyEntryPointGenerator { - - private final ProcessingEnvironment env; - private final TypeElement earlyEntryPoint; - - AggregatedEarlyEntryPointGenerator(TypeElement earlyEntryPoint, ProcessingEnvironment env) { - this.earlyEntryPoint = earlyEntryPoint; - this.env = env; - } - - void generate() throws IOException { - Processors.generateAggregatingClass( - ClassNames.AGGREGATED_EARLY_ENTRY_POINT_PACKAGE, - AnnotationSpec.builder(ClassNames.AGGREGATED_EARLY_ENTRY_POINT) - .addMember("earlyEntryPoint", "$S", earlyEntryPoint.getQualifiedName()) - .build(), - earlyEntryPoint, - getClass(), - env); - } -} diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java deleted file mode 100644 index ed347bd17..000000000 --- a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.earlyentrypoint; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -import dagger.hilt.processor.internal.AnnotationValues; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** - * A class that represents the values stored in an {@link - * dagger.hilt.android.internal.uninstallmodules.AggregatedUninstallModules} annotation. - */ -@AutoValue -public abstract class AggregatedEarlyEntryPointMetadata { - - /** Returns the element annotated with {@link dagger.hilt.android.EarlyEntryPoint}. */ - public abstract TypeElement earlyEntryPoint(); - - /** Returns all aggregated deps in the aggregating package. */ - public static ImmutableSet<AggregatedEarlyEntryPointMetadata> from(Elements elements) { - return AggregatedElements.from( - ClassNames.AGGREGATED_EARLY_ENTRY_POINT_PACKAGE, - ClassNames.AGGREGATED_EARLY_ENTRY_POINT, - elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static AggregatedEarlyEntryPointMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_EARLY_ENTRY_POINT); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - return new AutoValue_AggregatedEarlyEntryPointMetadata( - elements.getTypeElement(AnnotationValues.getString(values.get("earlyEntryPoint")))); - } -} diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD deleted file mode 100644 index 3573e8603..000000000 --- a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2020 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. - -# Description: -# A processor for @dagger.hilt.android.EarlyEntryPoint. - -package(default_visibility = ["//:src"]) - -java_plugin( - name = "processor", - generates_api = 1, - processor_class = "dagger.hilt.processor.internal.earlyentrypoint.EarlyEntryPointProcessor", - deps = [":processor_lib"], -) - -java_library( - name = "processor_lib", - srcs = [ - "AggregatedEarlyEntryPointGenerator.java", - "EarlyEntryPointProcessor.java", - ], - deps = [ - "//java/dagger/hilt/processor/internal:base_processor", - "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:processors", - "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/auto:service", - "@google_bazel_common//third_party/java/incap", - "@google_bazel_common//third_party/java/javapoet", - "@maven//:com_google_auto_auto_common", - ], -) - -java_library( - name = "aggregated_early_entry_point_metadata", - srcs = [ - "AggregatedEarlyEntryPointMetadata.java", - ], - deps = [ - "//java/dagger/hilt/processor/internal:aggregated_elements", - "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:processors", - "//java/dagger/internal/codegen/extension", - "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/auto:value", - ], -) - -filegroup( - name = "srcs_filegroup", - srcs = glob(["*"]), -) diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java b/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java deleted file mode 100644 index 848fa319d..000000000 --- a/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.earlyentrypoint; - -import static com.google.auto.common.MoreElements.asType; -import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING; - -import com.google.auto.service.AutoService; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.BaseProcessor; -import dagger.hilt.processor.internal.ClassNames; -import javax.annotation.processing.Processor; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; - -/** Validates {@link dagger.hilt.android.EarlyEntryPoint} usages. */ -@IncrementalAnnotationProcessor(ISOLATING) -@AutoService(Processor.class) -public final class EarlyEntryPointProcessor extends BaseProcessor { - - @Override - public ImmutableSet<String> getSupportedAnnotationTypes() { - return ImmutableSet.of(ClassNames.EARLY_ENTRY_POINT.toString()); - } - - @Override - public void processEach(TypeElement annotation, Element element) throws Exception { - new AggregatedEarlyEntryPointGenerator(asType(element), getProcessingEnv()).generate(); - } -} diff --git a/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java b/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java deleted file mode 100644 index 722b99b72..000000000 --- a/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.root; - -import com.squareup.javapoet.AnnotationSpec; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import java.io.IOException; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; - -/** Generates an {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot}. */ -final class AggregatedRootGenerator { - private final TypeElement rootElement; - private final TypeElement rootAnnotation; - private final ProcessingEnvironment processingEnv; - - AggregatedRootGenerator( - TypeElement rootElement, TypeElement rootAnnotation, ProcessingEnvironment processingEnv) { - this.rootElement = rootElement; - this.rootAnnotation = rootAnnotation; - this.processingEnv = processingEnv; - } - - void generate() throws IOException { - Processors.generateAggregatingClass( - ClassNames.AGGREGATED_ROOT_PACKAGE, - AnnotationSpec.builder(ClassNames.AGGREGATED_ROOT) - .addMember("root", "$S", rootElement.getQualifiedName()) - .addMember("rootAnnotation", "$T.class", rootAnnotation) - .build(), - rootElement, - getClass(), - processingEnv); - } -} diff --git a/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java b/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java deleted file mode 100644 index 961689b7c..000000000 --- a/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.root; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -import dagger.hilt.processor.internal.AnnotationValues; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** - * Represents the values stored in an {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot}. - */ -@AutoValue -abstract class AggregatedRootMetadata { - - /** Returns the element that was annotated with the root annotation. */ - abstract TypeElement rootElement(); - - /** Returns the root annotation as an element. */ - abstract TypeElement rootAnnotation(); - - static ImmutableSet<AggregatedRootMetadata> from(Elements elements) { - return AggregatedElements.from( - ClassNames.AGGREGATED_ROOT_PACKAGE, ClassNames.AGGREGATED_ROOT, elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static AggregatedRootMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_ROOT); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - return new AutoValue_AggregatedRootMetadata( - elements.getTypeElement(AnnotationValues.getString(values.get("root"))), - AnnotationValues.getTypeElement(values.get("rootAnnotation"))); - } -} diff --git a/java/dagger/hilt/processor/internal/root/BUILD b/java/dagger/hilt/processor/internal/root/BUILD index 5ce762fa6..709eb7f5f 100644 --- a/java/dagger/hilt/processor/internal/root/BUILD +++ b/java/dagger/hilt/processor/internal/root/BUILD @@ -29,14 +29,11 @@ java_plugin( java_library( name = "processor_lib", srcs = [ - "AggregatedRootGenerator.java", - "ComponentGenerator.java", - "EarlySingletonComponentCreatorGenerator.java", - "ProcessedRootSentinelGenerator.java", "RootFileFormatter.java", "RootGenerator.java", "RootProcessor.java", "TestComponentDataGenerator.java", + "TestComponentDataSupplierGenerator.java", "TestInjectorGenerator.java", ], deps = [ @@ -44,7 +41,6 @@ java_library( ":root_type", "//java/dagger/hilt/processor/internal:base_processor", "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:compiler_options", "//java/dagger/hilt/processor/internal:component_descriptor", "//java/dagger/hilt/processor/internal:component_names", "//java/dagger/hilt/processor/internal:processor_errors", @@ -66,18 +62,13 @@ java_library( java_library( name = "root_metadata", srcs = [ - "AggregatedRootMetadata.java", - "ComponentTree.java", - "ProcessedRootSentinelMetadata.java", "Root.java", "RootMetadata.java", "TestRootMetadata.java", ], deps = [ ":root_type", - "//java/dagger/hilt/processor/internal:aggregated_elements", "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:compiler_options", "//java/dagger/hilt/processor/internal:component_descriptor", "//java/dagger/hilt/processor/internal:kotlin", "//java/dagger/hilt/processor/internal:processor_errors", @@ -88,7 +79,6 @@ java_library( "//java/dagger/internal/codegen/kotlin", "//java/dagger/internal/guava:base", "//java/dagger/internal/guava:collect", - "//java/dagger/internal/guava:graph", "@google_bazel_common//third_party/java/auto:value", "@google_bazel_common//third_party/java/javapoet", "@maven//:com_google_auto_auto_common", @@ -100,6 +90,7 @@ java_library( srcs = ["RootType.java"], deps = [ "//java/dagger/hilt/processor/internal:classnames", + "//java/dagger/hilt/processor/internal:processor_errors", "//java/dagger/hilt/processor/internal:processors", "@google_bazel_common//third_party/java/javapoet", ], diff --git a/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java b/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java deleted file mode 100644 index 1dbda3982..000000000 --- a/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.root; - -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.TypeSpec; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import java.io.IOException; -import javax.annotation.processing.ProcessingEnvironment; - -/** Generator for the {@code EarlySingletonComponentCreator}. */ -final class EarlySingletonComponentCreatorGenerator { - private static final ClassName EARLY_SINGLETON_COMPONENT_CREATOR = - ClassName.get("dagger.hilt.android.internal.testing", "EarlySingletonComponentCreator"); - private static final ClassName EARLY_SINGLETON_COMPONENT_CREATOR_IMPL = - ClassName.get( - "dagger.hilt.android.internal.testing", "EarlySingletonComponentCreatorImpl"); - private static final ClassName DEFAULT_COMPONENT_IMPL = - ClassName.get( - "dagger.hilt.android.internal.testing.root", "DaggerDefault_HiltComponents_SingletonC"); - - static void generate(ProcessingEnvironment env) throws IOException { - TypeSpec.Builder builder = - TypeSpec.classBuilder(EARLY_SINGLETON_COMPONENT_CREATOR_IMPL) - .superclass(EARLY_SINGLETON_COMPONENT_CREATOR) - .addMethod( - MethodSpec.methodBuilder("create") - .returns(ClassName.OBJECT) - .addStatement( - "return $T.builder()\n" - + ".applicationContextModule(new $T($T.getApplicationContext()))\n" - + ".build()", - DEFAULT_COMPONENT_IMPL, - ClassNames.APPLICATION_CONTEXT_MODULE, - ClassNames.APPLICATION_PROVIDER) - .build()); - - Processors.addGeneratedAnnotation(builder, env, ClassNames.ROOT_PROCESSOR.toString()); - - JavaFile.builder(EARLY_SINGLETON_COMPONENT_CREATOR_IMPL.packageName(), builder.build()) - .build() - .writeTo(env.getFiler()); - } - - private EarlySingletonComponentCreatorGenerator() {} -} diff --git a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java deleted file mode 100644 index 87efa20a1..000000000 --- a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.root; - -import com.squareup.javapoet.AnnotationSpec; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import java.io.IOException; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; - -/** Generates an {@link dagger.hilt.internal.processedrootsentinel.ProcessedRootSentinel}. */ -final class ProcessedRootSentinelGenerator { - private final TypeElement processedRoot; - private final ProcessingEnvironment processingEnv; - - ProcessedRootSentinelGenerator(TypeElement processedRoot, ProcessingEnvironment processingEnv) { - this.processedRoot = processedRoot; - this.processingEnv = processingEnv; - } - - void generate() throws IOException { - Processors.generateAggregatingClass( - ClassNames.PROCESSED_ROOT_SENTINEL_PACKAGE, - AnnotationSpec.builder(ClassNames.PROCESSED_ROOT_SENTINEL) - .addMember("roots", "$S", processedRoot.getQualifiedName()) - .build(), - processedRoot, - getClass(), - processingEnv); - } -} diff --git a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java deleted file mode 100644 index d60015495..000000000 --- a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.root; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -import dagger.hilt.processor.internal.AnnotationValues; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** - * Represents the values stored in an {@link - * dagger.hilt.internal.processedrootsentinel.ProcessedRootSentinel}. - */ -@AutoValue -abstract class ProcessedRootSentinelMetadata { - - /** Returns the processed root elements. */ - abstract ImmutableSet<TypeElement> rootElements(); - - static ImmutableSet<ProcessedRootSentinelMetadata> from(Elements elements) { - return AggregatedElements.from( - ClassNames.PROCESSED_ROOT_SENTINEL_PACKAGE, - ClassNames.PROCESSED_ROOT_SENTINEL, - elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static ProcessedRootSentinelMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.PROCESSED_ROOT_SENTINEL); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - return new AutoValue_ProcessedRootSentinelMetadata( - AnnotationValues.getStrings(values.get("roots")).stream() - .map(elements::getTypeElement) - .collect(toImmutableSet())); - } -} diff --git a/java/dagger/hilt/processor/internal/root/Root.java b/java/dagger/hilt/processor/internal/root/Root.java index 24440b0c9..981636d62 100644 --- a/java/dagger/hilt/processor/internal/root/Root.java +++ b/java/dagger/hilt/processor/internal/root/Root.java @@ -19,7 +19,6 @@ package dagger.hilt.processor.internal.root; import com.google.auto.common.MoreElements; import com.google.auto.value.AutoValue; import com.squareup.javapoet.ClassName; -import dagger.hilt.processor.internal.ClassNames; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; @@ -27,37 +26,18 @@ import javax.lang.model.element.TypeElement; /** Metadata for a root element that can trigger the {@link RootProcessor}. */ @AutoValue abstract class Root { - /** - * Creates the default root for this (test) build compilation. - * - * <p>A default root installs only the global {@code InstallIn} and {@code TestInstallIn} - * dependencies. Test-specific dependencies are not installed in the default root. - * - * <p>The default root is used for two purposes: - * - * <ul> - * <li>To inject {@code EarlyEntryPoint} annotated interfaces. - * <li>To inject tests that only depend on global dependencies - * </ul> - */ - static Root createDefaultRoot(ProcessingEnvironment env) { - TypeElement rootElement = - env.getElementUtils().getTypeElement(ClassNames.DEFAULT_ROOT.canonicalName()); - return new AutoValue_Root(rootElement, /*isTestRoot=*/ true); - } - /** Creates a {@plainlink Root root} for the given {@plainlink Element element}. */ static Root create(Element element, ProcessingEnvironment env) { TypeElement rootElement = MoreElements.asType(element); - return new AutoValue_Root(rootElement, RootType.of(rootElement).isTestRoot()); + return new AutoValue_Root(RootType.of(env, rootElement), rootElement); } + /** Returns the type of the root {@code element}. */ + abstract RootType type(); + /** Returns the root element that should be used with processing. */ abstract TypeElement element(); - /** Returns {@code true} if this is a test root. */ - abstract boolean isTestRoot(); - /** Returns the class name of the root element. */ ClassName classname() { return ClassName.get(element()); @@ -68,8 +48,7 @@ abstract class Root { return element().toString(); } - /** Returns {@code true} if this uses the default root. */ - boolean isDefaultRoot() { - return classname().equals(ClassNames.DEFAULT_ROOT); + boolean isTestRoot() { + return type().isTestRoot(); } } diff --git a/java/dagger/hilt/processor/internal/root/RootGenerator.java b/java/dagger/hilt/processor/internal/root/RootGenerator.java index f87fbd90b..c2c55e6c4 100644 --- a/java/dagger/hilt/processor/internal/root/RootGenerator.java +++ b/java/dagger/hilt/processor/internal/root/RootGenerator.java @@ -16,7 +16,6 @@ package dagger.hilt.processor.internal.root; -import static com.google.common.base.Preconditions.checkState; import static dagger.hilt.processor.internal.Processors.toClassNames; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static javax.lang.model.element.Modifier.ABSTRACT; @@ -36,11 +35,11 @@ import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.TypeSpec; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.ComponentDescriptor; +import dagger.hilt.processor.internal.ComponentGenerator; import dagger.hilt.processor.internal.ComponentNames; +import dagger.hilt.processor.internal.ComponentTree; import dagger.hilt.processor.internal.Processors; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import java.util.Optional; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Modifier; @@ -48,27 +47,20 @@ import javax.lang.model.element.Modifier; /** Generates components and any other classes needed for a root. */ final class RootGenerator { - static void generate( - RootMetadata metadata, ComponentNames componentNames, ProcessingEnvironment env) - throws IOException { + static void generate(RootMetadata metadata, ProcessingEnvironment env) throws IOException { new RootGenerator( - RootMetadata.copyWithNewTree(metadata, filterDescriptors(metadata.componentTree())), - componentNames, - env) - .generateComponents(); + RootMetadata.copyWithNewTree( + metadata, + filterDescriptors(metadata.componentTree())), + env).generateComponents(); } private final RootMetadata metadata; private final ProcessingEnvironment env; private final Root root; - private final Map<String, Integer> simpleComponentNamesToDedupeSuffix = new HashMap<>(); - private final Map<ComponentDescriptor, ClassName> componentNameMap = new HashMap<>(); - private final ComponentNames componentNames; - private RootGenerator( - RootMetadata metadata, ComponentNames componentNames, ProcessingEnvironment env) { + private RootGenerator(RootMetadata metadata, ProcessingEnvironment env) { this.metadata = metadata; - this.componentNames = componentNames; this.env = env; this.root = metadata.root(); } @@ -76,9 +68,8 @@ final class RootGenerator { private void generateComponents() throws IOException { // TODO(bcorso): Consider moving all of this logic into ComponentGenerator? - ClassName componentsWrapperClassName = getComponentsWrapperClassName(); TypeSpec.Builder componentsWrapper = - TypeSpec.classBuilder(componentsWrapperClassName) + TypeSpec.classBuilder(getComponentsWrapperClassName()) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build()); @@ -102,6 +93,7 @@ final class RootGenerator { new ComponentGenerator( env, getComponentClassName(componentDescriptor), + root.element(), Optional.empty(), modules, metadata.entryPoints(componentDescriptor.component()), @@ -109,14 +101,11 @@ final class RootGenerator { ImmutableList.of(), componentAnnotation(componentDescriptor), componentBuilder(componentDescriptor)) - .typeSpecBuilder() - .addModifiers(Modifier.STATIC) - .build()); + .generate().toBuilder().addModifiers(Modifier.STATIC).build()); } RootFileFormatter.write( - JavaFile.builder(componentsWrapperClassName.packageName(), componentsWrapper.build()) - .build(), + JavaFile.builder(root.classname().packageName(), componentsWrapper.build()).build(), env.getFiler()); } @@ -141,7 +130,7 @@ final class RootGenerator { } private ImmutableMap<ComponentDescriptor, ClassName> subcomponentBuilderModules( - TypeSpec.Builder componentsWrapper) { + TypeSpec.Builder componentsWrapper) throws IOException { ImmutableMap.Builder<ComponentDescriptor, ClassName> modules = ImmutableMap.builder(); for (ComponentDescriptor descriptor : metadata.componentTree().getComponentDescriptors()) { // Root component builders don't have subcomponent builder modules @@ -162,7 +151,7 @@ final class RootGenerator { // @Binds FooSubcomponentInterfaceBuilder bind(FooSubcomponent.Builder builder); // } private TypeSpec subcomponentBuilderModule( - ClassName componentName, ClassName builderName, ClassName moduleName) { + ClassName componentName, ClassName builderName, ClassName moduleName) throws IOException { TypeSpec.Builder subcomponentBuilderModule = TypeSpec.interfaceBuilder(moduleName) .addOriginatingElement(root.element()) @@ -221,38 +210,10 @@ final class RootGenerator { } private ClassName getComponentsWrapperClassName() { - return componentNames.generatedComponentsWrapper(root.classname()); + return ComponentNames.generatedComponentsWrapper(root.classname()); } private ClassName getComponentClassName(ComponentDescriptor componentDescriptor) { - if (componentNameMap.containsKey(componentDescriptor)) { - return componentNameMap.get(componentDescriptor); - } - - // Disallow any component names with the same name as our SingletonComponent because we treat - // that component specially and things may break. - checkState( - componentDescriptor.component().equals(ClassNames.SINGLETON_COMPONENT) - || !componentDescriptor.component().simpleName().equals( - ClassNames.SINGLETON_COMPONENT.simpleName()), - "Cannot have a component with the same simple name as the reserved %s: %s", - ClassNames.SINGLETON_COMPONENT.simpleName(), - componentDescriptor.component()); - - ClassName generatedComponent = - componentNames.generatedComponent(root.classname(), componentDescriptor.component()); - - Integer suffix = simpleComponentNamesToDedupeSuffix.get(generatedComponent.simpleName()); - if (suffix != null) { - // If an entry exists, use the suffix in the map and the replace it with the value incremented - generatedComponent = Processors.append(generatedComponent, String.valueOf(suffix)); - simpleComponentNamesToDedupeSuffix.put(generatedComponent.simpleName(), suffix + 1); - } else { - // Otherwise, just add an entry for any possible future duplicates - simpleComponentNamesToDedupeSuffix.put(generatedComponent.simpleName(), 2); - } - - componentNameMap.put(componentDescriptor, generatedComponent); - return generatedComponent; + return ComponentNames.generatedComponent(root.classname(), componentDescriptor.component()); } } diff --git a/java/dagger/hilt/processor/internal/root/RootMetadata.java b/java/dagger/hilt/processor/internal/root/RootMetadata.java index b39b590ef..4c43f1d61 100644 --- a/java/dagger/hilt/processor/internal/root/RootMetadata.java +++ b/java/dagger/hilt/processor/internal/root/RootMetadata.java @@ -16,22 +16,20 @@ package dagger.hilt.processor.internal.root; -import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Suppliers.memoize; -import static dagger.hilt.processor.internal.HiltCompilerOptions.isSharedTestComponentsEnabled; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static javax.lang.model.element.Modifier.ABSTRACT; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.STATIC; import com.google.common.base.Supplier; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.TypeName; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.ComponentDescriptor; +import dagger.hilt.processor.internal.ComponentTree; import dagger.hilt.processor.internal.KotlinMetadataUtils; import dagger.hilt.processor.internal.Processors; import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies; @@ -55,42 +53,22 @@ public final class RootMetadata { ComponentTree componentTree, ComponentDependencies deps, ProcessingEnvironment env) { - return createInternal(root, ImmutableList.of(), componentTree, deps, env); - } - - static RootMetadata createForDefaultRoot( - Root root, - ImmutableList<RootMetadata> rootsUsingDefaultComponents, - ComponentTree componentTree, - ComponentDependencies deps, - ProcessingEnvironment env) { - checkState(root.isDefaultRoot()); - return createInternal(root, rootsUsingDefaultComponents, componentTree, deps, env); - } - - static RootMetadata copyWithNewTree(RootMetadata other, ComponentTree componentTree) { - return createInternal( - other.root, other.rootsUsingDefaultComponents, componentTree, other.deps, other.env); - } - - private static RootMetadata createInternal( - Root root, - ImmutableList<RootMetadata> rootsUsingDefaultComponents, - ComponentTree componentTree, - ComponentDependencies deps, - ProcessingEnvironment env) { - RootMetadata metadata = - new RootMetadata(root, componentTree, deps, rootsUsingDefaultComponents, env); + RootMetadata metadata = new RootMetadata(root, componentTree, deps, env); metadata.validate(); return metadata; } + static RootMetadata copyWithNewTree( + RootMetadata other, + ComponentTree componentTree) { + return create(other.root, componentTree, other.deps, other.env); + } + private final Root root; private final ProcessingEnvironment env; private final Elements elements; private final ComponentTree componentTree; private final ComponentDependencies deps; - private final ImmutableList<RootMetadata> rootsUsingDefaultComponents; private final Supplier<ImmutableSetMultimap<ClassName, ClassName>> scopesByComponent = memoize(this::getScopesByComponentUncached); private final Supplier<TestRootMetadata> testRootMetadata = @@ -100,14 +78,12 @@ public final class RootMetadata { Root root, ComponentTree componentTree, ComponentDependencies deps, - ImmutableList<RootMetadata> rootsUsingDefaultComponents, ProcessingEnvironment env) { this.root = root; this.env = env; this.elements = env.getElementUtils(); this.componentTree = componentTree; this.deps = deps; - this.rootsUsingDefaultComponents = rootsUsingDefaultComponents; } public Root root() { @@ -126,25 +102,9 @@ public final class RootMetadata { return deps.modules().get(componentName, root.classname(), root.isTestRoot()); } - /** - * Returns {@code true} if this is a test root that provides no test-specific dependencies or sets - * other options that would prevent it from sharing components with other test roots. - */ - // TODO(groakley): Allow more tests to share modules, e.g. tests that uninstall the same module. - // In that case, this might instead return which shared dep grouping should be used. - public boolean canShareTestComponents() { - return isSharedTestComponentsEnabled(env) - && root.isTestRoot() - && !deps.includesTestDeps(root.classname()); - } - public ImmutableSet<TypeName> entryPoints(ClassName componentName) { return ImmutableSet.<TypeName>builder() .addAll(getUserDefinedEntryPoints(componentName)) - .add( - root.isTestRoot() && componentName.equals(ClassNames.SINGLETON_COMPONENT) - ? ClassNames.TEST_SINGLETON_COMPONENT - : ClassNames.GENERATED_COMPONENT) .add(componentName) .build(); } @@ -168,7 +128,6 @@ public final class RootMetadata { } public TestRootMetadata testRootMetadata() { - checkState(!root.isDefaultRoot(), "The default root does not have TestRootMetadata!"); return testRootMetadata.get(); } @@ -190,7 +149,7 @@ public final class RootMetadata { for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) { ClassName componentName = componentDescriptor.component(); for (TypeElement extraModule : modulesThatDaggerCannotConstruct(componentName)) { - if (root.isTestRoot() && !componentName.equals(ClassNames.SINGLETON_COMPONENT)) { + if (root.type().isTestRoot() && !componentName.equals(ClassNames.SINGLETON_COMPONENT)) { env.getMessager() .printMessage( Diagnostic.Kind.ERROR, @@ -198,7 +157,7 @@ public final class RootMetadata { + "static provision methods or have a visible, no-arg constructor. Found: " + extraModule.getQualifiedName(), root.element()); - } else if (!root.isTestRoot()) { + } else if (!root.type().isTestRoot()) { env.getMessager() .printMessage( Diagnostic.Kind.ERROR, @@ -213,19 +172,10 @@ public final class RootMetadata { private ImmutableSet<TypeName> getUserDefinedEntryPoints(ClassName componentName) { ImmutableSet.Builder<TypeName> entryPointSet = ImmutableSet.builder(); - if (root.isDefaultRoot() && !rootsUsingDefaultComponents.isEmpty()) { - // Add entry points for shared component - rootsUsingDefaultComponents.stream() - .flatMap(metadata -> metadata.entryPoints(componentName).stream()) - .forEach(entryPointSet::add); - } else if (root.isDefaultRoot() && componentName.equals(ClassNames.SINGLETON_COMPONENT)) { - // We only do this for SingletonComponent because EarlyEntryPoints can only be installed - // in the SingletonComponent. - deps.earlyEntryPoints().forEach(entryPointSet::add); - } else { - deps.entryPoints().get(componentName, root.classname(), root.isTestRoot()).stream() - .map(ClassName::get) - .forEach(entryPointSet::add); + entryPointSet.add(ClassNames.GENERATED_COMPONENT); + for (TypeElement element : + deps.entryPoints().get(componentName, root.classname(), root.isTestRoot())) { + entryPointSet.add(ClassName.get(element)); } return entryPointSet.build(); } @@ -238,7 +188,7 @@ public final class RootMetadata { .flatMap(descriptor -> descriptor.scopes().stream()) .collect(toImmutableSet()); - AliasOfs aliasOfs = AliasOfs.create(env.getElementUtils(), defineComponentScopes); + AliasOfs aliasOfs = new AliasOfs(env, defineComponentScopes); for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) { for (ClassName scope : componentDescriptor.scopes()) { diff --git a/java/dagger/hilt/processor/internal/root/RootProcessor.java b/java/dagger/hilt/processor/internal/root/RootProcessor.java index 1ee4446d4..8f8c94874 100644 --- a/java/dagger/hilt/processor/internal/root/RootProcessor.java +++ b/java/dagger/hilt/processor/internal/root/RootProcessor.java @@ -17,11 +17,8 @@ package dagger.hilt.processor.internal.root; import static com.google.common.base.Preconditions.checkState; -import static dagger.hilt.processor.internal.HiltCompilerOptions.isCrossCompilationRootValidationDisabled; -import static dagger.hilt.processor.internal.HiltCompilerOptions.isSharedTestComponentsEnabled; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; -import static java.util.Comparator.comparing; import static javax.lang.model.element.Modifier.PUBLIC; import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING; @@ -31,17 +28,16 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.squareup.javapoet.ClassName; import dagger.hilt.processor.internal.BaseProcessor; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.ComponentDescriptor; -import dagger.hilt.processor.internal.ComponentNames; +import dagger.hilt.processor.internal.ComponentTree; import dagger.hilt.processor.internal.ProcessorErrors; import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies; import dagger.hilt.processor.internal.definecomponent.DefineComponents; import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.Processor; @@ -54,10 +50,9 @@ import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; @IncrementalAnnotationProcessor(AGGREGATING) @AutoService(Processor.class) public final class RootProcessor extends BaseProcessor { - private static final Comparator<TypeElement> QUALIFIED_NAME_COMPARATOR = - comparing(TypeElement::getQualifiedName, (n1, n2) -> n1.toString().compareTo(n2.toString())); - + private final List<ClassName> rootNames = new ArrayList<>(); private final Set<ClassName> processed = new HashSet<>(); + private boolean isTestEnv; // TODO(bcorso): Consider using a Dagger component to create/scope these objects private final DefineComponents defineComponents = DefineComponents.create(); private GeneratesRootInputs generatesRootInputs; @@ -81,13 +76,25 @@ public final class RootProcessor extends BaseProcessor { @Override public void processEach(TypeElement annotation, Element element) throws Exception { TypeElement rootElement = MoreElements.asType(element); - RootType rootType = RootType.of(rootElement); - if (rootType.isTestRoot()) { + boolean isTestRoot = RootType.of(getProcessingEnv(), rootElement).isTestRoot(); + checkState( + rootNames.isEmpty() || isTestEnv == isTestRoot, + "Cannot mix test roots with non-test roots:" + + "\n\tNon-Test Roots: %s" + + "\n\tTest Roots: %s", + isTestRoot ? rootNames : rootElement, + isTestRoot ? rootElement : rootNames); + isTestEnv = isTestRoot; + + rootNames.add(ClassName.get(rootElement)); + if (isTestEnv) { new TestInjectorGenerator( - getProcessingEnv(), TestRootMetadata.of(getProcessingEnv(), rootElement)) - .generate(); + getProcessingEnv(), + TestRootMetadata.of(getProcessingEnv(), rootElement)).generate(); + } else { + ProcessorErrors.checkState( + rootNames.size() <= 1, element, "More than one root found: %s", rootNames); } - new AggregatedRootGenerator(rootElement, annotation, getProcessingEnv()).generate(); } @Override @@ -107,22 +114,14 @@ public final class RootProcessor extends BaseProcessor { return; } - ImmutableSet<Root> allRoots = - AggregatedRootMetadata.from(getElementUtils()).stream() - .map(metadata -> Root.create(metadata.rootElement(), getProcessingEnv())) - .collect(toImmutableSet()); - - ImmutableSet<Root> processedRoots = - ProcessedRootSentinelMetadata.from(getElementUtils()).stream() - .flatMap(metadata -> metadata.rootElements().stream()) + ImmutableList<Root> rootsToProcess = + rootNames.stream() + .filter(rootName -> !processed.contains(rootName)) + // We create a new root element each round to avoid the jdk8 bug where + // TypeElement.equals does not work for elements across processing rounds. + .map(rootName -> getElementUtils().getTypeElement(rootName.toString())) .map(rootElement -> Root.create(rootElement, getProcessingEnv())) - .collect(toImmutableSet()); - - ImmutableSet<Root> rootsToProcess = - allRoots.stream() - .filter(root -> !processedRoots.contains(root)) - .filter(root -> !processed.contains(rootName(root))) - .collect(toImmutableSet()); + .collect(toImmutableList()); if (rootsToProcess.isEmpty()) { // Skip further processing since there's no roots that need processing. @@ -133,163 +132,40 @@ public final class RootProcessor extends BaseProcessor { // all roots. We should consider if it's worth trying to continue processing for other // roots. At the moment, I think it's rare that if one root failed the others would not. try { - validateRoots(allRoots, rootsToProcess); - - boolean isTestEnv = rootsToProcess.stream().anyMatch(Root::isTestRoot); - ComponentNames componentNames = - isTestEnv && isSharedTestComponentsEnabled(getProcessingEnv()) - ? ComponentNames.withRenamingIntoPackage( - ClassNames.DEFAULT_ROOT.packageName(), - rootsToProcess.stream().map(Root::element).collect(toImmutableList())) - : ComponentNames.withoutRenaming(); - - ImmutableSet<ComponentDescriptor> componentDescriptors = - defineComponents.getComponentDescriptors(getElementUtils()); - ComponentTree tree = ComponentTree.from(componentDescriptors); - ComponentDependencies deps = - ComponentDependencies.from(componentDescriptors, getElementUtils()); + ComponentTree tree = defineComponents.getComponentTree(getElementUtils()); + ComponentDependencies deps = ComponentDependencies.from( + tree.getComponentDescriptors(), getElementUtils()); ImmutableList<RootMetadata> rootMetadatas = rootsToProcess.stream() .map(root -> RootMetadata.create(root, tree, deps, getProcessingEnv())) .collect(toImmutableList()); for (RootMetadata rootMetadata : rootMetadatas) { - if (!rootMetadata.canShareTestComponents()) { - generateComponents(rootMetadata, componentNames); - } + setProcessingState(rootMetadata.root()); + generateComponents(rootMetadata); } if (isTestEnv) { - ImmutableList<RootMetadata> rootsThatCanShareComponents = - rootMetadatas.stream() - .filter(RootMetadata::canShareTestComponents) - .collect(toImmutableList()); - generateTestComponentData(rootMetadatas, componentNames); - if (deps.hasEarlyEntryPoints() || !rootsThatCanShareComponents.isEmpty()) { - Root defaultRoot = Root.createDefaultRoot(getProcessingEnv()); - generateComponents( - RootMetadata.createForDefaultRoot( - defaultRoot, rootsThatCanShareComponents, tree, deps, getProcessingEnv()), - componentNames); - EarlySingletonComponentCreatorGenerator.generate(getProcessingEnv()); - } + generateTestComponentData(rootMetadatas); } } catch (Exception e) { for (Root root : rootsToProcess) { - processed.add(rootName(root)); + processed.add(root.classname()); } throw e; - } finally { - rootsToProcess.forEach(this::setProcessingState); - // Calculate the roots processed in this round. We do this in the finally-block rather than in - // the try-block because the catch-block can change the processing state. - ImmutableSet<Root> rootsProcessedInRound = - rootsToProcess.stream() - // Only add a sentinel for processed roots. Skip preprocessed roots since those will - // will be processed in the next round. - .filter(root -> processed.contains(rootName(root))) - .collect(toImmutableSet()); - for (Root root : rootsProcessedInRound) { - new ProcessedRootSentinelGenerator(rootElement(root), getProcessingEnv()).generate(); - } - } - } - - private void validateRoots(ImmutableSet<Root> allRoots, ImmutableSet<Root> rootsToProcess) { - - ImmutableSet<TypeElement> rootElementsToProcess = - rootsToProcess.stream() - .map(Root::element) - .sorted(QUALIFIED_NAME_COMPARATOR) - .collect(toImmutableSet()); - - ImmutableSet<TypeElement> appRootElementsToProcess = - rootsToProcess.stream() - .filter(root -> !root.isTestRoot()) - .map(Root::element) - .sorted(QUALIFIED_NAME_COMPARATOR) - .collect(toImmutableSet()); - - // Perform validation between roots in this compilation unit. - if (!appRootElementsToProcess.isEmpty()) { - ImmutableSet<TypeElement> testRootElementsToProcess = - rootsToProcess.stream() - .filter(Root::isTestRoot) - .map(Root::element) - .sorted(QUALIFIED_NAME_COMPARATOR) - .collect(toImmutableSet()); - - ProcessorErrors.checkState( - testRootElementsToProcess.isEmpty(), - "Cannot process test roots and app roots in the same compilation unit:" - + "\n\tApp root in this compilation unit: %s" - + "\n\tTest roots in this compilation unit: %s", - appRootElementsToProcess, - testRootElementsToProcess); - - ProcessorErrors.checkState( - appRootElementsToProcess.size() == 1, - "Cannot process multiple app roots in the same compilation unit: %s", - appRootElementsToProcess); - } - - // Perform validation across roots previous compilation units. - if (!isCrossCompilationRootValidationDisabled(rootElementsToProcess, getProcessingEnv())) { - ImmutableSet<TypeElement> processedTestRootElements = - allRoots.stream() - .filter(Root::isTestRoot) - .filter(root -> !rootsToProcess.contains(root)) - .map(Root::element) - .sorted(QUALIFIED_NAME_COMPARATOR) - .collect(toImmutableSet()); - - // TODO(b/185742783): Add an explanation or link to docs to explain why we're forbidding this. - ProcessorErrors.checkState( - processedTestRootElements.isEmpty(), - "Cannot process new roots when there are test roots from a previous compilation unit:" - + "\n\tTest roots from previous compilation unit: %s" - + "\n\tAll roots from this compilation unit: %s", - processedTestRootElements, - rootElementsToProcess); - - ImmutableSet<TypeElement> processedAppRootElements = - allRoots.stream() - .filter(root -> !root.isTestRoot()) - .filter(root -> !rootsToProcess.contains(root)) - .map(Root::element) - .sorted(QUALIFIED_NAME_COMPARATOR) - .collect(toImmutableSet()); - - ProcessorErrors.checkState( - processedAppRootElements.isEmpty() || appRootElementsToProcess.isEmpty(), - "Cannot process app roots in this compilation unit since there are app roots in a " - + "previous compilation unit:" - + "\n\tApp roots in previous compilation unit: %s" - + "\n\tApp roots in this compilation unit: %s", - processedAppRootElements, - appRootElementsToProcess); } } private void setProcessingState(Root root) { - processed.add(rootName(root)); + processed.add(root.classname()); } - private ClassName rootName(Root root) { - return ClassName.get(rootElement(root)); + private void generateComponents(RootMetadata rootMetadata) throws IOException { + RootGenerator.generate(rootMetadata, getProcessingEnv()); } - private TypeElement rootElement(Root root) { - return root.element(); - } - - private void generateComponents(RootMetadata rootMetadata, ComponentNames componentNames) + private void generateTestComponentData(ImmutableList<RootMetadata> rootMetadatas) throws IOException { - RootGenerator.generate(rootMetadata, componentNames, getProcessingEnv()); - } - - private void generateTestComponentData( - ImmutableList<RootMetadata> rootMetadatas, ComponentNames componentNames) throws IOException { for (RootMetadata rootMetadata : rootMetadatas) { // TODO(bcorso): Consider moving this check earlier into processEach. TypeElement testElement = rootMetadata.testRootMetadata().testElement(); @@ -298,7 +174,8 @@ public final class RootProcessor extends BaseProcessor { testElement, "Hilt tests must be public, but found: %s", testElement); - new TestComponentDataGenerator(getProcessingEnv(), rootMetadata, componentNames).generate(); + new TestComponentDataGenerator(getProcessingEnv(), rootMetadata).generate(); } + new TestComponentDataSupplierGenerator(getProcessingEnv(), rootMetadatas).generate(); } } diff --git a/java/dagger/hilt/processor/internal/root/RootType.java b/java/dagger/hilt/processor/internal/root/RootType.java index 807f71d73..3545231c7 100644 --- a/java/dagger/hilt/processor/internal/root/RootType.java +++ b/java/dagger/hilt/processor/internal/root/RootType.java @@ -19,6 +19,7 @@ package dagger.hilt.processor.internal.root; import com.squareup.javapoet.ClassName; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.Processors; +import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.TypeElement; /** The valid root types for Hilt applications. */ @@ -46,7 +47,7 @@ import javax.lang.model.element.TypeElement; return annotation; } - public static RootType of(TypeElement element) { + public static RootType of(ProcessingEnvironment env, TypeElement element) { if (Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_APP)) { return ROOT; } else if (Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_TEST)) { diff --git a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java b/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java index 101c124d9..284f8cdee 100644 --- a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java +++ b/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java @@ -20,7 +20,6 @@ import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; import static java.util.stream.Collectors.joining; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; -import static javax.lang.model.element.Modifier.PROTECTED; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; import static javax.lang.model.util.ElementFilter.constructorsIn; @@ -46,28 +45,24 @@ public final class TestComponentDataGenerator { private final ProcessingEnvironment processingEnv; private final RootMetadata rootMetadata; private final ClassName name; - private final ComponentNames componentNames; public TestComponentDataGenerator( ProcessingEnvironment processingEnv, - RootMetadata rootMetadata, - ComponentNames componentNames) { + RootMetadata rootMetadata) { this.processingEnv = processingEnv; this.rootMetadata = rootMetadata; - this.componentNames = componentNames; this.name = Processors.append( Processors.getEnclosedClassName(rootMetadata.testRootMetadata().testName()), - "_TestComponentDataSupplier"); + "_ComponentDataHolder"); } /** * * * <pre><code>{@code - * public final class FooTest_TestComponentDataSupplier extends TestComponentDataSupplier { - * @Override - * protected TestComponentData get() { + * public final class FooTest_ComponentDataHolder { + * public static TestComponentData get() { * return new TestComponentData( * false, // waitForBindValue * testInstance -> injectInternal(($1T) testInstance), @@ -88,15 +83,15 @@ public final class TestComponentDataGenerator { public void generate() throws IOException { TypeSpec.Builder generator = TypeSpec.classBuilder(name) - .superclass(ClassNames.TEST_COMPONENT_DATA_SUPPLIER) .addModifiers(PUBLIC, FINAL) + .addMethod(MethodSpec.constructorBuilder().addModifiers(PRIVATE).build()) .addMethod(getMethod()) .addMethod(getTestInjectInternalMethod()); Processors.addGeneratedAnnotation( generator, processingEnv, ClassNames.ROOT_PROCESSOR.toString()); - JavaFile.builder(name.packageName(), generator.build()) + JavaFile.builder(rootMetadata.testRootMetadata().testName().packageName(), generator.build()) .build() .writeTo(processingEnv.getFiler()); } @@ -104,11 +99,8 @@ public final class TestComponentDataGenerator { private MethodSpec getMethod() { TypeElement testElement = rootMetadata.testRootMetadata().testElement(); ClassName component = - componentNames.generatedComponent( - rootMetadata.canShareTestComponents() - ? ClassNames.DEFAULT_ROOT - : ClassName.get(testElement), - ClassNames.SINGLETON_COMPONENT); + ComponentNames.generatedComponent( + ClassName.get(testElement), ClassNames.SINGLETON_COMPONENT); ImmutableSet<TypeElement> daggerRequiredModules = rootMetadata.modulesThatDaggerCannotConstruct(ClassNames.SINGLETON_COMPONENT); ImmutableSet<TypeElement> hiltRequiredModules = @@ -117,7 +109,7 @@ public final class TestComponentDataGenerator { .collect(toImmutableSet()); return MethodSpec.methodBuilder("get") - .addModifiers(PROTECTED) + .addModifiers(PUBLIC, STATIC) .returns(ClassNames.TEST_COMPONENT_DATA) .addStatement( "return new $T($L, $L, $L, $L, $L)", @@ -210,14 +202,14 @@ public final class TestComponentDataGenerator { AnnotationSpec.builder(SuppressWarnings.class) .addMember("value", "$S", "unchecked") .build()) - .addStatement(callInjectTest(testElement)) + .addStatement("$L.injectTest(testInstance)", getInjector(testElement)) .build(); } - private CodeBlock callInjectTest(TypeElement testElement) { + private static CodeBlock getInjector(TypeElement testElement) { return CodeBlock.of( - "(($T) (($T) $T.getApplicationContext()).generatedComponent()).injectTest(testInstance)", - rootMetadata.testRootMetadata().testInjectorName(), + "(($T) (($T) $T.getApplicationContext()).generatedComponent())", + ClassNames.TEST_INJECTOR, ClassNames.GENERATED_COMPONENT_MANAGER, ClassNames.APPLICATION_PROVIDER); } diff --git a/java/dagger/hilt/processor/internal/root/TestComponentDataSupplierGenerator.java b/java/dagger/hilt/processor/internal/root/TestComponentDataSupplierGenerator.java new file mode 100644 index 000000000..e5a83b63c --- /dev/null +++ b/java/dagger/hilt/processor/internal/root/TestComponentDataSupplierGenerator.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020 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.root; + +import static javax.lang.model.element.Modifier.FINAL; +import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.element.Modifier.PROTECTED; +import static javax.lang.model.element.Modifier.PUBLIC; + +import com.google.common.collect.ImmutableList; +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.FieldSpec; +import com.squareup.javapoet.JavaFile; +import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; +import com.squareup.javapoet.TypeSpec; +import com.squareup.javapoet.WildcardTypeName; +import dagger.hilt.processor.internal.ClassNames; +import dagger.hilt.processor.internal.Processors; +import java.io.IOException; +import javax.annotation.processing.ProcessingEnvironment; + +/** Generates an implementation of {@link dagger.hilt.android.internal.TestComponentDataSupplier} */ +public final class TestComponentDataSupplierGenerator { + private static final ClassName TEST_COMPONENT_DATA_SUPPLIER_IMPL = + ClassName.get("dagger.hilt.android.internal.testing", "TestComponentDataSupplierImpl"); + private static final ParameterizedTypeName CLASS_TYPE = + ParameterizedTypeName.get(ClassNames.CLASS, WildcardTypeName.subtypeOf(TypeName.OBJECT)); + private static final ParameterizedTypeName TEST_COMPONENT_DATA_MAP_TYPE = + ParameterizedTypeName.get(ClassNames.MAP, CLASS_TYPE, ClassNames.TEST_COMPONENT_DATA); + + private final ProcessingEnvironment processingEnv; + private final ImmutableList<RootMetadata> rootMetadatas; + + public TestComponentDataSupplierGenerator( + ProcessingEnvironment processingEnv, + ImmutableList<RootMetadata> rootMetadatas) { + this.processingEnv = processingEnv; + this.rootMetadatas = rootMetadatas; + } + + /** + * <pre><code>{@code + * public final class TestComponentDataSupplierImpl extends TestComponentDataSupplier { + * private final Map<Class<?>, TestComponentData> testComponentDataMap = new HashMap<>(); + * + * protected TestComponentDataSupplierImpl() { + * testComponentDataMap.put(FooTest.class, new FooTest_ComponentData()); + * testComponentDataMap.put(BarTest.class, new BarTest_ComponentData()); + * ... + * } + * + * @Override + * protected Map<Class<?>, TestComponentData> get() { + * return testComponentDataMap; + * } + * } + * }</code></pre> + */ + public void generate() throws IOException { + TypeSpec.Builder generator = + TypeSpec.classBuilder(TEST_COMPONENT_DATA_SUPPLIER_IMPL) + .addModifiers(PUBLIC, FINAL) + .superclass(ClassNames.TEST_COMPONENT_DATA_SUPPLIER) + .addField( + FieldSpec.builder( + TEST_COMPONENT_DATA_MAP_TYPE, "testComponentDataMap", PRIVATE, FINAL) + .initializer("new $T<>($L)", ClassNames.HASH_MAP, rootMetadatas.size()) + .build()) + .addMethod(constructor()) + .addMethod(getMethod()); + + Processors.addGeneratedAnnotation( + generator, processingEnv, ClassNames.ROOT_PROCESSOR.toString()); + + JavaFile.builder(TEST_COMPONENT_DATA_SUPPLIER_IMPL.packageName(), generator.build()) + .build() + .writeTo(processingEnv.getFiler()); + } + + + private MethodSpec constructor() { + MethodSpec.Builder constructor = MethodSpec.constructorBuilder(); + for (RootMetadata rootMetadata : rootMetadatas) { + ClassName testName = rootMetadata.testRootMetadata().testName(); + ClassName testComponentDataHolderName = + Processors.append(Processors.getEnclosedClassName(testName), "_ComponentDataHolder"); + constructor.addStatement( + "testComponentDataMap.put($T.class, $T.get())", + testName, + testComponentDataHolderName); + } + return constructor.build(); + } + + private MethodSpec getMethod() { + return MethodSpec.methodBuilder("get") + .addAnnotation(Override.class) + .addModifiers(PROTECTED) + .returns(TEST_COMPONENT_DATA_MAP_TYPE) + .addStatement("return testComponentDataMap") + .build(); + } +} diff --git a/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java b/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java index b7200e7fb..fc97feda6 100644 --- a/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java +++ b/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java @@ -20,6 +20,7 @@ import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; +import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; import dagger.hilt.processor.internal.ClassNames; import dagger.hilt.processor.internal.Processors; @@ -40,9 +41,7 @@ public final class TestInjectorGenerator { // @GeneratedEntryPoint // @InstallIn(SingletonComponent.class) - // public interface FooTest_GeneratedInjector { - // void injectTest(FooTest fooTest); - // } + // public interface FooTest_GeneratedInjector extends TestInjector<FooTest> {} public void generate() throws IOException { TypeSpec.Builder builder = TypeSpec.interfaceBuilder(metadata.testInjectorName()) @@ -54,8 +53,11 @@ public final class TestInjectorGenerator { .addMember("value", "$T.class", installInComponent(metadata.testElement())) .build()) .addModifiers(Modifier.PUBLIC) + .addSuperinterface( + ParameterizedTypeName.get(ClassNames.TEST_INJECTOR, metadata.testName())) .addMethod( MethodSpec.methodBuilder("injectTest") + .addAnnotation(Override.class) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addParameter( metadata.testName(), diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java deleted file mode 100644 index 654a690c4..000000000 --- a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.uninstallmodules; - -import com.google.common.collect.ImmutableList; -import com.squareup.javapoet.AnnotationSpec; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import java.io.IOException; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.element.TypeElement; - -/** - * Generates an {@link dagger.hilt.android.internal.uninstallmodules.AggregatedUninstallModules} - * annotation. - */ -final class AggregatedUninstallModulesGenerator { - - private final ProcessingEnvironment env; - private final TypeElement testElement; - private final ImmutableList<TypeElement> uninstallModuleElements; - - AggregatedUninstallModulesGenerator( - TypeElement testElement, - ImmutableList<TypeElement> uninstallModuleElements, - ProcessingEnvironment env) { - this.testElement = testElement; - this.uninstallModuleElements = uninstallModuleElements; - this.env = env; - } - - void generate() throws IOException { - Processors.generateAggregatingClass( - ClassNames.AGGREGATED_UNINSTALL_MODULES_PACKAGE, - aggregatedUninstallModulesAnnotation(), - testElement, - getClass(), - env); - } - - private AnnotationSpec aggregatedUninstallModulesAnnotation() { - AnnotationSpec.Builder builder = - AnnotationSpec.builder(ClassNames.AGGREGATED_UNINSTALL_MODULES); - builder.addMember("test", "$S", testElement.getQualifiedName()); - uninstallModuleElements.stream() - .map(TypeElement::getQualifiedName) - .forEach(uninstallModule -> builder.addMember("uninstallModules", "$S", uninstallModule)); - return builder.build(); - } -} diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java deleted file mode 100644 index eee78490d..000000000 --- a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.uninstallmodules; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; - -import com.google.auto.value.AutoValue; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import dagger.hilt.processor.internal.AggregatedElements; -import dagger.hilt.processor.internal.AnnotationValues; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.Processors; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -/** - * A class that represents the values stored in an - * {@link dagger.hilt.android.internal.uninstallmodules.AggregatedUninstallModules} annotation. - */ -@AutoValue -public abstract class AggregatedUninstallModulesMetadata { - - /** Returns the test annotated with {@link dagger.hilt.android.testing.UninstallModules}. */ - public abstract TypeElement testElement(); - - /** - * Returns the list of uninstall modules in {@link dagger.hilt.android.testing.UninstallModules}. - */ - public abstract ImmutableList<TypeElement> uninstallModuleElements(); - - /** Returns all aggregated deps in the aggregating package mapped by the top-level element. */ - public static ImmutableSet<AggregatedUninstallModulesMetadata> from(Elements elements) { - return AggregatedElements.from( - ClassNames.AGGREGATED_UNINSTALL_MODULES_PACKAGE, - ClassNames.AGGREGATED_UNINSTALL_MODULES, - elements) - .stream() - .map(aggregatedElement -> create(aggregatedElement, elements)) - .collect(toImmutableSet()); - } - - private static AggregatedUninstallModulesMetadata create(TypeElement element, Elements elements) { - AnnotationMirror annotationMirror = - Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_UNINSTALL_MODULES); - - ImmutableMap<String, AnnotationValue> values = - Processors.getAnnotationValues(elements, annotationMirror); - - return new AutoValue_AggregatedUninstallModulesMetadata( - elements.getTypeElement(AnnotationValues.getString(values.get("test"))), - AnnotationValues.getAnnotationValues(values.get("uninstallModules")).stream() - .map(AnnotationValues::getString) - .map(elements::getTypeElement) - .collect(toImmutableList())); - } -} diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD deleted file mode 100644 index 4f944be48..000000000 --- a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (C) 2020 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. - -# Description: -# A processor for @dagger.hilt.android.testing.UninstallModules. - -package(default_visibility = ["//:src"]) - -java_plugin( - name = "processor", - generates_api = 1, - processor_class = "dagger.hilt.processor.internal.uninstallmodules.UninstallModulesProcessor", - deps = [":processor_lib"], -) - -java_library( - name = "processor_lib", - srcs = [ - "AggregatedUninstallModulesGenerator.java", - "UninstallModulesProcessor.java", - ], - deps = [ - "//java/dagger/hilt/processor/internal:base_processor", - "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:processor_errors", - "//java/dagger/hilt/processor/internal:processors", - "//java/dagger/internal/codegen/extension", - "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/auto:service", - "@google_bazel_common//third_party/java/incap", - "@google_bazel_common//third_party/java/javapoet", - "@maven//:com_google_auto_auto_common", - ], -) - -java_library( - name = "aggregated_uninstall_modules_metadata", - srcs = [ - "AggregatedUninstallModulesMetadata.java", - ], - deps = [ - "//java/dagger/hilt/processor/internal:aggregated_elements", - "//java/dagger/hilt/processor/internal:classnames", - "//java/dagger/hilt/processor/internal:processors", - "//java/dagger/internal/codegen/extension", - "//java/dagger/internal/guava:collect", - "@google_bazel_common//third_party/java/auto:value", - ], -) - -filegroup( - name = "srcs_filegroup", - srcs = glob(["*"]), -) diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java b/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java deleted file mode 100644 index c7e528d9a..000000000 --- a/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2020 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.uninstallmodules; - -import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList; -import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING; - -import com.google.auto.common.MoreElements; -import com.google.auto.service.AutoService; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.squareup.javapoet.ClassName; -import dagger.hilt.processor.internal.BaseProcessor; -import dagger.hilt.processor.internal.ClassNames; -import dagger.hilt.processor.internal.ProcessorErrors; -import dagger.hilt.processor.internal.Processors; -import java.util.Set; -import javax.annotation.processing.Processor; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; - -/** Validates {@link dagger.hilt.android.testing.UninstallModules} usages. */ -@IncrementalAnnotationProcessor(ISOLATING) -@AutoService(Processor.class) -public final class UninstallModulesProcessor extends BaseProcessor { - - @Override - public Set<String> getSupportedAnnotationTypes() { - return ImmutableSet.of(ClassNames.UNINSTALL_MODULES.toString()); - } - - @Override - public void processEach(TypeElement annotation, Element element) throws Exception { - // TODO(bcorso): Consider using RootType to check this? - // TODO(bcorso): Loosen this restriction to allow defining sets of ignored modules in libraries. - ProcessorErrors.checkState( - MoreElements.isType(element) - && Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_TEST), - element, - "@%s should only be used on test classes annotated with @%s, but found: %s", - annotation.getSimpleName(), - ClassNames.HILT_ANDROID_TEST.simpleName(), - element); - - TypeElement testElement = MoreElements.asType(element); - ImmutableList<TypeElement> uninstallModules = - Processors.getAnnotationClassValues( - getElementUtils(), - Processors.getAnnotationMirror(testElement, ClassNames.UNINSTALL_MODULES), - "value"); - - checkModulesHaveInstallIn(testElement, uninstallModules); - checkModulesDontOriginateFromTest(testElement, uninstallModules); - - new AggregatedUninstallModulesGenerator(testElement, uninstallModules, getProcessingEnv()) - .generate(); - } - - private void checkModulesHaveInstallIn( - TypeElement testElement, ImmutableList<TypeElement> uninstallModules) { - ImmutableList<TypeElement> invalidModules = - uninstallModules.stream() - .filter( - module -> - !(Processors.hasAnnotation(module, ClassNames.MODULE) - && Processors.hasAnnotation(module, ClassNames.INSTALL_IN))) - .collect(toImmutableList()); - - ProcessorErrors.checkState( - invalidModules.isEmpty(), - // TODO(b/152801981): Point to the annotation value rather than the annotated element. - testElement, - "@UninstallModules should only include modules annotated with both @Module and @InstallIn, " - + "but found: %s.", - invalidModules); - } - - private void checkModulesDontOriginateFromTest( - TypeElement testElement, ImmutableList<TypeElement> uninstallModules) { - ImmutableList<ClassName> invalidModules = - uninstallModules.stream() - .filter( - module -> - Processors.getOriginatingTestElement(module, getElementUtils()).isPresent()) - .map(ClassName::get) - .collect(toImmutableList()); - - ProcessorErrors.checkState( - invalidModules.isEmpty(), - // TODO(b/152801981): Point to the annotation value rather than the annotated element. - testElement, - "@UninstallModules should not contain test modules, but found: %s", - invalidModules); - } -} |