Merge Android U (ab/10368041)
Bug: 291102124
Merged-In: Ib28f095544608907fc3191b88bf58375c3b2f1ee
Change-Id: I6ba34d8fbadc22a3bccf1e9b368d463b52ccb372
diff --git a/.github/actions/artifact-android-emulator-tests/action.yml b/.github/actions/artifact-android-emulator-tests/action.yml
index 393227c..2fc2987 100644
--- a/.github/actions/artifact-android-emulator-tests/action.yml
+++ b/.github/actions/artifact-android-emulator-tests/action.yml
@@ -12,7 +12,14 @@
- name: 'Check out repository'
uses: actions/checkout@v3
- name: 'Cache Gradle files'
- uses: gradle/gradle-build-action@v2
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
- name: 'Download local snapshot for tests'
uses: actions/download-artifact@v3
with:
diff --git a/.github/actions/artifact-android-local-tests/action.yml b/.github/actions/artifact-android-local-tests/action.yml
index 5b6e837..5410985 100644
--- a/.github/actions/artifact-android-local-tests/action.yml
+++ b/.github/actions/artifact-android-local-tests/action.yml
@@ -12,7 +12,14 @@
- name: 'Check out repository'
uses: actions/checkout@v3
- name: 'Cache Gradle files'
- uses: gradle/gradle-build-action@v2
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
- name: 'Download local snapshot for tests'
uses: actions/download-artifact@v3
with:
diff --git a/.github/actions/artifact-java-local-tests/action.yml b/.github/actions/artifact-java-local-tests/action.yml
index 040dbe3..e3cf770 100644
--- a/.github/actions/artifact-java-local-tests/action.yml
+++ b/.github/actions/artifact-java-local-tests/action.yml
@@ -7,7 +7,14 @@
- name: 'Check out repository'
uses: actions/checkout@v3
- name: 'Cache Gradle files'
- uses: gradle/gradle-build-action@v2
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
- name: 'Download local snapshot for tests'
uses: actions/download-artifact@v3
with:
diff --git a/.github/actions/bazel-build/action.yml b/.github/actions/bazel-build/action.yml
index 63783e6..c464dfe 100644
--- a/.github/actions/bazel-build/action.yml
+++ b/.github/actions/bazel-build/action.yml
@@ -21,6 +21,9 @@
- name: 'Java build'
run: bazel build //java/...
shell: bash
+ - name: 'Install maven version'
+ run: ./util/install-maven.sh ${{ env.USE_MAVEN_VERSION }}
+ shell: bash
- name: 'Install local snapshot'
run: ./util/install-local-snapshot.sh
shell: bash
diff --git a/.github/actions/bazel-test/action.yml b/.github/actions/bazel-test/action.yml
index d0469ec..d84f061 100644
--- a/.github/actions/bazel-test/action.yml
+++ b/.github/actions/bazel-test/action.yml
@@ -31,7 +31,14 @@
restore-keys: |
${{ runner.os }}-bazel-test-
- name: 'Cache Gradle files'
- uses: gradle/gradle-build-action@v2
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
- name: 'Run Bazel tests'
run: bazel test --test_output=errors //...
shell: bash
diff --git a/.github/actions/build-gradle-plugin/action.yml b/.github/actions/build-gradle-plugin/action.yml
index c06bbde..4fb3293 100644
--- a/.github/actions/build-gradle-plugin/action.yml
+++ b/.github/actions/build-gradle-plugin/action.yml
@@ -33,7 +33,17 @@
restore-keys: |
${{ runner.os }}-bazel-build-
- name: 'Cache Gradle files'
- uses: gradle/gradle-build-action@v2
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: 'Install maven version'
+ run: ./util/install-maven.sh ${{ env.USE_MAVEN_VERSION }}
+ shell: bash
- name: 'Build and install Hilt Gradle plugin local snapshot'
run: ./util/deploy-hilt-gradle-plugin.sh "install:install-file" "LOCAL-SNAPSHOT"
shell: bash
diff --git a/.github/actions/test-gradle-plugin/action.yml b/.github/actions/test-gradle-plugin/action.yml
index f68d79b..5523278 100644
--- a/.github/actions/test-gradle-plugin/action.yml
+++ b/.github/actions/test-gradle-plugin/action.yml
@@ -28,7 +28,14 @@
restore-keys: |
${{ runner.os }}-bazel-build-
- name: 'Cache Gradle files'
- uses: gradle/gradle-build-action@v2
+ uses: actions/cache@v2
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
- name: 'Download local snapshot for tests'
uses: actions/download-artifact@v3
with:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 397b0c2..f4650e7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,6 +14,9 @@
# Our Bazel builds currently rely on 5.3.2. The version is set via
# baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk.
USE_BAZEL_VERSION: '5.3.2'
+ # The default Maven 3.9.0 has a regression so we manually install 3.8.7.
+ # https://issues.apache.org/jira/browse/MNG-7679
+ USE_MAVEN_VERSION: '3.8.7'
jobs:
validate-latest-dagger-version:
@@ -71,7 +74,7 @@
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/artifact-android-emulator-tests
- timeout-minutes: 25
+ timeout-minutes: 30 # TODO(b/287486065) investigate whether there is performance regression
with:
api-level: '30'
artifact-android-emulator-legacy-api-tests:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0575623..fd371b1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -14,6 +14,9 @@
# baselisk by USE_BAZEL_VERSION: https://github.com/bazelbuild/bazelisk.
USE_BAZEL_VERSION: '5.3.2'
DAGGER_RELEASE_VERSION: "${{ github.event.inputs.dagger_release_version }}"
+ # The default Maven 3.9.0 has a regression so we manually install 3.8.7.
+ # https://issues.apache.org/jira/browse/MNG-7679
+ USE_MAVEN_VERSION: '3.8.7'
# TODO(bcorso):Convert these jobs into local composite actions to share with the
# continuous integration workflow.
diff --git a/Android.bp b/Android.bp
index 39149e1..f3f6498 100644
--- a/Android.bp
+++ b/Android.bp
@@ -155,6 +155,7 @@
"java/dagger/model/*.java",
"java/dagger/spi/*.java",
"java/dagger/spi/model/*.java",
+ "java/dagger/spi/model/*.kt",
],
exclude_srcs: [
@@ -162,10 +163,6 @@
"java/dagger/internal/codegen/kythe/DaggerKythePlugin.java",
],
- // Manually include META-INF/services/javax.annotation.processing.Processor
- // as the AutoService processor doesn't work properly.
- java_resource_dirs: ["resources"],
-
static_libs: [
"auto_common",
"dagger2",
@@ -175,6 +172,7 @@
"guava",
"javapoet",
"jsr330",
+ "kotlin_symbol_processing_api",
"kotlin-stdlib",
"kotlin-stdlib-jdk8",
"kotlinpoet",
@@ -188,7 +186,6 @@
"auto_value_annotations",
"auto_value_memoized_extension_annotations",
"dagger2-android-annotation-stubs",
- "kotlin_symbol_processing_api",
],
plugins: [
@@ -484,6 +481,10 @@
"java/dagger/hilt/processor/internal/**/*.java",
"java/dagger/hilt/processor/internal/**/*.kt",
],
+ exclude_srcs: [
+ // Depends on DefineComponentValidationProcessingStep which is not present in github.
+ "java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentValidationProcessor.java",
+ ],
plugins: [
"auto_service_plugin",
"auto_value_plugin",
diff --git a/METADATA b/METADATA
index c9c7925..5a52462 100644
--- a/METADATA
+++ b/METADATA
@@ -1,7 +1,9 @@
-name: "dagger2"
-description:
- "A fast dependency injector for Android and Java."
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update dagger2
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+name: "dagger2"
+description: "A fast dependency injector for Android and Java."
third_party {
url {
type: HOMEPAGE
@@ -11,7 +13,11 @@
type: GIT
value: "https://github.com/google/dagger"
}
- version: "dagger-2.41"
- last_upgrade_date { year: 2022 month: 04 day: 04 }
+ version: "dagger-2.47"
license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 8
+ day: 2
+ }
}
diff --git a/README.md b/README.md
index 5f9f5bf..01f3c91 100644
--- a/README.md
+++ b/README.md
@@ -8,10 +8,9 @@
reflection or runtime bytecode generation, does all its analysis at
compile-time, and generates plain Java source code.
-Dagger is actively maintained by the same team that works on [Guava]. Snapshot
-releases are auto-deployed to Sonatype's central Maven repository on every clean
-build with the version `HEAD-SNAPSHOT`. The current version builds upon previous
-work done at [Square][square].
+Dagger is actively maintained by Google. Snapshot releases are auto-deployed to
+Sonatype's central Maven repository on every clean build with the version
+`HEAD-SNAPSHOT`. The current version builds upon previous work done at [Square][square].
## Documentation
@@ -39,8 +38,8 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-DAGGER_TAG = "2.44.2"
-DAGGER_SHA = "cbff42063bfce78a08871d5a329476eb38c96af9cf20d21f8b412fee76296181"
+DAGGER_TAG = "2.46.1"
+DAGGER_SHA = "bbd75275faa3186ebaa08e6779dc5410741a940146d43ef532306eb2682c13f7"
http_archive(
name = "dagger",
strip_prefix = "dagger-dagger-%s" % DAGGER_TAG,
@@ -333,7 +332,6 @@
[GitHub Issues]: https://github.com/google/dagger/issues
[gradle-api-implementation]: https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation
[gradle-api-implementation-android]: https://developer.android.com/studio/build/dependencies#dependency_configurations
-[Guava]: https://github.com/google/guava
[`kapt`]: https://kotlinlang.org/docs/reference/kapt.html
[latestapi]: https://dagger.dev/api/latest/
[mavenbadge-svg]: https://maven-badges.herokuapp.com/maven-central/com.google.dagger/dagger/badge.svg
diff --git a/WORKSPACE b/WORKSPACE
index 84fa4f1..860daf5 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -171,7 +171,7 @@
ERROR_PRONE_VERSION = "2.14.0"
-KSP_VERSION = "1.8.0-1.0.9"
+KSP_VERSION = KOTLIN_VERSION + "-1.0.9"
maven_install(
artifacts = [
@@ -245,7 +245,7 @@
"org.jetbrains.kotlin:kotlin-compiler-embeddable:%s" % KOTLIN_VERSION,
"org.jetbrains.kotlin:kotlin-daemon-embeddable:%s" % KOTLIN_VERSION,
"org.jetbrains.kotlin:kotlin-stdlib:%s" % KOTLIN_VERSION,
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.0",
+ "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.6.2",
"org.mockito:mockito-core:2.28.2",
"org.objenesis:objenesis:1.0",
"org.robolectric:robolectric:4.4",
diff --git a/java/dagger/BindsInstance.java b/java/dagger/BindsInstance.java
index eab8796..5ea7286 100644
--- a/java/dagger/BindsInstance.java
+++ b/java/dagger/BindsInstance.java
@@ -52,7 +52,18 @@
*
* <p>will allow clients of the builder or factory to pass their own instances of {@code Foo} and
* {@code Bar}, and those instances can be injected within the component as {@code Foo} or
- * {@code @Blue Bar}, respectively.
+ * {@code @Blue Bar}, respectively. It's important to note that unlike in factories, the methods in
+ * builders should only accept and bind a single parameter each. Using the following will result in
+ * an error:
+ *
+ * <pre>
+ * {@literal @Component.Builder}
+ * interface Builder {
+ * // Error! Builder methods can only have one parameter
+ * {@literal @BindsInstance} Builder fooAndBar(Foo foo, {@literal @Blue} Bar bar);
+ * ...
+ * }
+ * </pre>
*
* <p>{@code @BindsInstance} arguments may not be {@code null} unless the parameter is annotated
* with {@code @Nullable}.
diff --git a/java/dagger/hilt/BUILD b/java/dagger/hilt/BUILD
index 1de6165..8d25adc 100644
--- a/java/dagger/hilt/BUILD
+++ b/java/dagger/hilt/BUILD
@@ -115,11 +115,11 @@
srcs = glob(["*"]) + [
"//java/dagger/hilt/codegen:srcs_filegroup",
"//java/dagger/hilt/components:srcs_filegroup",
- "//java/dagger/hilt/migration:srcs_filegroup",
"//java/dagger/hilt/internal:srcs_filegroup",
"//java/dagger/hilt/internal/aliasof:srcs_filegroup",
"//java/dagger/hilt/internal/definecomponent:srcs_filegroup",
"//java/dagger/hilt/internal/generatesrootinput:srcs_filegroup",
+ "//java/dagger/hilt/migration:srcs_filegroup",
],
)
diff --git a/java/dagger/hilt/android/internal/lifecycle/RetainedLifecycleImpl.java b/java/dagger/hilt/android/internal/lifecycle/RetainedLifecycleImpl.java
index 5be3144..806377b 100644
--- a/java/dagger/hilt/android/internal/lifecycle/RetainedLifecycleImpl.java
+++ b/java/dagger/hilt/android/internal/lifecycle/RetainedLifecycleImpl.java
@@ -25,7 +25,9 @@
import java.util.Set;
/** Internal implementation. Do not use. */
-public final class RetainedLifecycleImpl implements ActivityRetainedLifecycle, ViewModelLifecycle {
+public final class RetainedLifecycleImpl
+ implements ActivityRetainedLifecycle,
+ ViewModelLifecycle {
private final Set<RetainedLifecycle.OnClearedListener> listeners = new HashSet<>();
private boolean onClearedDispatched = false;
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle
index d333297..3c03495 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/build.gradle
@@ -2,6 +2,10 @@
id 'org.jetbrains.kotlin.jvm'
}
+kotlin {
+ jvmToolchain(11)
+}
+
dependencies {
implementation project(':agp-wrapper')
compileOnly gradleApi()
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt
index 1536af5..1f50794 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/AndroidComponentsExtensionCompatApi70Impl.kt
@@ -25,7 +25,6 @@
private val project: Project
) : AndroidComponentsExtensionCompat {
- @Suppress("UnstableApiUsage")
override fun onAllVariants(block: (ComponentCompat) -> Unit) {
val actual = project.extensions.getByType(AndroidComponentsExtension::class.java)
actual.onVariants { variant ->
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt
index 5c626ef..36c7d77 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-0/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi70Impl.kt
@@ -27,7 +27,7 @@
override val name: String
get() = component.name
- @Suppress("UnstableApiUsage")
+ @Suppress("UnstableApiUsage") // Due to ASM pipeline APIs
override fun <ParamT : InstrumentationParameters> transformClassesWith(
classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
scope: InstrumentationScope,
@@ -36,6 +36,7 @@
component.transformClassesWith(classVisitorFactoryImplClass, scope, instrumentationParamsConfig)
}
+ @Suppress("UnstableApiUsage") // Due to ASM pipeline APIs
override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
component.setAsmFramesComputationMode(mode)
}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle
index ee75692..5bc8d3d 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/build.gradle
@@ -2,6 +2,10 @@
id 'org.jetbrains.kotlin.jvm'
}
+kotlin {
+ jvmToolchain(11)
+}
+
dependencies {
implementation project(':agp-wrapper')
compileOnly gradleApi()
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt
index 9184864..d7c9658 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-1/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi71Impl.kt
@@ -27,7 +27,6 @@
override val name: String
get() = component.name
- @Suppress("UnstableApiUsage")
override fun <ParamT : InstrumentationParameters> transformClassesWith(
classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
scope: InstrumentationScope,
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle
index a6b9207..a413301 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/build.gradle
@@ -2,6 +2,10 @@
id 'org.jetbrains.kotlin.jvm'
}
+kotlin {
+ jvmToolchain(11)
+}
+
dependencies {
implementation project(':agp-wrapper')
compileOnly gradleApi()
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt
index 555a775..ac4abf5 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-7-2/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompatApi72Impl.kt
@@ -27,7 +27,6 @@
override val name: String
get() = component.name
- @Suppress("UnstableApiUsage")
override fun <ParamT : InstrumentationParameters> transformClassesWith(
classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<ParamT>>,
scope: InstrumentationScope,
@@ -40,7 +39,6 @@
)
}
- @Suppress("UnstableApiUsage")
override fun setAsmFramesComputationMode(mode: FramesComputationMode) {
component.instrumentation.setAsmFramesComputationMode(mode)
}
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle
index 7f2bfac..3ad558a 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-impl/build.gradle
@@ -2,6 +2,10 @@
id 'org.jetbrains.kotlin.jvm'
}
+kotlin {
+ jvmToolchain(11)
+}
+
dependencies {
api project(':agp-wrapper')
implementation project(':agp-wrapper-7-0')
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt b/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
index e078003..6c5e781 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
+++ b/java/dagger/hilt/android/plugin/agp-wrapper-impl/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
@@ -24,6 +24,10 @@
val minor: Int,
) : Comparable<SimpleAGPVersion> {
+ override fun toString(): String {
+ return "$major.$minor"
+ }
+
override fun compareTo(other: SimpleAGPVersion): Int {
return compareValuesBy(
this,
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle b/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle
index e959d7a..71ea724 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle
+++ b/java/dagger/hilt/android/plugin/agp-wrapper/build.gradle
@@ -2,6 +2,10 @@
id 'org.jetbrains.kotlin.jvm'
}
+kotlin {
+ jvmToolchain(11)
+}
+
dependencies {
compileOnly gradleApi()
compileOnly "com.android.tools.build:gradle:$agp_version"
diff --git a/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt b/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt
index 2a024c1..acc59e7 100644
--- a/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt
+++ b/java/dagger/hilt/android/plugin/agp-wrapper/src/main/kotlin/dagger/hilt/android/plugin/util/ComponentCompat.kt
@@ -26,7 +26,6 @@
* - In AGP 4.2 its package is 'com.android.build.api.component'
* - In AGP 7.0 its packages is 'com.android.build.api.variant'
*/
-@Suppress("UnstableApiUsage") // ASM Pipeline APIs
abstract class ComponentCompat {
/** Redeclaration of [com.android.build.api.variant.ComponentIdentity.name] */
diff --git a/java/dagger/hilt/android/plugin/build.gradle b/java/dagger/hilt/android/plugin/build.gradle
index 1f75cf9..869d885 100644
--- a/java/dagger/hilt/android/plugin/build.gradle
+++ b/java/dagger/hilt/android/plugin/build.gradle
@@ -1,7 +1,8 @@
buildscript {
ext {
- kotlin_version = "1.8.0"
+ kotlin_version = "1.8.20"
agp_version = System.getenv('AGP_VERSION') ?: "7.2.0"
+ ksp_version = "$kotlin_version-1.0.11"
pluginArtifactId = 'hilt-android-gradle-plugin'
pluginId = 'com.google.dagger.hilt.android'
}
diff --git a/java/dagger/hilt/android/plugin/main/build.gradle b/java/dagger/hilt/android/plugin/main/build.gradle
index 12ba7f4..96a28b9 100644
--- a/java/dagger/hilt/android/plugin/main/build.gradle
+++ b/java/dagger/hilt/android/plugin/main/build.gradle
@@ -64,14 +64,17 @@
implementation gradleApi()
compileOnly "com.android.tools.build:gradle:$agp_version"
compileOnly "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- implementation 'org.javassist:javassist:3.26.0-GA'
+ compileOnly "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp_version"
implementation 'org.ow2.asm:asm:9.0'
implementation "com.squareup:javapoet:1.13.0"
testImplementation gradleTestKit()
testImplementation 'junit:junit:4.12'
testImplementation 'com.google.truth:truth:1.0.1'
+ testImplementation 'org.javassist:javassist:3.26.0-GA'
testPluginCompile 'com.android.tools.build:gradle:7.1.2'
+ testPluginCompile 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0'
+ testPluginCompile 'com.google.devtools.ksp:symbol-processing-gradle-plugin:1.8.0-1.0.9'
}
// Configure the generating task of plugin-under-test-metadata.properties to
@@ -82,16 +85,15 @@
it.pluginClasspath.from(configurations.testPluginCompile)
}
-compileKotlin {
- kotlinOptions {
- jvmTarget = '11'
- allWarningsAsErrors = true
- }
+kotlin {
+ jvmToolchain(11)
}
-java {
- sourceCompatibility JavaVersion.VERSION_11
- targetCompatibility JavaVersion.VERSION_11
+compileKotlin {
+ kotlinOptions {
+ allWarningsAsErrors = true
+ freeCompilerArgs += [ "-opt-in=kotlin.ExperimentalStdlibApi" ]
+ }
}
// Imports a shared library from the main project. The library and its classes
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
deleted file mode 100644
index f31399a..0000000
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
+++ /dev/null
@@ -1,259 +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.android.plugin
-
-import dagger.hilt.android.plugin.util.isClassFile
-import dagger.hilt.android.plugin.util.isJarFile
-import java.io.File
-import java.io.FileInputStream
-import java.util.zip.ZipInputStream
-import javassist.ClassPool
-import javassist.CtClass
-import javassist.Modifier
-import javassist.bytecode.Bytecode
-import javassist.bytecode.CodeIterator
-import javassist.bytecode.Opcode
-import org.slf4j.LoggerFactory
-
-typealias CodeArray = javassist.bytecode.ByteArray // Avoids conflict with Kotlin's stdlib ByteArray
-
-/**
- * A helper class for performing the transform.
- *
- * Create it with the list of all available source directories along with the root output directory
- * and use [AndroidEntryPointClassTransformer.transformFile] or
- * [AndroidEntryPointClassTransformer.transformJarContents] to perform the actual transformation.
- */
-internal class AndroidEntryPointClassTransformer(
- val taskName: String,
- allInputs: List<File>,
- private val sourceRootOutputDir: File,
- private val copyNonTransformed: Boolean
-) {
- private val logger = LoggerFactory.getLogger(AndroidEntryPointClassTransformer::class.java)
-
- // A ClassPool created from the given input files, this allows us to use the higher
- // level Javaassit APIs, but requires class parsing/loading.
- private val classPool: ClassPool = ClassPool(true).also { pool ->
- allInputs.forEach {
- pool.appendClassPath(it.path)
- }
- }
-
- init {
- sourceRootOutputDir.mkdirs()
- }
-
- /**
- * Transforms the classes inside the jar and copies re-written class files if and only if they are
- * transformed.
- *
- * @param inputFile The jar file to transform, must be a jar.
- * @return true if at least one class within the jar was transformed.
- */
- fun transformJarContents(inputFile: File): Boolean {
- require(inputFile.isJarFile()) {
- "Invalid file, '$inputFile' is not a jar."
- }
- // Validate transform is not applied to a jar when copying is enabled, meaning the transformer
- // is being used in the Android transform API pipeline which does not need to transform jars
- // and handles copying them.
- check(!copyNonTransformed) {
- "Transforming a jar is not supported with 'copyNonTransformed'."
- }
- var transformed = false
- ZipInputStream(FileInputStream(inputFile)).use { input ->
- var entry = input.nextEntry
- while (entry != null) {
- if (entry.isClassFile()) {
- val clazz = classPool.makeClass(input, false)
- transformed = transformClassToOutput(clazz) || transformed
- clazz.detach()
- }
- entry = input.nextEntry
- }
- }
- return transformed
- }
-
- /**
- * Transform a single class file.
- *
- * @param inputFile The file to transform, must be a class file.
- * @return true if the class file was transformed.
- */
- fun transformFile(inputFile: File): Boolean {
- check(inputFile.isClassFile()) {
- "Invalid file, '$inputFile' is not a class."
- }
- val clazz = inputFile.inputStream().use { classPool.makeClass(it, false) }
- val transformed = transformClassToOutput(clazz)
- clazz.detach()
- return transformed
- }
-
- private fun transformClassToOutput(clazz: CtClass): Boolean {
- val transformed = transformClass(clazz)
- if (transformed || copyNonTransformed) {
- clazz.writeFile(sourceRootOutputDir.path)
- }
- return transformed
- }
-
- private fun transformClass(clazz: CtClass): Boolean {
- if (ANDROID_ENTRY_POINT_ANNOTATIONS.none { clazz.hasAnnotation(it) }) {
- // Not a Android entry point annotated class, don't do anything.
- return false
- }
-
- // TODO(danysantiago): Handle classes with '$' in their name if they do become an issue.
- val superclassName = clazz.classFile.superclass
- val entryPointSuperclassName =
- clazz.packageName + ".Hilt_" + clazz.simpleName.replace("$", "_")
- logger.info(
- "[$taskName] Transforming ${clazz.name} to extend $entryPointSuperclassName instead of " +
- "$superclassName."
- )
- val entryPointSuperclass = classPool.get(entryPointSuperclassName)
- clazz.superclass = entryPointSuperclass
- transformSuperMethodCalls(clazz, superclassName, entryPointSuperclassName)
-
- // Check if Hilt generated class is a BroadcastReceiver with the marker field which means
- // a super.onReceive invocation has to be inserted in the implementation.
- if (entryPointSuperclass.declaredFields.any { it.name == "onReceiveBytecodeInjectionMarker" }) {
- transformOnReceive(clazz, entryPointSuperclassName)
- }
-
- return true
- }
-
- /**
- * Iterates over each declared method, finding in its bodies super calls. (e.g. super.onCreate())
- * and rewrites the method reference of the invokespecial instruction to one that uses the new
- * superclass.
- *
- * The invokespecial instruction is emitted for code that between other things also invokes a
- * method of a superclass of the current class. The opcode invokespecial takes two operands, each
- * of 8 bit, that together represent an address in the constant pool to a method reference. The
- * method reference is computed at compile-time by looking the direct superclass declaration, but
- * at runtime the code behaves like invokevirtual, where as the actual method invoked is looked up
- * based on the class hierarchy.
- *
- * However, it has been observed that on APIs 19 to 22 the Android Runtime (ART) jumps over the
- * direct superclass and into the method reference class, causing unexpected behaviours.
- * Therefore, this method performs the additional transformation to rewrite direct super call
- * invocations to use a method reference whose class in the pool is the new superclass. Note that
- * this is not necessary for constructor calls since the Javassist library takes care of those.
- *
- * @see: https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html#jvms-6.5.invokespecial
- * @see: https://source.android.com/devices/tech/dalvik/dalvik-bytecode
- */
- private fun transformSuperMethodCalls(
- clazz: CtClass,
- oldSuperclassName: String,
- newSuperclassName: String
- ) {
- val constantPool = clazz.classFile.constPool
- clazz.declaredMethods
- .filter {
- it.methodInfo.isMethod &&
- !Modifier.isStatic(it.modifiers) &&
- !Modifier.isAbstract(it.modifiers) &&
- !Modifier.isNative(it.modifiers)
- }
- .forEach { method ->
- val codeAttr = method.methodInfo.codeAttribute
- val code = codeAttr.code
- codeAttr.iterator().forEachInstruction { index, opcode ->
- // We are only interested in 'invokespecial' instructions.
- if (opcode != Opcode.INVOKESPECIAL) {
- return@forEachInstruction
- }
- // If the method reference of the instruction is not using the old superclass then we
- // should not rewrite it.
- val methodRef = CodeArray.readU16bit(code, index + 1)
- val currentClassRef = constantPool.getMethodrefClassName(methodRef)
- if (currentClassRef != oldSuperclassName) {
- return@forEachInstruction
- }
- // If the method reference of the instruction is a constructor, then we should not
- // rewrite it since its an instantiation and not a `super()` call.
- val methodRefName = constantPool.getMethodrefName(methodRef)
- if (methodRefName == "<init>") {
- return@forEachInstruction
- }
- val nameAndTypeRef = constantPool.getMethodrefNameAndType(methodRef)
- val newSuperclassRef = constantPool.addClassInfo(newSuperclassName)
- val newMethodRef = constantPool.addMethodrefInfo(newSuperclassRef, nameAndTypeRef)
- logger.info(
- "[$taskName] Redirecting an invokespecial in " +
- "${clazz.name}.${method.name}:${method.signature} at code index $index from " +
- "method ref #$methodRef to #$newMethodRef."
- )
- CodeArray.write16bit(newMethodRef, code, index + 1)
- }
- }
- }
-
- // Iterate over each instruction in a CodeIterator.
- private fun CodeIterator.forEachInstruction(body: CodeIterator.(Int, Int) -> Unit) {
- while (hasNext()) {
- val index = next()
- this.body(index, byteAt(index))
- }
- }
-
- /**
- * For a BroadcastReceiver insert a super call in the onReceive method implementation since
- * after the class is transformed onReceive will no longer be abstract (it is implemented by
- * Hilt generated receiver).
- */
- private fun transformOnReceive(clazz: CtClass, entryPointSuperclassName: String) {
- val method = clazz.declaredMethods.first {
- it.name + it.signature == ON_RECEIVE_METHOD_NAME + ON_RECEIVE_METHOD_SIGNATURE
- }
- val constantPool = clazz.classFile.constPool
- val newCode = Bytecode(constantPool).apply {
- addAload(0) // Loads 'this'
- addAload(1) // Loads method param 1 (Context)
- addAload(2) // Loads method param 2 (Intent)
- addInvokespecial(
- entryPointSuperclassName, ON_RECEIVE_METHOD_NAME, ON_RECEIVE_METHOD_SIGNATURE
- )
- }
- val newCodeAttribute = newCode.toCodeAttribute()
- val currentCodeAttribute = method.methodInfo.codeAttribute
- currentCodeAttribute.maxStack =
- maxOf(newCodeAttribute.maxStack, currentCodeAttribute.maxStack)
- currentCodeAttribute.maxLocals =
- maxOf(newCodeAttribute.maxLocals, currentCodeAttribute.maxLocals)
- val codeIterator = currentCodeAttribute.iterator()
- val pos = codeIterator.insertEx(newCode.get()) // insert new code
- codeIterator.insert(newCodeAttribute.exceptionTable, pos) // offset exception table
- method.methodInfo.rebuildStackMap(clazz.classPool) // update stack table
- }
-
- companion object {
- val ANDROID_ENTRY_POINT_ANNOTATIONS = setOf(
- "dagger.hilt.android.AndroidEntryPoint",
- "dagger.hilt.android.HiltAndroidApp"
- )
- val ON_RECEIVE_METHOD_NAME = "onReceive"
- val ON_RECEIVE_METHOD_SIGNATURE =
- "(Landroid/content/Context;Landroid/content/Intent;)V"
- }
-}
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
index 5eff60b..da5fb3c 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
@@ -39,13 +39,11 @@
private val additionalClasses: File
) : ClassVisitor(apiVersion, nextClassVisitor) {
- @Suppress("UnstableApiUsage") // ASM Pipeline APIs
interface AndroidEntryPointParams : InstrumentationParameters {
@get:Internal
val additionalClassesDir: Property<File>
}
- @Suppress("UnstableApiUsage") // ASM Pipeline APIs
abstract class Factory : AsmClassVisitorFactory<AndroidEntryPointParams> {
override fun createClassVisitor(
classContext: ClassContext,
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
deleted file mode 100644
index c9c6708..0000000
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
+++ /dev/null
@@ -1,176 +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.
- */
-
-@file:Suppress("DEPRECATION") // com.android.build.api.transform is deprecated
-
-package dagger.hilt.android.plugin
-
-import com.android.build.api.transform.DirectoryInput
-import com.android.build.api.transform.Format
-import com.android.build.api.transform.JarInput
-import com.android.build.api.transform.QualifiedContent
-import com.android.build.api.transform.Status
-import com.android.build.api.transform.Transform
-import com.android.build.api.transform.TransformInput
-import com.android.build.api.transform.TransformInvocation
-import dagger.hilt.android.plugin.util.isClassFile
-import java.io.File
-
-/**
- * Bytecode transformation to make @AndroidEntryPoint annotated classes extend the Hilt
- * generated android classes, including the @HiltAndroidApp application class.
- *
- * A transform receives input as a collection [TransformInput], which is composed of [JarInput]s and
- * [DirectoryInput]s. The resulting files must be placed in the
- * [TransformInvocation.getOutputProvider]. The bytecode transformation can be done with any library
- * (in our case Javaassit). The [QualifiedContent.Scope] defined in a transform defines the input
- * the transform will receive and if it can be applied to only the Android application projects or
- * Android libraries too.
- *
- * See: [TransformPublic Docs](https://google.github.io/android-gradle-dsl/javadoc/current/com/android/build/api/transform/Transform.html)
- */
-class AndroidEntryPointTransform : Transform() {
- // The name of the transform. This name appears as a gradle task.
- override fun getName() = "AndroidEntryPointTransform"
-
- // The type of input this transform will handle.
- override fun getInputTypes() = setOf(QualifiedContent.DefaultContentType.CLASSES)
-
- override fun isIncremental() = true
-
- // The project scope this transform is applied to.
- override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT)
-
- /**
- * Performs the transformation of the bytecode.
- *
- * The inputs will be available in the [TransformInvocation] along with referenced inputs that
- * should not be transformed. The inputs received along with the referenced inputs depend on the
- * scope of the transform.
- *
- * The invocation will also indicate if an incremental transform has to be applied or not. Even
- * though a transform might return true in its [isIncremental] function, the invocation might
- * return false in [TransformInvocation.isIncremental], therefore both cases must be handled.
- */
- override fun transform(invocation: TransformInvocation) {
- if (!invocation.isIncremental) {
- // Remove any lingering files on a non-incremental invocation since everything has to be
- // transformed.
- invocation.outputProvider.deleteAll()
- }
-
- invocation.inputs.forEach { transformInput ->
- transformInput.jarInputs.forEach { jarInput ->
- val outputJar =
- invocation.outputProvider.getContentLocation(
- jarInput.name,
- jarInput.contentTypes,
- jarInput.scopes,
- Format.JAR
- )
- if (invocation.isIncremental) {
- when (jarInput.status) {
- Status.ADDED, Status.CHANGED -> copyJar(jarInput.file, outputJar)
- Status.REMOVED -> outputJar.delete()
- Status.NOTCHANGED -> {
- // No need to transform.
- }
- else -> {
- error("Unknown status: ${jarInput.status}")
- }
- }
- } else {
- copyJar(jarInput.file, outputJar)
- }
- }
- transformInput.directoryInputs.forEach { directoryInput ->
- val outputDir = invocation.outputProvider.getContentLocation(
- directoryInput.name,
- directoryInput.contentTypes,
- directoryInput.scopes,
- Format.DIRECTORY
- )
- val classTransformer =
- createHiltClassTransformer(invocation.inputs, invocation.referencedInputs, outputDir)
- if (invocation.isIncremental) {
- directoryInput.changedFiles.forEach { (file, status) ->
- val outputFile = toOutputFile(outputDir, directoryInput.file, file)
- when (status) {
- Status.ADDED, Status.CHANGED ->
- transformFile(file, outputFile.parentFile, classTransformer)
- Status.REMOVED -> outputFile.delete()
- Status.NOTCHANGED -> {
- // No need to transform.
- }
- else -> {
- error("Unknown status: $status")
- }
- }
- }
- } else {
- directoryInput.file.walkTopDown().forEach { file ->
- val outputFile = toOutputFile(outputDir, directoryInput.file, file)
- transformFile(file, outputFile.parentFile, classTransformer)
- }
- }
- }
- }
- }
-
- // Create a transformer given an invocation inputs. Note that since this is a PROJECT scoped
- // transform the actual transformation is only done on project files and not its dependencies.
- private fun createHiltClassTransformer(
- inputs: Collection<TransformInput>,
- referencedInputs: Collection<TransformInput>,
- outputDir: File
- ): AndroidEntryPointClassTransformer {
- val classFiles = (inputs + referencedInputs).flatMap { input ->
- (input.directoryInputs + input.jarInputs).map { it.file }
- }
- return AndroidEntryPointClassTransformer(
- taskName = name,
- allInputs = classFiles,
- sourceRootOutputDir = outputDir,
- copyNonTransformed = true
- )
- }
-
- // Transform a single file. If the file is not a class file it is just copied to the output dir.
- private fun transformFile(
- inputFile: File,
- outputDir: File,
- transformer: AndroidEntryPointClassTransformer
- ) {
- if (inputFile.isClassFile()) {
- transformer.transformFile(inputFile)
- } else if (inputFile.isFile) {
- // Copy all non .class files to the output.
- outputDir.mkdirs()
- val outputFile = File(outputDir, inputFile.name)
- inputFile.copyTo(target = outputFile, overwrite = true)
- }
- }
-
- // We are only interested in project compiled classes but we have to copy received jars to the
- // output.
- private fun copyJar(inputJar: File, outputJar: File) {
- outputJar.parentFile?.mkdirs()
- inputJar.copyTo(target = outputJar, overwrite = true)
- }
-
- private fun toOutputFile(outputDir: File, inputDir: File, inputFile: File) =
- File(outputDir, inputFile.relativeTo(inputDir).path)
-}
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltCommandLineArgumentProvider.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltCommandLineArgumentProvider.kt
new file mode 100644
index 0000000..88c9f87
--- /dev/null
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltCommandLineArgumentProvider.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.plugin
+
+import dagger.hilt.processor.internal.optionvalues.GradleProjectType
+import org.gradle.api.tasks.Input
+import org.gradle.process.CommandLineArgumentProvider
+
+/**
+ * Plugin configured annotation processor options provider.
+ */
+internal class HiltCommandLineArgumentProvider(
+ @get:Input
+ val forKsp: Boolean,
+ @get:Input
+ val projectType: GradleProjectType,
+ @get:Input
+ val enableAggregatingTask: Boolean,
+ @get:Input
+ val disableCrossCompilationRootValidation: Boolean
+): CommandLineArgumentProvider {
+
+ private val prefix = if (forKsp) "" else "-A"
+
+ override fun asArguments() = buildMap {
+ // Enable Dagger's fast-init, the best mode for Hilt.
+ put("dagger.fastInit", "enabled")
+ // Disable @AndroidEntryPoint superclass validation.
+ put("dagger.hilt.android.internal.disableAndroidSuperclassValidation", "true")
+ // Report project type for root validation.
+ put("dagger.hilt.android.internal.projectType", projectType.toString())
+
+ // Disable the aggregating processor if aggregating task is enabled.
+ if (enableAggregatingTask) {
+ put("dagger.hilt.internal.useAggregatingRootProcessor", "false")
+ }
+ // Disable cross compilation root validation.
+ // The plugin option duplicates the processor flag because it is an input of the
+ // aggregating task.
+ if (disableCrossCompilationRootValidation) {
+ put("dagger.hilt.disableCrossCompilationRootValidation", "true")
+ }
+ }.map { (key, value) -> "$prefix$key=$value" }
+}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
index f5f71a9..4c78d1b 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
@@ -23,10 +23,10 @@
* If set to `true`, Hilt will adjust the compile classpath such that it includes transitive
* dependencies, ignoring `api` or `implementation` boundaries during compilation. You should
* enable this option if your project has multiple level of transitive dependencies that contain
- * injected classes or entry points.
+ * injected classes or entry points. The default value is `false`.
*
- * Enabling this option also requires android.lintOptions.checkReleaseBuilds to be set to 'false'
- * if the Android Gradle Plugin version being used is less than 7.0.
+ * This option should be enable as a last resort to avoid classpath issues if
+ * [enableAggregatingTask] (set to `true` by default) causes issues.
*
* See https://github.com/google/dagger/issues/1991 for more context.
*/
@@ -37,22 +37,26 @@
* annotated classes before the host-side JVM tests run. You should enable this option if you are
* running Robolectric UI tests as part of your JUnit tests.
*
- * This flag is not necessary if when com.android.tools.build:gradle:4.2.0+ is used and will be
- * deprecated in a future version.
+ * This flag is not necessary when com.android.tools.build:gradle:4.2.0+ is used.
*/
+ @Deprecated("Since Hilt Android Gradle plugin requires the usage of the Android " +
+ "Gradle plugin (AGP) version 7.0 or higher this option is no longer necessary and has no " +
+ "effect in the configuration.")
var enableTransformForLocalTests: Boolean
/**
* If set to `true`, Hilt will perform module and entry points aggregation in a task instead of an
- * aggregating annotation processor. Enabling this flag improves incremental build times.
+ * aggregating annotation processor. Enabling this flag improves incremental build times. The
+ * default value is `true`.
*
* When this flag is enabled, 'enableExperimentalClasspathAggregation' has no effect since
- * classpath aggregation will be done by default.
+ * classpath aggregation is already performed by the aggregation task.
*/
var enableAggregatingTask: Boolean
/**
- * If set to `true`, Hilt will disable cross compilation root validation.
+ * If set to `true`, Hilt will disable cross compilation root validation. The default value is
+ * `false`.
*
* See [documentation](https://dagger.dev/hilt/flags#disable-cross-compilation-root-validation)
* for more information.
@@ -62,6 +66,9 @@
internal open class HiltExtensionImpl : HiltExtension {
override var enableExperimentalClasspathAggregation: Boolean = false
+ @Deprecated("Since Hilt Android Gradle plugin requires the usage of the Android " +
+ "Gradle plugin (AGP) version 7.0 or higher this option is no longer necessary and has no " +
+ "effect in the configuration.")
override var enableTransformForLocalTests: Boolean = false
override var enableAggregatingTask: Boolean = true
override var disableCrossCompilationRootValidation: Boolean = false
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
index f2dd881..4e2b878 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
@@ -22,30 +22,32 @@
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.TestExtension
-import com.android.build.gradle.TestedExtension
import com.android.build.gradle.api.AndroidBasePlugin
import com.android.build.gradle.tasks.JdkImageInput
import dagger.hilt.android.plugin.task.AggregateDepsTask
-import dagger.hilt.android.plugin.task.HiltTransformTestClassesTask
import dagger.hilt.android.plugin.util.AggregatedPackagesTransform
import dagger.hilt.android.plugin.util.ComponentCompat
import dagger.hilt.android.plugin.util.CopyTransform
import dagger.hilt.android.plugin.util.SimpleAGPVersion
+import dagger.hilt.android.plugin.util.addJavaTaskProcessorOptions
+import dagger.hilt.android.plugin.util.addKaptTaskProcessorOptions
+import dagger.hilt.android.plugin.util.addKspTaskProcessorOptions
import dagger.hilt.android.plugin.util.capitalize
import dagger.hilt.android.plugin.util.getAndroidComponentsExtension
import dagger.hilt.android.plugin.util.getKaptConfigName
-import dagger.hilt.android.plugin.util.getSdkPath
+import dagger.hilt.android.plugin.util.getKspConfigName
+import dagger.hilt.android.plugin.util.isKspTask
import dagger.hilt.processor.internal.optionvalues.GradleProjectType
import java.io.File
import javax.inject.Inject
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
+import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.attributes.Attribute
import org.gradle.api.provider.ProviderFactory
-import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.process.CommandLineArgumentProvider
import org.gradle.util.GradleVersion
@@ -60,7 +62,7 @@
* update the superclass.
*/
class HiltGradlePlugin @Inject constructor(
- val providers: ProviderFactory
+ private val providers: ProviderFactory
) : Plugin<Project> {
override fun apply(project: Project) {
var configured = false
@@ -82,15 +84,13 @@
val hiltExtension = project.extensions.create(
HiltExtension::class.java, "hilt", HiltExtensionImpl::class.java
)
+ if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(7, 0)) {
+ error("The Hilt Android Gradle plugin is only compatible with Android Gradle plugin (AGP) " +
+ "version 7.0 or higher (found ${SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION}).")
+ }
configureDependencyTransforms(project)
configureCompileClasspath(project, hiltExtension)
- if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(4, 2)) {
- // Configures bytecode transform using older APIs pre AGP 4.2
- configureBytecodeTransform(project, hiltExtension)
- } else {
- // Configures bytecode transform using AGP 4.2 ASM pipeline.
- configureBytecodeTransformASM(project, hiltExtension)
- }
+ configureBytecodeTransformASM(project)
configureAggregatingTask(project, hiltExtension)
configureProcessorFlags(project, hiltExtension)
}
@@ -242,17 +242,8 @@
project.dependencies.add(compileOnlyConfigName, artifactView.files)
}
- @Suppress("UnstableApiUsage") // ASM Pipeline APIs
- private fun configureBytecodeTransformASM(project: Project, hiltExtension: HiltExtension) {
- var warnAboutLocalTestsFlag = false
+ private fun configureBytecodeTransformASM(project: Project) {
fun registerTransform(androidComponent: ComponentCompat) {
- if (hiltExtension.enableTransformForLocalTests && !warnAboutLocalTestsFlag) {
- project.logger.warn(
- "The Hilt configuration option 'enableTransformForLocalTests' is no longer necessary " +
- "when com.android.tools.build:gradle:4.2.0+ is used."
- )
- warnAboutLocalTestsFlag = true
- }
androidComponent.transformClassesWith(
classVisitorFactoryImplClass = AndroidEntryPointClassVisitor.Factory::class.java,
scope = InstrumentationScope.PROJECT
@@ -268,24 +259,6 @@
getAndroidComponentsExtension(project).onAllVariants { registerTransform(it) }
}
- private fun configureBytecodeTransform(project: Project, hiltExtension: HiltExtension) {
- val androidExtension = project.baseExtension() ?: error("Android BaseExtension not found.")
- androidExtension::class.java.getMethod(
- "registerTransform",
- Class.forName("com.android.build.api.transform.Transform"),
- Array<Any>::class.java
- ).invoke(androidExtension, AndroidEntryPointTransform(), emptyArray<Any>())
-
- // Create and configure a task for applying the transform for host-side unit tests. b/37076369
- project.testedExtension()?.unitTestVariants?.all { unitTestVariant ->
- HiltTransformTestClassesTask.create(
- project = project,
- unitTestVariant = unitTestVariant,
- extension = hiltExtension
- )
- }
- }
-
private fun configureAggregatingTask(project: Project, hiltExtension: HiltExtension) {
val androidExtension = project.baseExtension() ?: error("Android BaseExtension not found.")
androidExtension.forEachRootVariant { variant ->
@@ -307,15 +280,18 @@
val hiltCompileConfiguration = project.configurations.create(
"hiltCompileOnly${variant.name.capitalize()}"
).apply {
+ description = "Hilt aggregated compile only dependencies for '${variant.name}'"
isCanBeConsumed = false
isCanBeResolved = true
+ isVisible = false
}
// Add the JavaCompile task classpath and output dir to the config, the task's classpath
// will contain:
// * compileOnly dependencies
- // * KAPT and Kotlinc generated bytecode
+ // * KAPT, KSP and Kotlinc generated bytecode
// * R.jar
// * Tested classes if the variant is androidTest
+ // TODO(danysantiago): Revisit to support K2 compiler
project.dependencies.add(
hiltCompileConfiguration.name,
project.files(variant.javaCompileProvider.map { it.classpath })
@@ -325,8 +301,34 @@
project.files(variant.javaCompileProvider.map {it.destinationDirectory.get() })
)
+ val hiltAnnotationProcessorConfiguration = project.configurations.create(
+ "hiltAnnotationProcessor${variant.name.capitalize()}"
+ ).also { config ->
+ config.description = "Hilt annotation processor classpath for '${variant.name}'"
+ config.isCanBeConsumed = false
+ config.isCanBeResolved = true
+ config.isVisible = false
+ // Add user annotation processor configuration, so that SPI plugins and other processors
+ // are discoverable.
+ val apConfigurations: List<Configuration> = buildList {
+ add(variant.annotationProcessorConfiguration)
+ project.plugins.withId("kotlin-kapt") {
+ project.configurations.findByName(getKaptConfigName(variant))?.let { add(it) }
+ }
+ project.plugins.withId("com.google.devtools.ksp") {
+ // Add the main 'ksp' config since the variant aware config does not extend main.
+ // https://github.com/google/ksp/issues/1433
+ project.configurations.findByName("ksp")?.let { add(it) }
+ project.configurations.findByName(getKspConfigName(variant))?.let { add(it) }
+ }
+ }
+ config.extendsFrom(*apConfigurations.toTypedArray())
+ // Add hilt-compiler even though it might be in the AP configurations already.
+ project.dependencies.add(config.name, "com.google.dagger:hilt-compiler:$HILT_VERSION")
+ }
+
fun getInputClasspath(artifactAttributeValue: String) =
- mutableListOf<Configuration>().apply {
+ buildList<Configuration> {
@Suppress("DEPRECATION") // Older variant API is deprecated
if (variant is com.android.build.gradle.api.TestVariant) {
add(variant.testedVariant.runtimeConfiguration)
@@ -399,21 +401,7 @@
}
compileTask.destinationDirectory.set(componentClasses.singleFile)
compileTask.options.apply {
- annotationProcessorPath = project.configurations.create(
- "hiltAnnotationProcessor${variant.name.capitalize()}"
- ).also { config ->
- config.isCanBeConsumed = false
- config.isCanBeResolved = true
- // Add user annotation processor configuration, so that SPI plugins and other processors
- // are discoverable.
- val apConfigurations: List<Configuration> = mutableListOf<Configuration>().apply {
- add(variant.annotationProcessorConfiguration)
- project.configurations.findByName(getKaptConfigName(variant))?.let { add(it) }
- }
- config.extendsFrom(*apConfigurations.toTypedArray())
- // Add hilt-compiler even though it might be in the AP configurations already.
- project.dependencies.add(config.name, "com.google.dagger:hilt-compiler:$HILT_VERSION")
- }
+ annotationProcessorPath = hiltAnnotationProcessorConfiguration
generatedSourceOutputDirectory.set(
project.file(
project.buildDir.resolve("generated/hilt/component_sources/${variant.name}/")
@@ -440,12 +428,8 @@
variant.registerPostJavacGeneratedBytecode(componentClasses)
}
- private fun getAndroidJar(project: Project, compileSdkVersion: String) =
- project.files(File(project.getSdkPath(), "platforms/$compileSdkVersion/android.jar"))
-
private fun configureProcessorFlags(project: Project, hiltExtension: HiltExtension) {
val androidExtension = project.baseExtension() ?: error("Android BaseExtension not found.")
-
val projectType = when (androidExtension) {
is AppExtension -> GradleProjectType.APP
is LibraryExtension -> GradleProjectType.LIBRARY
@@ -453,37 +437,23 @@
else -> error("Hilt plugin does not know how to configure '$this'")
}
- // Pass annotation processor flags via a CommandLineArgumentProvider so that plugin
- // options defined in the extension are populated from the user's build file. Checking the
- // option too early would make it seem like it is never set.
- androidExtension.defaultConfig.javaCompileOptions.annotationProcessorOptions
- .compilerArgumentProvider(HiltCommandLineArgumentProvider(hiltExtension, projectType))
- }
-
- private class HiltCommandLineArgumentProvider(
- private val hiltExtension: HiltExtension,
- private val projectType: GradleProjectType
- ): CommandLineArgumentProvider {
- override fun asArguments() = mutableListOf<Pair<String, String>>().apply {
- // Pass annotation processor flag to enable Dagger's fast-init, the best mode for Hilt.
- add("dagger.fastInit" to "enabled")
- // Pass annotation processor flag to disable @AndroidEntryPoint superclass validation.
- add("dagger.hilt.android.internal.disableAndroidSuperclassValidation" to "true")
-
- add("dagger.hilt.android.internal.projectType" to projectType.toString())
-
- // Pass annotation processor flag to disable the aggregating processor if aggregating
- // task is enabled.
- if (hiltExtension.enableAggregatingTask) {
- add("dagger.hilt.internal.useAggregatingRootProcessor" to "false")
+ getAndroidComponentsExtension(project).onAllVariants { component ->
+ // Pass annotation processor flags via a CommandLineArgumentProvider so that plugin
+ // options defined in the extension are populated from the user's build file.
+ val argsProducer: (Task) -> CommandLineArgumentProvider = { task ->
+ HiltCommandLineArgumentProvider(
+ forKsp = task.isKspTask(),
+ projectType = projectType,
+ enableAggregatingTask =
+ hiltExtension.enableAggregatingTask,
+ disableCrossCompilationRootValidation =
+ hiltExtension.disableCrossCompilationRootValidation
+ )
}
- // Pass annotation processor flag to disable cross compilation root validation.
- // The plugin option duplicates the processor flag because it is an input of the
- // aggregating task.
- if (hiltExtension.disableCrossCompilationRootValidation) {
- add("dagger.hilt.disableCrossCompilationRootValidation" to "true")
- }
- }.map { (key, value) -> "-A$key=$value" }
+ addJavaTaskProcessorOptions(project, component, argsProducer)
+ addKaptTaskProcessorOptions(project, component, argsProducer)
+ addKspTaskProcessorOptions(project, component, argsProducer)
+ }
}
private fun verifyDependencies(project: Project) {
@@ -491,35 +461,36 @@
if (project.state.failure != null) {
return
}
- val dependencies = project.configurations.flatMap { configuration ->
- configuration.dependencies.map { dependency -> dependency.group to dependency.name }
- }
+ val dependencies = project.configurations
+ .filterNot {
+ // Exclude plugin created config since plugin adds the deps to them.
+ it.name.startsWith("hiltAnnotationProcessor") ||
+ it.name.startsWith("hiltCompileOnly")
+ }
+ .flatMap { configuration ->
+ configuration.dependencies.map { dependency -> dependency.group to dependency.name }
+ }.toSet()
+ fun getMissingDepMsg(depCoordinate: String): String =
+ "The Hilt Android Gradle plugin is applied but no $depCoordinate dependency was found."
if (!dependencies.contains(LIBRARY_GROUP to "hilt-android")) {
- error(missingDepError("$LIBRARY_GROUP:hilt-android"))
+ error(getMissingDepMsg("$LIBRARY_GROUP:hilt-android"))
}
if (
!dependencies.contains(LIBRARY_GROUP to "hilt-android-compiler") &&
!dependencies.contains(LIBRARY_GROUP to "hilt-compiler")
) {
- error(missingDepError("$LIBRARY_GROUP:hilt-compiler"))
+ error(getMissingDepMsg("$LIBRARY_GROUP:hilt-compiler"))
}
}
private fun Project.baseExtension(): BaseExtension?
= extensions.findByType(BaseExtension::class.java)
- private fun Project.testedExtension(): TestedExtension?
- = extensions.findByType(TestedExtension::class.java)
-
companion object {
- val ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String::class.java)
+ private val ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String::class.java)
const val DAGGER_ARTIFACT_TYPE_VALUE = "jar-for-dagger"
const val AGGREGATED_HILT_ARTIFACT_TYPE_VALUE = "aggregated-jar-for-hilt"
const val LIBRARY_GROUP = "com.google.dagger"
-
- val missingDepError: (String) -> String = { depCoordinate ->
- "The Hilt Android Gradle plugin is applied but no $depCoordinate dependency was found."
- }
}
}
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt
index 27ea2c7..ba41935 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/root/Aggregator.kt
@@ -123,10 +123,10 @@
return object : AnnotationVisitor(asmApiVersion, nextAnnotationVisitor) {
lateinit var rootClass: String
var rootPackage: String? = null
- val rootSimpleNames: MutableList<String> = mutableListOf<String>()
+ val rootSimpleNames = mutableListOf<String>()
lateinit var originatingRootClass: String
var originatingRootPackage: String? = null
- val originatingRootSimpleNames: MutableList<String> = mutableListOf<String>()
+ val originatingRootSimpleNames = mutableListOf<String>()
lateinit var rootAnnotationClassName: Type
override fun visit(name: String, value: Any?) {
@@ -136,14 +136,13 @@
"originatingRoot" -> originatingRootClass = value as String
"originatingRootPackage" -> originatingRootPackage = value as String
"rootAnnotation" -> rootAnnotationClassName = (value as Type)
- else -> throw IllegalStateException("Unexpected annotation value: " + name)
+ else -> error("Unexpected annotation value: $name")
}
super.visit(name, value)
}
- override fun visitArray(name: String): AnnotationVisitor? {
+ override fun visitArray(name: String): AnnotationVisitor {
return object : AnnotationVisitor(asmApiVersion, super.visitArray(name)) {
- @Suppress("UNCHECKED_CAST")
override fun visit(passThroughValueName: String?, value: Any?) {
// Note that passThroughValueName should usually be null since the real name
// is the name passed to visitArray.
@@ -239,7 +238,7 @@
AliasOfPropagatedDataIr(
fqName = annotatedClassName,
defineComponentScopes =
- defineComponentScopeClassNames.map({ it.toClassName() }).toList(),
+ defineComponentScopeClassNames.map { it.toClassName() }.toList(),
alias = aliasClassName.toClassName(),
)
)
@@ -439,7 +438,7 @@
fallbackCanonicalName: String
): ClassName {
if (packageName != null) {
- check(simpleNames.size > 0)
+ check(simpleNames.isNotEmpty())
return ClassName.get(
packageName,
simpleNames.first(),
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/task/HiltTransformTestClassesTask.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/task/HiltTransformTestClassesTask.kt
deleted file mode 100644
index d033c60..0000000
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/task/HiltTransformTestClassesTask.kt
+++ /dev/null
@@ -1,170 +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.android.plugin.task
-
-import dagger.hilt.android.plugin.AndroidEntryPointClassTransformer
-import dagger.hilt.android.plugin.HiltExtension
-import dagger.hilt.android.plugin.util.capitalize
-import dagger.hilt.android.plugin.util.getCompileKotlin
-import dagger.hilt.android.plugin.util.isClassFile
-import dagger.hilt.android.plugin.util.isJarFile
-import java.io.File
-import javax.inject.Inject
-import org.gradle.api.Action
-import org.gradle.api.DefaultTask
-import org.gradle.api.Project
-import org.gradle.api.file.ConfigurableFileCollection
-import org.gradle.api.file.DirectoryProperty
-import org.gradle.api.file.FileCollection
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Classpath
-import org.gradle.api.tasks.OutputDirectory
-import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.TaskProvider
-import org.gradle.api.tasks.testing.Test
-import org.gradle.workers.WorkAction
-import org.gradle.workers.WorkParameters
-import org.gradle.workers.WorkerExecutor
-import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
-
-/**
- * Task that transform classes used by host-side unit tests. See b/37076369
- */
-abstract class HiltTransformTestClassesTask @Inject constructor(
- private val workerExecutor: WorkerExecutor
-) : DefaultTask() {
-
- @get:Classpath
- abstract val compiledClasses: ConfigurableFileCollection
-
- @get:OutputDirectory
- abstract val outputDir: DirectoryProperty
-
- internal interface Parameters : WorkParameters {
- val name: Property<String>
- val compiledClasses: ConfigurableFileCollection
- val outputDir: DirectoryProperty
- }
-
- abstract class WorkerAction : WorkAction<Parameters> {
- override fun execute() {
- val outputDir = parameters.outputDir.asFile.get()
- outputDir.deleteRecursively()
- outputDir.mkdirs()
-
- val allInputs = parameters.compiledClasses.files.toList()
- val classTransformer = AndroidEntryPointClassTransformer(
- taskName = parameters.name.get(),
- allInputs = allInputs,
- sourceRootOutputDir = outputDir,
- copyNonTransformed = false
- )
- // Parse the classpath in reverse so that we respect overwrites, if it ever happens.
- allInputs.reversed().forEach {
- if (it.isDirectory) {
- it.walkTopDown().forEach { file ->
- if (file.isClassFile()) {
- classTransformer.transformFile(file)
- }
- }
- } else if (it.isJarFile()) {
- classTransformer.transformJarContents(it)
- }
- }
- }
- }
-
- @TaskAction
- fun transformClasses() {
- workerExecutor.noIsolation().submit(WorkerAction::class.java) {
- it.compiledClasses.from(compiledClasses)
- it.outputDir.set(outputDir)
- it.name.set(name)
- }
- }
-
- internal class ConfigAction(
- private val outputDir: File,
- private val inputClasspath: FileCollection
- ) : Action<HiltTransformTestClassesTask> {
- override fun execute(transformTask: HiltTransformTestClassesTask) {
- transformTask.description = "Transforms AndroidEntryPoint annotated classes for JUnit tests."
- transformTask.outputDir.set(outputDir)
- transformTask.compiledClasses.from(inputClasspath)
- }
- }
-
- companion object {
-
- private const val TASK_PREFIX = "hiltTransformFor"
-
- fun create(
- project: Project,
- @Suppress("DEPRECATION") unitTestVariant: com.android.build.gradle.api.UnitTestVariant,
- extension: HiltExtension
- ) {
- if (!extension.enableTransformForLocalTests) {
- // Not enabled, nothing to do here.
- return
- }
-
- // TODO(danysantiago): Only use project compiled sources as input, and not all dependency jars
- // Using 'null' key to obtain the full compile classpath since we are not using the
- // registerPreJavacGeneratedBytecode() API that would have otherwise given us a key to get
- // a classpath up to the generated bytecode associated with the key.
- val inputClasspath =
- project.files(unitTestVariant.getCompileClasspath(null))
-
- // Find the test sources Java compile task and add its output directory into our input
- // classpath file collection. This also makes the transform task depend on the test compile
- // task.
- val testCompileTaskProvider = unitTestVariant.javaCompileProvider
- inputClasspath.from(testCompileTaskProvider.map { it.destinationDirectory })
-
- // Similarly, if the Kotlin plugin is configured, find the test sources Kotlin compile task
- // and add its output directory to our input classpath file collection.
- project.plugins.withType(KotlinBasePluginWrapper::class.java) {
- val kotlinCompileTaskProvider = getCompileKotlin(unitTestVariant, project)
- inputClasspath.from(kotlinCompileTaskProvider.map { it.destinationDirectory })
- }
-
- // Create and configure the transform task.
- val outputDir =
- project.buildDir.resolve("intermediates/hilt/${unitTestVariant.dirName}Output")
- val hiltTransformProvider = project.tasks.register(
- "$TASK_PREFIX${unitTestVariant.name.capitalize()}",
- HiltTransformTestClassesTask::class.java,
- ConfigAction(outputDir, inputClasspath)
- )
- // Map the transform task's output to a file collection.
- val outputFileCollection =
- project.files(hiltTransformProvider.map { it.outputDir })
-
- // Configure test classpath by appending the transform output file collection to the start of
- // the test classpath so they override the original ones. This also makes test task (the one
- // that runs the tests) depend on the transform task.
-
- @Suppress("UNCHECKED_CAST")
- val testTaskProvider = project.tasks.named(
- "test${unitTestVariant.name.capitalize()}"
- ) as TaskProvider<Test>
- testTaskProvider.configure {
- it.classpath = outputFileCollection + it.classpath
- }
- }
- }
-}
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt
index 0fe2f83..1f4a792 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Configurations.kt
@@ -17,20 +17,31 @@
package dagger.hilt.android.plugin.util
@Suppress("DEPRECATION") // Older variant API is deprecated
-internal fun getKaptConfigName(variant: com.android.build.gradle.api.BaseVariant): String {
- // KAPT config names don't follow the usual convention:
+internal fun getKaptConfigName(variant: com.android.build.gradle.api.BaseVariant)
+ = getConfigName(variant, "kapt")
+
+@Suppress("DEPRECATION") // Older variant API is deprecated
+internal fun getKspConfigName(variant: com.android.build.gradle.api.BaseVariant)
+ = getConfigName(variant, "ksp")
+
+@Suppress("DEPRECATION") // Older variant API is deprecated
+internal fun getConfigName(
+ variant: com.android.build.gradle.api.BaseVariant,
+ prefix: String
+): String {
+ // Config names don't follow the usual task name conventions:
// <Variant Name> -> <Config Name>
- // debug -> kaptDebug
- // debugAndroidTest -> kaptAndroidTestDebug
- // debugUnitTest -> kaptTestDebug
- // release -> kaptRelease
- // releaseUnitTest -> kaptTestRelease
+ // debug -> <prefix>Debug
+ // debugAndroidTest -> <prefix>AndroidTestDebug
+ // debugUnitTest -> <prefix>TestDebug
+ // release -> <prefix>Release
+ // releaseUnitTest -> <prefix>TestRelease
return when (variant) {
is com.android.build.gradle.api.TestVariant ->
- "kaptAndroidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}"
+ "${prefix}AndroidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}"
is com.android.build.gradle.api.UnitTestVariant ->
- "kaptTest${variant.name.substringBeforeLast("UnitTest").capitalize()}"
+ "${prefix}Test${variant.name.substringBeforeLast("UnitTest").capitalize()}"
else ->
- "kapt${variant.name}"
+ "${prefix}${variant.name.capitalize()}"
}
}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
index e7b0234..b837d4e 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
@@ -18,10 +18,8 @@
import java.io.File
import java.io.InputStream
-import java.util.Properties
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
-import org.gradle.api.Project
/* Checks if a file is a .class file. */
fun File.isClassFile() = this.isFile && this.extension == "class"
@@ -48,36 +46,3 @@
inputEntry = nextEntry
}
}
-
-/* Gets the Android Sdk Path. */
-fun Project.getSdkPath(): File {
- val localPropsFile = rootProject.projectDir.resolve("local.properties")
- if (localPropsFile.exists()) {
- val localProps = Properties()
- localPropsFile.inputStream().use { localProps.load(it) }
- val localSdkDir = localProps["sdk.dir"]?.toString()
- if (localSdkDir != null) {
- val sdkDirectory = File(localSdkDir)
- if (sdkDirectory.isDirectory) {
- return sdkDirectory
- }
- }
- }
- return getSdkPathFromEnvironmentVariable()
-}
-
-private fun getSdkPathFromEnvironmentVariable(): File {
- // Check for environment variables, in the order AGP checks.
- listOf("ANDROID_HOME", "ANDROID_SDK_ROOT").forEach {
- val envValue = System.getenv(it)
- if (envValue != null) {
- val sdkDirectory = File(envValue)
- if (sdkDirectory.isDirectory) {
- return sdkDirectory
- }
- }
- }
- // Only print the error for SDK ROOT since ANDROID_HOME is deprecated but we first check
- // it because it is prioritized according to the documentation.
- error("ANDROID_SDK_ROOT environment variable is not set")
-}
diff --git a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
index 2bab91b..2c803b7 100644
--- a/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
+++ b/java/dagger/hilt/android/plugin/main/src/main/kotlin/dagger/hilt/android/plugin/util/Tasks.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Dagger Authors.
+ * Copyright (C) 2023 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,17 +16,60 @@
package dagger.hilt.android.plugin.util
+import com.google.devtools.ksp.gradle.KspTaskJvm
import org.gradle.api.Project
-import org.gradle.api.tasks.TaskProvider
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.gradle.api.Task
+import org.gradle.api.tasks.compile.JavaCompile
+import org.gradle.process.CommandLineArgumentProvider
+import org.jetbrains.kotlin.gradle.internal.KaptTask
-/**
- * Gets [KotlinCompile] task of an Android variant.
- */
-@Suppress("UNCHECKED_CAST")
-internal fun getCompileKotlin(
- @Suppress("DEPRECATION") variant: com.android.build.gradle.api.BaseVariant,
- project: Project
-) = project.tasks.named(
- "compile${variant.name.capitalize()}Kotlin"
-) as TaskProvider<KotlinCompile>
+internal fun addJavaTaskProcessorOptions(
+ project: Project,
+ component: ComponentCompat,
+ produceArgProvider: (Task) -> CommandLineArgumentProvider
+) = project.tasks.withType(JavaCompile::class.java) { task ->
+ if (task.name == "compile${component.name.capitalize()}JavaWithJavac") {
+ task.options.compilerArgumentProviders.add(produceArgProvider.invoke(task))
+ }
+}
+
+internal fun addKaptTaskProcessorOptions(
+ project: Project,
+ component: ComponentCompat,
+ produceArgProvider: (Task) -> CommandLineArgumentProvider
+) = project.plugins.withId("kotlin-kapt") {
+ project.tasks.withType(KaptTask::class.java) { task ->
+ if (task.name == "kapt${component.name.capitalize()}Kotlin") {
+ val argProvider = produceArgProvider.invoke(task)
+ // TODO: Update once KT-58009 is fixed.
+ try {
+ // Because of KT-58009, we need to add a `listOf(argProvider)` instead
+ // of `argProvider`.
+ task.annotationProcessorOptionProviders.add(listOf(argProvider))
+ } catch (e: Throwable) {
+ // Once KT-58009 is fixed, adding `listOf(argProvider)` will fail, we will
+ // pass `argProvider` instead, which is the correct way.
+ task.annotationProcessorOptionProviders.add(argProvider)
+ }
+ }
+ }
+}
+
+internal fun addKspTaskProcessorOptions(
+ project: Project,
+ component: ComponentCompat,
+ produceArgProvider: (Task) -> CommandLineArgumentProvider
+) = project.plugins.withId("com.google.devtools.ksp") {
+ project.tasks.withType(KspTaskJvm::class.java) { task ->
+ if (task.name == "ksp${component.name.capitalize()}Kotlin") {
+ task.commandLineArgumentProviders.add(produceArgProvider.invoke(task))
+ }
+ }
+}
+
+internal fun Task.isKspTask(): Boolean = try {
+ val kspTaskClass = Class.forName("com.google.devtools.ksp.gradle.KspTask")
+ kspTaskClass.isAssignableFrom(this::class.java)
+} catch (ex: ClassNotFoundException) {
+ false
+}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java
index 1104ba0..f2209f3 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java
+++ b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/java/spi/TestPlugin.java
@@ -16,10 +16,10 @@
package spi;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraphPlugin;
+import dagger.spi.model.DiagnosticReporter;
import javax.tools.Diagnostic;
/**
diff --git a/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.BindingGraphPlugin b/java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.model.BindingGraphPlugin
similarity index 100%
rename from java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.BindingGraphPlugin
rename to java/dagger/hilt/android/plugin/main/src/test/data/spi-plugin/src/main/resources/META-INF/services/dagger.spi.model.BindingGraphPlugin
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt
index 9b1d677..fb47bdb 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/GradleTestRunner.kt
@@ -22,10 +22,13 @@
/** Testing utility class that sets up a simple Android project that applies the Hilt plugin. */
class GradleTestRunner(val tempFolder: TemporaryFolder) {
+ private val pluginClasspaths = mutableListOf<String>()
+ private val pluginIds = mutableListOf<String>()
private val dependencies = mutableListOf<String>()
private val activities = mutableListOf<String>()
private val additionalAndroidOptions = mutableListOf<String>()
private val hiltOptions = mutableListOf<String>()
+ private val additionalClosures = mutableListOf<String>()
private var appClassName: String? = null
private var buildFile: File? = null
private var gradlePropertiesFile: File? = null
@@ -39,6 +42,17 @@
tempFolder.newFolder("src", "main", "res")
}
+ // Adds a Gradle plugin classpath to the test project,
+ // e.g. "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0"
+ fun addPluginClasspath(pluginClasspath: String) {
+ pluginClasspaths.add(pluginClasspath)
+ }
+
+ // Adds a Gradle plugin id to the test project, e.g. "kotlin-android"
+ fun addPluginId(pluginId: String) {
+ pluginIds.add(pluginId)
+ }
+
// Adds project dependencies, e.g. "implementation <group>:<id>:<version>"
fun addDependencies(vararg deps: String) {
dependencies.addAll(deps)
@@ -61,6 +75,10 @@
hiltOptions.addAll(options)
}
+ fun addAdditionalClosure(closure: String) {
+ additionalClosures.add(closure)
+ }
+
// Adds a source package to the project. The package path is relative to 'src/main/java'.
fun addSrcPackage(packagePath: String) {
File(tempFolder.root, "src/main/java/$packagePath").mkdirs()
@@ -127,12 +145,14 @@
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
+ ${pluginClasspaths.joinToString(separator = "\n") { "classpath '$it'" }}
}
}
plugins {
id '${ if (isAppProject) "com.android.application" else "com.android.library" }'
id 'com.google.dagger.hilt.android'
+ ${pluginIds.joinToString(separator = "\n") { "id '$it'" }}
}
android {
@@ -168,6 +188,7 @@
hilt {
${hiltOptions.joinToString(separator = "\n")}
}
+ ${additionalClosures.joinToString(separator = "\n")}
""".trimIndent()
)
}
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt
index d13253b..1e8490f 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/IncrementalProcessorTest.kt
@@ -195,7 +195,6 @@
// Compute directory paths
val defaultGenSrcDir = "build/generated/ap_generated_sources/debug/out/"
- val testDefaultGenSrcDir = "build/generated/ap_generated_sources/debugUnitTest/out/"
fun getComponentTreeDepsGenSrcDir(variant: String) = if (incapMode == ISOLATING_MODE) {
"build/generated/hilt/component_trees/$variant/"
} else {
diff --git a/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt b/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt
index ffe6dc0..963d262 100644
--- a/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt
+++ b/java/dagger/hilt/android/plugin/main/src/test/kotlin/SPIPluginTest.kt
@@ -21,8 +21,11 @@
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
-class SPIPluginTest {
+@RunWith(Parameterized::class)
+class SPIPluginTest(val backend: Backend) {
@get:Rule
val testProjectDir = TemporaryFolder()
@@ -40,12 +43,30 @@
""".trimIndent()
)
}
+ val processorConfig = when (backend) {
+ Backend.JAVAC -> "annotationProcessor"
+ Backend.KAPT -> "kapt"
+ Backend.KSP -> "ksp"
+ }
+ if (backend == Backend.KAPT || backend == Backend.KSP) {
+ gradleRunner.addPluginId("kotlin-android")
+ if (backend == Backend.KAPT) {
+ gradleRunner.addPluginId("kotlin-kapt")
+ } else {
+ gradleRunner.addPluginId("com.google.devtools.ksp")
+ }
+ gradleRunner.addAdditionalClosure("""
+ |kotlin {
+ | jvmToolchain(11)
+ |}
+ """.trimMargin())
+ }
gradleRunner.addHiltOption("enableAggregatingTask = true")
gradleRunner.addDependencies(
"implementation 'androidx.appcompat:appcompat:1.1.0'",
"implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'",
- "annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'",
- "annotationProcessor project(':spi-plugin')",
+ "$processorConfig 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'",
+ "$processorConfig project(':spi-plugin')",
)
gradleRunner.addSrc(
srcPath = "minimal/MyApp.java",
@@ -74,4 +95,14 @@
"[spi.TestPlugin] Found component: minimal.MyApp_HiltComponents.SingletonC"
)
}
+
+ companion object {
+ @JvmStatic
+ @Parameterized.Parameters(name = "backend = {0}")
+ fun params() = listOf(Backend.JAVAC, Backend.KAPT, Backend.KSP)
+
+ enum class Backend {
+ JAVAC, KAPT, KSP
+ }
+ }
}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/processor/BUILD b/java/dagger/hilt/android/processor/BUILD
index 6ca29b4..6f45216 100644
--- a/java/dagger/hilt/android/processor/BUILD
+++ b/java/dagger/hilt/android/processor/BUILD
@@ -36,7 +36,6 @@
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:metadata",
"//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
@@ -48,10 +47,11 @@
"//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:dagger_models",
"//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:component_names",
"//java/dagger/hilt/processor/internal:components",
- "//java/dagger/hilt/processor/internal:element_descriptors",
+ "//java/dagger/hilt/processor/internal:hilt_processing_env_configs",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
@@ -60,6 +60,7 @@
"//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:metadatas",
"//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",
@@ -77,19 +78,18 @@
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
],
artifact_target_maven_deps = [
- "com.google.auto:auto-common",
"com.google.code.findbugs:jsr305",
"com.google.dagger:dagger-compiler",
"com.google.dagger:dagger",
"com.google.dagger:dagger-spi",
+ "com.google.devtools.ksp:symbol-processing-api",
"com.google.guava:failureaccess",
"com.google.guava:guava",
"com.squareup:javapoet",
- "javax.annotation:javax.annotation-api",
+ "com.squareup:kotlinpoet",
"javax.inject:javax.inject",
"net.ltgt.gradle.incap:incap",
"org.jetbrains.kotlin:kotlin-stdlib",
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
],
javadoc_android_api_level = 32,
javadoc_root_packages = [
@@ -100,10 +100,6 @@
javadoc_srcs = [
"//java/dagger/hilt:hilt_processing_filegroup",
],
- # The shaded deps are added using jarjar, but they won't be shaded until later
- # due to: https://github.com/google/dagger/issues/2765. For the shaded rules see
- # util/deploy-hilt.sh
- shaded_deps = ["//third_party/java/auto:common"],
)
filegroup(
diff --git a/java/dagger/hilt/android/processor/internal/BUILD b/java/dagger/hilt/android/processor/internal/BUILD
index dfd7333..45615e4 100644
--- a/java/dagger/hilt/android/processor/internal/BUILD
+++ b/java/dagger/hilt/android/processor/internal/BUILD
@@ -27,18 +27,6 @@
],
)
-# TODO(erichang): Merge this into other utils
-java_library(
- name = "utils",
- srcs = [
- "MoreTypes.java",
- ],
- deps = [
- "//third_party/java/guava/base",
- "//third_party/java/guava/collect",
- ],
-)
-
filegroup(
name = "srcs_filegroup",
srcs = glob(["**/*"]),
diff --git a/java/dagger/hilt/android/processor/internal/MoreTypes.java b/java/dagger/hilt/android/processor/internal/MoreTypes.java
deleted file mode 100644
index e5a2cdd..0000000
--- a/java/dagger/hilt/android/processor/internal/MoreTypes.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2019 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.android.processor.internal;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ErrorType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.SimpleTypeVisitor7;
-import javax.lang.model.util.Types;
-
-/** More utility methods for types. */
-public final class MoreTypes {
- private MoreTypes() {}
-
- /**
- * If the received mirror represents a declared type or an array of declared types, this returns
- * the represented declared type. Otherwise throws an IllegalStateException.
- */
- public static DeclaredType getDeclaredType(TypeMirror type) {
- return type.accept(
- new SimpleTypeVisitor7<DeclaredType, Void>() {
- @Override public DeclaredType visitArray(ArrayType type, Void unused) {
- return getDeclaredType(type.getComponentType());
- }
-
- @Override public DeclaredType visitDeclared(DeclaredType type, Void unused) {
- return type;
- }
-
- @Override public DeclaredType visitError(ErrorType type, Void unused) {
- return type;
- }
-
- @Override public DeclaredType defaultAction(TypeMirror type, Void unused) {
- throw new IllegalStateException("Unhandled type: " + type);
- }
- }, null /* the Void accumulator */);
- }
-
- /** Returns the TypeElement corresponding to a TypeMirror. */
- public static TypeElement asTypeElement(TypeMirror type) {
- return asTypeElement(getDeclaredType(type));
- }
-
- /** Returns the TypeElement corresponding to a DeclaredType. */
- public static TypeElement asTypeElement(DeclaredType type) {
- return (TypeElement) type.asElement();
- }
-
- /**
- * Returns a {@link ExecutableType} if the {@link TypeMirror} represents an executable type such
- * as a method, constructor, or initializer or throws an {@link IllegalArgumentException}.
- */
- public static ExecutableType asExecutable(TypeMirror maybeExecutableType) {
- return maybeExecutableType.accept(ExecutableTypeVisitor.INSTANCE, null);
- }
-
- private static final class ExecutableTypeVisitor extends CastingTypeVisitor<ExecutableType> {
- private static final ExecutableTypeVisitor INSTANCE = new ExecutableTypeVisitor();
-
- ExecutableTypeVisitor() {
- super("executable type");
- }
-
- @Override
- public ExecutableType visitExecutable(ExecutableType type, Void ignore) {
- return type;
- }
- }
-
- private abstract static class CastingTypeVisitor<T> extends SimpleTypeVisitor7<T, Void> {
- private final String label;
-
- CastingTypeVisitor(String label) {
- this.label = label;
- }
-
- @Override
- protected T defaultAction(TypeMirror e, Void v) {
- throw new IllegalArgumentException(e + " does not represent a " + label);
- }
- }
-
- /**
- * Returns the first matching method, if one exists (starting with classElement, then searching
- * each sub classes).
- */
- public static Optional<ExecutableElement> findInheritedMethod(
- Types types, TypeElement classElement, ExecutableElement method) {
- Optional<ExecutableElement> match = Optional.empty();
- while (!match.isPresent() && !classElement.asType().getKind().equals(TypeKind.NONE)) {
- match = findMethod(types, classElement, method);
- classElement = MoreTypes.asTypeElement(classElement.getSuperclass());
- }
- return match;
- }
-
- /** Returns a method with a matching signature in classElement if one exists. */
- public static Optional<ExecutableElement> findMethod(
- Types types, TypeElement classElement, ExecutableElement method) {
- ExecutableType methodType = asExecutable(method.asType());
- Set<ExecutableElement> matchingMethods =
- findMethods(classElement, method.getSimpleName().toString())
- .stream()
- .filter(clsMethod -> types.isSubsignature(asExecutable(clsMethod.asType()), methodType))
- .collect(Collectors.toSet());
-
- Preconditions.checkState(
- matchingMethods.size() <= 1,
- "Found multiple methods with matching signature in class %s: %s",
- classElement,
- matchingMethods);
-
- return matchingMethods.size() == 1
- ? Optional.of(Iterables.getOnlyElement(matchingMethods))
- : Optional.empty();
- }
-
- /** Returns methods with a matching name in classElement. */
- public static Set<ExecutableElement> findMethods(TypeElement classElement, String name) {
- return ElementFilter.methodsIn(classElement.getEnclosedElements())
- .stream()
- .filter(clsMethod -> clsMethod.getSimpleName().contentEquals(name))
- .collect(Collectors.toSet());
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
index f933a90..49f439e 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
@@ -16,28 +16,29 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeParameterElement;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.Processors;
import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
/** Generates an Hilt Activity class for the @AndroidEntryPoint annotated class. */
public final class ActivityGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
private final ClassName generatedClassName;
- public ActivityGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
+ public ActivityGenerator(XProcessingEnv env, AndroidEntryPointMetadata metadata) {
this.env = env;
this.metadata = metadata;
-
generatedClassName = metadata.generatedClassName();
}
@@ -48,10 +49,10 @@
public void generate() throws IOException {
TypeSpec.Builder builder =
TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
.superclass(metadata.baseClassName())
.addModifiers(metadata.generatedClassModifiers());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
@@ -62,7 +63,7 @@
builder.addMethod(init());
metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
+ .map(XTypeParameterElement::getTypeVariableName)
.forEachOrdered(builder::addTypeVariable);
Generators.addComponentOverride(metadata, builder);
@@ -76,9 +77,10 @@
builder.addMethod(getDefaultViewModelProviderFactory());
}
- JavaFile.builder(generatedClassName.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(generatedClassName.packageName(), builder.build()).build(),
+ XFiler.Mode.Isolating);
}
// private void init() {
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
index 39adc18..6f925da 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
@@ -16,16 +16,27 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.isAndroidSuperclassValidationDisabled;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static androidx.room.compiler.processing.XTypeKt.isVoidObject;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.isAndroidSuperClassValidationDisabled;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XTypeElements.isKotlinSource;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -33,33 +44,27 @@
import com.squareup.javapoet.TypeName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.BadInputException;
-import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Components;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.Processors;
import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtil;
import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.stream.Collectors;
-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.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
/** Metadata class for @AndroidEntryPoint annotated classes. */
@AutoValue
public abstract class AndroidEntryPointMetadata {
- /** The class {@link Element} annotated with @AndroidEntryPoint. */
- public abstract TypeElement element();
+ /** The class annotated with @AndroidEntryPoint. */
+ public abstract XTypeElement element();
- /** The base class {@link Element} given to @AndroidEntryPoint. */
- public abstract TypeElement baseElement();
+ /** The base class given to @AndroidEntryPoint. */
+ public abstract XTypeElement baseElement();
/** The name of the generated base class, beginning with 'Hilt_'. */
public abstract ClassName generatedClassName();
@@ -98,7 +103,7 @@
/** Returns true if this class allows optional injection. */
public boolean allowsOptionalInjection() {
- return Processors.hasAnnotation(element(), AndroidClassNames.OPTIONAL_INJECT);
+ return element().hasAnnotation(AndroidClassNames.OPTIONAL_INJECT);
}
/** Returns true if any base class (transitively) allows optional injection. */
@@ -113,12 +118,12 @@
/** The name of the class annotated with @AndroidEntryPoint */
public ClassName elementClassName() {
- return ClassName.get(element());
+ return element().getClassName();
}
/** The name of the base class given to @AndroidEntryPoint */
public TypeName baseClassName() {
- return TypeName.get(baseElement().asType());
+ return baseElement().getType().getTypeName();
}
/** The name of the generated injector for the Hilt class. */
@@ -152,13 +157,15 @@
* https://discuss.kotlinlang.org/t/why-does-kotlin-prohibit-exposing-restricted-visibility-types/7047
*/
public Modifier[] generatedClassModifiers() {
- return isKotlinClass(element()) && element().getModifiers().contains(Modifier.PUBLIC)
+ // Note XElement#isPublic() refers to the jvm visibility. Since "internal" visibility is
+ // represented as public in the jvm, we have to check XElement#isInternal() explicitly.
+ return isKotlinSource(element()) && element().isPublic() && !element().isInternal()
? new Modifier[] {Modifier.ABSTRACT, Modifier.PUBLIC}
: new Modifier[] {Modifier.ABSTRACT};
}
- private static ClassName generatedClassName(TypeElement element) {
- return Processors.prepend(Processors.getEnclosedClassName(ClassName.get(element)), "Hilt_");
+ private static ClassName generatedClassName(XTypeElement element) {
+ return Processors.prepend(Processors.getEnclosedClassName(element.getClassName()), "Hilt_");
}
private static final ImmutableSet<ClassName> HILT_ANNOTATION_NAMES =
@@ -166,27 +173,25 @@
AndroidClassNames.HILT_ANDROID_APP,
AndroidClassNames.ANDROID_ENTRY_POINT);
- private static ImmutableSet<? extends AnnotationMirror> hiltAnnotations(Element element) {
- return element.getAnnotationMirrors().stream()
- .filter(mirror -> HILT_ANNOTATION_NAMES.contains(ClassName.get(mirror.getAnnotationType())))
+ private static ImmutableSet<XAnnotation> hiltAnnotations(XElement element) {
+ return element.getAllAnnotations().stream()
+ .filter(annotation -> HILT_ANNOTATION_NAMES.contains(annotation.getClassName()))
.collect(toImmutableSet());
}
/** Returns true if the given element has Android Entry Point metadata. */
- public static boolean hasAndroidEntryPointMetadata(Element element) {
+ public static boolean hasAndroidEntryPointMetadata(XElement element) {
return !hiltAnnotations(element).isEmpty();
}
/** Returns the {@link AndroidEntryPointMetadata} for a @AndroidEntryPoint annotated element. */
- public static AndroidEntryPointMetadata of(ProcessingEnvironment env, Element element) {
- LinkedHashSet<Element> inheritanceTrace = new LinkedHashSet<>();
- inheritanceTrace.add(element);
- return of(env, element, inheritanceTrace);
+ public static AndroidEntryPointMetadata of(XElement element) {
+ return of(element, Sets.newLinkedHashSet(ImmutableList.of(element)));
}
public static AndroidEntryPointMetadata manuallyConstruct(
- TypeElement element,
- TypeElement baseElement,
+ XTypeElement element,
+ XTypeElement baseElement,
ClassName generatedClassName,
boolean requiresBytecodeInjection,
AndroidType androidType,
@@ -211,24 +216,22 @@
* along the way.
*/
private static AndroidEntryPointMetadata of(
- ProcessingEnvironment env, Element element, LinkedHashSet<Element> inheritanceTrace) {
- ImmutableSet<? extends AnnotationMirror> hiltAnnotations = hiltAnnotations(element);
+ XElement element, LinkedHashSet<XElement> inheritanceTrace) {
+ ImmutableSet<XAnnotation> hiltAnnotations = hiltAnnotations(element);
ProcessorErrors.checkState(
hiltAnnotations.size() == 1,
element,
"Expected exactly 1 of %s. Found: %s",
- HILT_ANNOTATION_NAMES,
- hiltAnnotations);
- ClassName annotationClassName =
- ClassName.get(
- MoreTypes.asTypeElement(Iterables.getOnlyElement(hiltAnnotations).getAnnotationType()));
+ HILT_ANNOTATION_NAMES.stream().map(ClassName::canonicalName).collect(toImmutableSet()),
+ hiltAnnotations.stream().map(XAnnotations::toStableString).collect(toImmutableSet()));
+ ClassName annotationClassName = getOnlyElement(hiltAnnotations).getClassName();
ProcessorErrors.checkState(
- element.getKind() == ElementKind.CLASS,
+ isTypeElement(element) && asTypeElement(element).isClass(),
element,
"Only classes can be annotated with @%s",
annotationClassName.simpleName());
- TypeElement androidEntryPointElement = MoreElements.asType(element);
+ XTypeElement androidEntryPointElement = asTypeElement(element);
ProcessorErrors.checkState(
androidEntryPointElement.getTypeParameters().isEmpty(),
@@ -236,18 +239,18 @@
"@%s-annotated classes cannot have type parameters.",
annotationClassName.simpleName());
- final TypeElement androidEntryPointClassValue =
- Processors.getAnnotationClassValue(
- env.getElementUtils(),
- Processors.getAnnotationMirror(androidEntryPointElement, annotationClassName),
- "value");
- final TypeElement baseElement;
- final ClassName generatedClassName;
+ XTypeElement androidEntryPointClassValue =
+ androidEntryPointElement
+ .getAnnotation(annotationClassName)
+ .getAsType("value")
+ .getTypeElement();
+ XTypeElement baseElement;
+ ClassName generatedClassName = generatedClassName(androidEntryPointElement);
boolean requiresBytecodeInjection =
- isAndroidSuperclassValidationDisabled(androidEntryPointElement, env)
- && MoreTypes.isTypeOf(Void.class, androidEntryPointClassValue.asType());
+ isAndroidSuperClassValidationDisabled(androidEntryPointElement)
+ && isVoidObject(androidEntryPointClassValue.getType());
if (requiresBytecodeInjection) {
- baseElement = MoreElements.asType(env.getTypeUtils().asElement(androidEntryPointElement.getSuperclass()));
+ baseElement = androidEntryPointElement.getSuperClass().getTypeElement();
// If this AndroidEntryPoint is a Kotlin class and its base type is also Kotlin and has
// default values declared in its constructor then error out because for the short-form
// usage of @AndroidEntryPoint the bytecode transformation will be done incorrectly.
@@ -263,11 +266,10 @@
+ "declaration.",
baseElement.getQualifiedName(),
androidEntryPointElement.getQualifiedName());
- generatedClassName = generatedClassName(androidEntryPointElement);
} else {
baseElement = androidEntryPointClassValue;
ProcessorErrors.checkState(
- !MoreTypes.isTypeOf(Void.class, baseElement.asType()),
+ !isVoidObject(baseElement.getType()),
androidEntryPointElement,
"Expected @%s to have a value."
+ " Did you forget to apply the Gradle Plugin? (com.google.dagger.hilt.android)\n"
@@ -276,22 +278,22 @@
// Check that the root $CLASS extends Hilt_$CLASS
String extendsName =
- env.getTypeUtils()
- .asElement(androidEntryPointElement.getSuperclass())
- .getSimpleName()
- .toString();
- generatedClassName = generatedClassName(androidEntryPointElement);
- ProcessorErrors.checkState(
- extendsName.contentEquals(generatedClassName.simpleName()),
- androidEntryPointElement,
- "@%s class expected to extend %s. Found: %s",
- annotationClassName.simpleName(),
- generatedClassName.simpleName(),
- extendsName);
+ androidEntryPointElement.getSuperClass().getTypeElement().getClassName().simpleName();
+
+ // TODO(b/288210593): Add this check back to KSP once this bug is fixed.
+ if (getProcessingEnv(androidEntryPointElement).getBackend() == XProcessingEnv.Backend.JAVAC) {
+ ProcessorErrors.checkState(
+ extendsName.contentEquals(generatedClassName.simpleName()),
+ androidEntryPointElement,
+ "@%s class expected to extend %s. Found: %s",
+ annotationClassName.simpleName(),
+ generatedClassName.simpleName(),
+ extendsName);
+ }
}
Optional<AndroidEntryPointMetadata> baseMetadata =
- baseMetadata(env, androidEntryPointElement, baseElement, inheritanceTrace);
+ baseMetadata(androidEntryPointElement, baseElement, inheritanceTrace);
if (baseMetadata.isPresent()) {
return manuallyConstruct(
@@ -320,48 +322,38 @@
}
private static Optional<AndroidEntryPointMetadata> baseMetadata(
- ProcessingEnvironment env,
- TypeElement element,
- TypeElement baseElement,
- LinkedHashSet<Element> inheritanceTrace) {
+ XTypeElement element, XTypeElement baseElement, LinkedHashSet<XElement> inheritanceTrace) {
ProcessorErrors.checkState(
inheritanceTrace.add(baseElement),
element,
cyclicInheritanceErrorMessage(inheritanceTrace, baseElement));
if (hasAndroidEntryPointMetadata(baseElement)) {
AndroidEntryPointMetadata baseMetadata =
- AndroidEntryPointMetadata.of(env, baseElement, inheritanceTrace);
+ AndroidEntryPointMetadata.of(baseElement, inheritanceTrace);
checkConsistentAnnotations(element, baseMetadata);
return Optional.of(baseMetadata);
}
- TypeMirror superClass = baseElement.getSuperclass();
+ XType superClass = baseElement.getSuperClass();
// None type is returned if this is an interface or Object
- if (superClass.getKind() != TypeKind.NONE && superClass.getKind() != TypeKind.ERROR) {
- Preconditions.checkState(superClass.getKind() == TypeKind.DECLARED);
- return baseMetadata(env, element, MoreTypes.asTypeElement(superClass), inheritanceTrace);
+ if (superClass != null && !superClass.isError()) {
+ Preconditions.checkState(isDeclared(superClass));
+ return baseMetadata(element, superClass.getTypeElement(), inheritanceTrace);
}
return Optional.empty();
}
private static String cyclicInheritanceErrorMessage(
- LinkedHashSet<Element> inheritanceTrace, TypeElement cycleEntryPoint) {
+ LinkedHashSet<XElement> inheritanceTrace, XTypeElement cycleEntryPoint) {
return String.format(
"Cyclic inheritance detected. Make sure the base class of @AndroidEntryPoint "
+ "is not the annotated class itself or subclass of the annotated class.\n"
+ "The cyclic inheritance structure: %s --> %s\n",
inheritanceTrace.stream()
- .map(Element::asType)
- .map(TypeMirror::toString)
+ .map(XElements::toStableString)
.collect(Collectors.joining(" --> ")),
- cycleEntryPoint.asType());
- }
-
- private static boolean isKotlinClass(TypeElement typeElement) {
- return typeElement.getAnnotationMirrors().stream()
- .map(mirror -> mirror.getAnnotationType())
- .anyMatch(type -> ClassName.get(type).equals(ClassNames.KOTLIN_METADATA));
+ XElements.toStableString(cycleEntryPoint));
}
/**
@@ -438,23 +430,22 @@
this.componentManagerInitArgs = componentManagerInitArgs;
}
- private static Type of(TypeElement element, TypeElement baseElement) {
- if (Processors.hasAnnotation(element, AndroidClassNames.HILT_ANDROID_APP)) {
- return forHiltAndroidApp(element, baseElement);
- }
- return forAndroidEntryPoint(element, baseElement);
+ private static Type of(XTypeElement element, XTypeElement baseElement) {
+ return element.hasAnnotation(AndroidClassNames.HILT_ANDROID_APP)
+ ? forHiltAndroidApp(element, baseElement)
+ : forAndroidEntryPoint(element, baseElement);
}
- private static Type forHiltAndroidApp(TypeElement element, TypeElement baseElement) {
+ private static Type forHiltAndroidApp(XTypeElement element, XTypeElement baseElement) {
ProcessorErrors.checkState(
Processors.isAssignableFrom(baseElement, AndroidClassNames.APPLICATION),
element,
"@HiltAndroidApp base class must extend Application. Found: %s",
- baseElement);
+ XElements.toStableString(baseElement));
return Type.APPLICATION;
}
- private static Type forAndroidEntryPoint(TypeElement element, TypeElement baseElement) {
+ private static Type forAndroidEntryPoint(XTypeElement element, XTypeElement baseElement) {
if (Processors.isAssignableFrom(baseElement, AndroidClassNames.ACTIVITY)) {
ProcessorErrors.checkState(
Processors.isAssignableFrom(baseElement, AndroidClassNames.COMPONENT_ACTIVITY),
@@ -472,7 +463,7 @@
return Type.FRAGMENT;
} else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.VIEW)) {
boolean withFragmentBindings =
- Processors.hasAnnotation(element, AndroidClassNames.WITH_FRAGMENT_BINDINGS);
+ element.hasAnnotation(AndroidClassNames.WITH_FRAGMENT_BINDINGS);
return withFragmentBindings ? Type.VIEW : Type.VIEW_NO_FRAGMENT;
} else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.APPLICATION)) {
throw new BadInputException(
@@ -487,22 +478,22 @@
}
private static void checkConsistentAnnotations(
- TypeElement element, AndroidEntryPointMetadata baseMetadata) {
- TypeElement baseElement = baseMetadata.element();
+ XTypeElement element, AndroidEntryPointMetadata baseMetadata) {
+ XTypeElement baseElement = baseMetadata.element();
checkAnnotationsMatch(element, baseElement, AndroidClassNames.WITH_FRAGMENT_BINDINGS);
ProcessorErrors.checkState(
baseMetadata.allowsOptionalInjection()
- || !Processors.hasAnnotation(element, AndroidClassNames.OPTIONAL_INJECT),
+ || !element.hasAnnotation(AndroidClassNames.OPTIONAL_INJECT),
element,
"@OptionalInject Hilt class cannot extend from a non-optional @AndroidEntryPoint base: %s",
- element);
+ XElements.toStableString(element));
}
private static void checkAnnotationsMatch(
- TypeElement element, TypeElement baseElement, ClassName annotationName) {
- boolean isAnnotated = Processors.hasAnnotation(element, annotationName);
- boolean isBaseAnnotated = Processors.hasAnnotation(baseElement, annotationName);
+ XTypeElement element, XTypeElement baseElement, ClassName annotationName) {
+ boolean isAnnotated = element.hasAnnotation(annotationName);
+ boolean isBaseAnnotated = baseElement.hasAnnotation(annotationName);
ProcessorErrors.checkState(
isAnnotated == isBaseAnnotated,
element,
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessingStep.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessingStep.java
new file mode 100644
index 0000000..10ca698
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessingStep.java
@@ -0,0 +1,109 @@
+/*
+ * 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.android.processor.internal.androidentrypoint;
+
+import static dagger.hilt.processor.internal.HiltCompilerOptions.getGradleProjectType;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.android.processor.internal.AndroidClassNames;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.hilt.processor.internal.optionvalues.GradleProjectType;
+
+/**
+ * Processor that creates a module for classes marked with {@link
+ * dagger.hilt.android.AndroidEntryPoint}.
+ */
+public final class AndroidEntryPointProcessingStep extends BaseProcessingStep {
+ public AndroidEntryPointProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(
+ AndroidClassNames.ANDROID_ENTRY_POINT, AndroidClassNames.HILT_ANDROID_APP);
+ }
+
+ @Override
+ public boolean delayErrors() {
+ return true;
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) throws Exception {
+ AndroidEntryPointMetadata metadata = AndroidEntryPointMetadata.of(element);
+ new InjectorEntryPointGenerator(processingEnv(), metadata).generate();
+ switch (metadata.androidType()) {
+ case APPLICATION:
+ GradleProjectType projectType = getGradleProjectType(processingEnv());
+ if (projectType != GradleProjectType.UNSET) {
+ ProcessorErrors.checkState(
+ projectType == GradleProjectType.APP,
+ element,
+ "Application class, %s, annotated with @HiltAndroidApp must be defined in a "
+ + "Gradle android application module (i.e. contains a build.gradle file with "
+ + "`plugins { id 'com.android.application' }`).",
+ metadata.element().getQualifiedName());
+ }
+
+ // The generated application references the generated component so they must be generated
+ // in the same build unit. Thus, we only generate the application here if we're using the
+ // aggregating root processor. If we're using the Hilt Gradle plugin's aggregating task, we
+ // need to generate the application within ComponentTreeDepsProcessor instead.
+ if (useAggregatingRootProcessor(processingEnv())) {
+ // While we could always generate the application in ComponentTreeDepsProcessor, even if
+ // we're using the aggregating root processor, it can lead to extraneous errors when
+ // things fail before ComponentTreeDepsProcessor runs so we generate it here to avoid that
+ new ApplicationGenerator(processingEnv(), metadata).generate();
+ } else {
+ // If we're not using the aggregating root processor, then make sure the root application
+ // does not extend the generated application directly, and instead uses bytecode injection
+ ProcessorErrors.checkState(
+ metadata.requiresBytecodeInjection(),
+ metadata.element(),
+ "'enableAggregatingTask=true' cannot be used when the application directly "
+ + "references the generated Hilt class, %s. Either extend %s directly (relying "
+ + "on the Gradle plugin described in "
+ + "https://dagger.dev/hilt/gradle-setup#why-use-the-plugin or set "
+ + "'enableAggregatingTask=false'.",
+ metadata.generatedClassName(),
+ metadata.baseClassName());
+ }
+ break;
+ case ACTIVITY:
+ new ActivityGenerator(processingEnv(), metadata).generate();
+ break;
+ case BROADCAST_RECEIVER:
+ new BroadcastReceiverGenerator(processingEnv(), metadata).generate();
+ break;
+ case FRAGMENT:
+ new FragmentGenerator(processingEnv(), metadata).generate();
+ break;
+ case SERVICE:
+ new ServiceGenerator(processingEnv(), metadata).generate();
+ break;
+ case VIEW:
+ new ViewGenerator(processingEnv(), metadata).generate();
+ break;
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
index 04ea06b..e7c3831 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
@@ -16,20 +16,12 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.getGradleProjectType;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableSet;
-import dagger.hilt.android.processor.internal.AndroidClassNames;
-import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.optionvalues.GradleProjectType;
-import java.util.Set;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/**
@@ -38,80 +30,9 @@
*/
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class AndroidEntryPointProcessor extends BaseProcessor {
-
+public final class AndroidEntryPointProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(
- AndroidClassNames.ANDROID_ENTRY_POINT.toString(),
- AndroidClassNames.HILT_ANDROID_APP.toString());
- }
-
- @Override
- public boolean delayErrors() {
- return true;
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- AndroidEntryPointMetadata metadata = AndroidEntryPointMetadata.of(getProcessingEnv(), element);
- new InjectorEntryPointGenerator(getProcessingEnv(), metadata).generate();
- switch (metadata.androidType()) {
- case APPLICATION:
- GradleProjectType projectType = getGradleProjectType(getProcessingEnv());
- if (projectType != GradleProjectType.UNSET) {
- ProcessorErrors.checkState(
- projectType == GradleProjectType.APP,
- element,
- "Application class, %s, annotated with @HiltAndroidApp must be defined in a "
- + "Gradle android application module (i.e. contains a build.gradle file with "
- + "`plugins { id 'com.android.application' }`).",
- metadata.element().getQualifiedName());
- }
-
- // The generated application references the generated component so they must be generated
- // in the same build unit. Thus, we only generate the application here if we're using the
- // aggregating root processor. If we're using the Hilt Gradle plugin's aggregating task, we
- // need to generate the application within ComponentTreeDepsProcessor instead.
- if (useAggregatingRootProcessor(getProcessingEnv())) {
- // While we could always generate the application in ComponentTreeDepsProcessor, even if
- // we're using the aggregating root processor, it can lead to extraneous errors when
- // things fail before ComponentTreeDepsProcessor runs so we generate it here to avoid that
- new ApplicationGenerator(getProcessingEnv(), metadata).generate();
- } else {
- // If we're not using the aggregating root processor, then make sure the root application
- // does not extend the generated application directly, and instead uses bytecode injection
- ProcessorErrors.checkState(
- metadata.requiresBytecodeInjection(),
- metadata.element(),
- "'enableAggregatingTask=true' cannot be used when the application directly "
- + "references the generated Hilt class, %s. Either extend %s directly (relying "
- + "on the Gradle plugin described in "
- + "https://dagger.dev/hilt/gradle-setup#why-use-the-plugin or set "
- + "'enableAggregatingTask=false'.",
- metadata.generatedClassName(),
- metadata.baseClassName());
- }
- break;
- case ACTIVITY:
- new ActivityGenerator(getProcessingEnv(), metadata).generate();
- break;
- case BROADCAST_RECEIVER:
- new BroadcastReceiverGenerator(getProcessingEnv(), metadata).generate();
- break;
- case FRAGMENT:
- new FragmentGenerator(
- getProcessingEnv(), metadata )
- .generate();
- break;
- case SERVICE:
- new ServiceGenerator(getProcessingEnv(), metadata).generate();
- break;
- case VIEW:
- new ViewGenerator(getProcessingEnv(), metadata).generate();
- break;
- default:
- throw new IllegalStateException("Unknown Hilt type: " + metadata.androidType());
- }
+ protected BaseProcessingStep processingStep() {
+ return new AndroidEntryPointProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
index dc7bd37..84a256b 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
@@ -16,9 +16,15 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PROTECTED;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static kotlin.streams.jdk8.StreamsKt.asStream;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeParameterElement;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
@@ -28,28 +34,23 @@
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.ComponentNames;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XElements;
import java.io.IOException;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
+import java.util.stream.Stream;
import javax.lang.model.element.Modifier;
-import javax.lang.model.util.ElementFilter;
/** Generates an Hilt Application for an @AndroidEntryPoint app class. */
public final class ApplicationGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
private final ClassName wrapperClassName;
private final ComponentNames componentNames;
- public ApplicationGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
+ public ApplicationGenerator(XProcessingEnv env, AndroidEntryPointMetadata metadata) {
this.env = env;
this.metadata = metadata;
this.wrapperClassName = metadata.generatedClassName();
@@ -63,11 +64,12 @@
public void generate() throws IOException {
TypeSpec.Builder typeSpecBuilder =
TypeSpec.classBuilder(wrapperClassName.simpleName())
- .addOriginatingElement(metadata.element())
.superclass(metadata.baseClassName())
.addModifiers(metadata.generatedClassModifiers())
.addField(injectedField());
+ JavaPoetExtKt.addOriginatingElement(typeSpecBuilder, metadata.element());
+
typeSpecBuilder
.addField(componentManagerField())
.addMethod(componentManagerMethod());
@@ -76,7 +78,7 @@
Processors.addGeneratedAnnotation(typeSpecBuilder, env, getClass());
metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
+ .map(XTypeParameterElement::getTypeVariableName)
.forEachOrdered(typeSpecBuilder::addTypeVariable);
Generators.copyLintAnnotations(metadata.element(), typeSpecBuilder);
@@ -90,34 +92,32 @@
typeSpecBuilder.addMethod(onCreateMethod()).addMethod(injectionMethod());
}
- JavaFile.builder(metadata.elementClassName().packageName(), typeSpecBuilder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(metadata.elementClassName().packageName(), typeSpecBuilder.build())
+ .build(),
+ XFiler.Mode.Isolating);
}
private boolean hasCustomInject() {
- boolean hasCustomInject =
- Processors.hasAnnotation(metadata.element(), AndroidClassNames.CUSTOM_INJECT);
+ boolean hasCustomInject = metadata.element().hasAnnotation(AndroidClassNames.CUSTOM_INJECT);
if (hasCustomInject) {
// Check that the Hilt base class does not already define a customInject implementation.
- Set<ExecutableElement> customInjectMethods =
- ElementFilter.methodsIn(
- ImmutableSet.<Element>builder()
- .addAll(metadata.element().getEnclosedElements())
- .addAll(env.getElementUtils().getAllMembers(metadata.baseElement()))
- .build())
- .stream()
- .filter(method -> method.getSimpleName().contentEquals("customInject"))
+ ImmutableSet<XMethodElement> customInjectMethods =
+ Stream.concat(
+ metadata.element().getDeclaredMethods().stream(),
+ asStream(metadata.baseElement().getAllMethods()))
+ .filter(method -> getSimpleName(method).contentEquals("customInject"))
.filter(method -> method.getParameters().isEmpty())
- .collect(Collectors.toSet());
+ .collect(toImmutableSet());
- for (ExecutableElement customInjectMethod : customInjectMethods) {
+ for (XMethodElement customInjectMethod : customInjectMethods) {
ProcessorErrors.checkState(
- customInjectMethod.getModifiers().containsAll(ImmutableSet.of(ABSTRACT, PROTECTED)),
+ customInjectMethod.isAbstract() && customInjectMethod.isProtected(),
customInjectMethod,
"%s#%s, must have modifiers `abstract` and `protected` when using @CustomInject.",
- customInjectMethod.getEnclosingElement(),
- customInjectMethod);
+ XElements.toStableString(customInjectMethod.getEnclosingElement()),
+ XElements.toStableString(customInjectMethod));
}
}
return hasCustomInject;
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index 55bfcb1..96beff3 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -32,7 +32,11 @@
java_library(
name = "processor_lib",
- srcs = ["AndroidEntryPointProcessor.java"],
+ srcs = [
+ "AndroidEntryPointProcessingStep.java",
+ "AndroidEntryPointProcessor.java",
+ "KspAndroidEntryPointProcessor.java",
+ ],
deps = [
":android_generators",
":metadata",
@@ -40,11 +44,13 @@
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal:compiler_options",
"//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/optionvalues",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
+ "//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -63,18 +69,17 @@
deps = [
":metadata",
"//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/android/processor/internal:utils",
"//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:compiler_options",
"//java/dagger/hilt/processor/internal:component_names",
- "//java/dagger/hilt/processor/internal:element_descriptors",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:common",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
+ "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
],
)
@@ -85,14 +90,13 @@
],
deps = [
"//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:compiler_options",
"//java/dagger/hilt/processor/internal:components",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/kotlin",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
index 23c054a..156842b 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
@@ -16,9 +16,19 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static dagger.hilt.processor.internal.ElementDescriptors.getMethodDescriptor;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import com.google.common.collect.Iterables;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XTypeParameterElement;
+import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
@@ -26,33 +36,25 @@
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
-import dagger.hilt.android.processor.internal.MoreTypes;
import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XExecutableTypes;
import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
+import java.util.Optional;
import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.util.ElementFilter;
/** Generates an Hilt BroadcastReceiver class for the @AndroidEntryPoint annotated class. */
public final class BroadcastReceiverGenerator {
-
private static final String ON_RECEIVE_DESCRIPTOR =
"onReceive(Landroid/content/Context;Landroid/content/Intent;)V";
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
private final ClassName generatedClassName;
- public BroadcastReceiverGenerator(
- ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
+ public BroadcastReceiverGenerator(XProcessingEnv env, AndroidEntryPointMetadata metadata) {
this.env = env;
this.metadata = metadata;
-
generatedClassName = metadata.generatedClassName();
}
@@ -63,17 +65,17 @@
public void generate() throws IOException {
TypeSpec.Builder builder =
TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
.superclass(metadata.baseClassName())
.addModifiers(metadata.generatedClassModifiers())
.addMethod(onReceiveMethod());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyConstructors(metadata.baseElement(), builder);
metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
+ .map(XTypeParameterElement::getTypeVariableName)
.forEachOrdered(builder::addTypeVariable);
Generators.addInjectionMethods(metadata, builder);
@@ -94,21 +96,21 @@
.build());
}
- JavaFile.builder(generatedClassName.packageName(),
- builder.build()).build().writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(generatedClassName.packageName(), builder.build()).build(),
+ XFiler.Mode.Isolating);
}
- private static boolean isOnReceiveImplemented(TypeElement typeElement) {
+ private static boolean isOnReceiveImplemented(XTypeElement typeElement) {
boolean isImplemented =
- ElementFilter.methodsIn(typeElement.getEnclosedElements()).stream()
- .anyMatch(
- methodElement ->
- getMethodDescriptor(methodElement).equals(ON_RECEIVE_DESCRIPTOR)
- && !methodElement.getModifiers().contains(Modifier.ABSTRACT));
+ typeElement.getDeclaredMethods().stream()
+ .filter(method -> !method.isAbstract())
+ .anyMatch(method -> method.getJvmDescriptor().equals(ON_RECEIVE_DESCRIPTOR));
if (isImplemented) {
return true;
- } else if (typeElement.getSuperclass().getKind() != TypeKind.NONE) {
- return isOnReceiveImplemented(MoreTypes.asTypeElement(typeElement.getSuperclass()));
+ } else if (typeElement.getSuperClass() != null) {
+ return isOnReceiveImplemented(typeElement.getSuperClass().getTypeElement());
} else {
return false;
}
@@ -136,19 +138,38 @@
method.addStatement("super.onReceive(context, intent)");
} else {
// Get the onReceive method element from BroadcastReceiver.
- ExecutableElement onReceiveElement =
- Iterables.getOnlyElement(
- MoreTypes.findMethods(
- env.getElementUtils()
- .getTypeElement(AndroidClassNames.BROADCAST_RECEIVER.toString()),
- "onReceive"));
+ XMethodElement onReceiveMethod =
+ getOnlyElement(
+ findMethodsByName(
+ env.requireTypeElement(AndroidClassNames.BROADCAST_RECEIVER), "onReceive"));
// If the base class or one of its super classes implements onReceive, call super.onReceive()
- MoreTypes.findInheritedMethod(env.getTypeUtils(), metadata.baseElement(), onReceiveElement)
- .filter(onReceive -> !onReceive.getModifiers().contains(Modifier.ABSTRACT))
+ findMethodBySubsignature(metadata.baseElement(), onReceiveMethod)
+ .filter(onReceive -> !onReceive.isAbstract())
.ifPresent(onReceive -> method.addStatement("super.onReceive(context, intent)"));
}
-
return method.build();
}
+
+ private Optional<XMethodElement> findMethodBySubsignature(
+ XTypeElement typeElement, XMethodElement method) {
+ String methodName = getSimpleName(method);
+ XType currentType = typeElement.getType();
+ Optional<XMethodElement> match = Optional.empty();
+ while (!match.isPresent() && currentType != null) {
+ match =
+ findMethodsByName(currentType.getTypeElement(), methodName).stream()
+ .filter(m -> XExecutableTypes.isSubsignature(m, method))
+ .collect(toOptional());
+ currentType = currentType.getTypeElement().getSuperClass();
+ }
+ return match;
+ }
+
+ private static ImmutableSet<XMethodElement> findMethodsByName(
+ XTypeElement typeElement, String name) {
+ return typeElement.getDeclaredMethods().stream()
+ .filter(m -> getSimpleName(m).contentEquals(name))
+ .collect(toImmutableSet());
+ }
}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
index bf00e66..45017e4 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
@@ -16,6 +16,10 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeParameterElement;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
@@ -23,12 +27,10 @@
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
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.Modifier;
/** Generates an Hilt Fragment class for the @AndroidEntryPoint annotated class. */
@@ -43,12 +45,12 @@
.addModifiers(Modifier.PRIVATE)
.build();
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
private final ClassName generatedClassName;
public FragmentGenerator(
- ProcessingEnvironment env,
+ XProcessingEnv env,
AndroidEntryPointMetadata metadata ) {
this.env = env;
this.metadata = metadata;
@@ -56,9 +58,10 @@
}
public void generate() throws IOException {
- JavaFile.builder(generatedClassName.packageName(), createTypeSpec())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(generatedClassName.packageName(), createTypeSpec()).build(),
+ XFiler.Mode.Isolating);
}
// @Generated("FragmentGenerator")
@@ -68,7 +71,6 @@
TypeSpec createTypeSpec() {
TypeSpec.Builder builder =
TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
.superclass(metadata.baseClassName())
.addModifiers(metadata.generatedClassModifiers())
.addField(COMPONENT_CONTEXT_FIELD)
@@ -79,6 +81,7 @@
.addMethod(inflatorMethod())
.addField(DISABLE_GET_CONTEXT_FIX_FIELD);
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
@@ -86,7 +89,7 @@
Generators.copyConstructors(metadata.baseElement(), builder);
metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
+ .map(XTypeParameterElement::getTypeVariableName)
.forEachOrdered(builder::addTypeVariable);
Generators.addComponentOverride(metadata, builder);
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
index e2892aa..dc2339b 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
@@ -16,14 +16,22 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import static androidx.room.compiler.processing.JavaPoetExtKt.toAnnotationSpec;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import com.google.auto.common.AnnotationMirrors;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XVariableElement;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.AnnotationSpec;
@@ -37,17 +45,10 @@
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointMetadata.AndroidType;
import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementFilter;
/** Helper class for writing Hilt generators. */
final class Generators {
@@ -63,22 +64,17 @@
annotation);
}
- /**
- * Copies all constructors with arguments to the builder.
- */
- static void copyConstructors(TypeElement baseClass, TypeSpec.Builder builder) {
+ /** Copies all constructors with arguments to the builder. */
+ static void copyConstructors(XTypeElement baseClass, TypeSpec.Builder builder) {
copyConstructors(baseClass, CodeBlock.builder().build(), builder);
}
- /**
- * Copies all constructors with arguments along with an appended body to the builder.
- */
- static void copyConstructors(TypeElement baseClass, CodeBlock body, TypeSpec.Builder builder) {
- List<ExecutableElement> constructors =
- ElementFilter.constructorsIn(baseClass.getEnclosedElements())
- .stream()
- .filter(constructor -> !constructor.getModifiers().contains(PRIVATE))
- .collect(Collectors.toList());
+ /** Copies all constructors with arguments along with an appended body to the builder. */
+ static void copyConstructors(XTypeElement baseClass, CodeBlock body, TypeSpec.Builder builder) {
+ ImmutableList<XConstructorElement> constructors =
+ baseClass.getConstructors().stream()
+ .filter(constructor -> !constructor.isPrivate())
+ .collect(toImmutableList());
if (constructors.size() == 1
&& getOnlyElement(constructors).getParameters().isEmpty()
@@ -91,14 +87,10 @@
}
/** Returns Optional with AnnotationSpec for Nullable if found on element, empty otherwise. */
- private static Optional<AnnotationSpec> getNullableAnnotationSpec(Element element) {
- for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
- if (annotationMirror
- .getAnnotationType()
- .asElement()
- .getSimpleName()
- .contentEquals("Nullable")) {
- AnnotationSpec annotationSpec = AnnotationSpec.get(annotationMirror);
+ private static Optional<AnnotationSpec> getNullableAnnotationSpec(XElement element) {
+ for (XAnnotation annotation : element.getAllAnnotations()) {
+ if (annotation.getClassName().simpleName().contentEquals("Nullable")) {
+ AnnotationSpec annotationSpec = toAnnotationSpec(annotation);
// If using the android internal Nullable, convert it to the externally-visible version.
return AndroidClassNames.NULLABLE_INTERNAL.equals(annotationSpec.type)
? Optional.of(AnnotationSpec.builder(AndroidClassNames.NULLABLE).build())
@@ -112,26 +104,27 @@
* Returns a ParameterSpec of the input parameter, @Nullable annotated if existing in original
* (this does not handle Nullable type annotations).
*/
- private static ParameterSpec getParameterSpecWithNullable(VariableElement parameter) {
- ParameterSpec.Builder builder = ParameterSpec.get(parameter).toBuilder();
+ private static ParameterSpec getParameterSpecWithNullable(XVariableElement parameter) {
+ ParameterSpec.Builder builder =
+ ParameterSpec.builder(parameter.getType().getTypeName(), getSimpleName(parameter));
getNullableAnnotationSpec(parameter).ifPresent(builder::addAnnotation);
return builder.build();
}
/**
- * Returns a {@link MethodSpec} for a constructor matching the given {@link ExecutableElement}
- * constructor signature, and just calls super. If the constructor is
- * {@link android.annotation.TargetApi} guarded, adds the TargetApi as well.
+ * Returns a {@link MethodSpec} for a constructor matching the given {@link XConstructorElement}
+ * constructor signature, and just calls super. If the constructor is {@link
+ * android.annotation.TargetApi} guarded, adds the TargetApi as well.
*/
// Example:
// Foo(Param1 param1, Param2 param2) {
// super(param1, param2);
// }
- static MethodSpec copyConstructor(ExecutableElement constructor) {
+ static MethodSpec copyConstructor(XConstructorElement constructor) {
return copyConstructor(constructor, CodeBlock.builder().build());
}
- private static MethodSpec copyConstructor(ExecutableElement constructor, CodeBlock body) {
+ private static MethodSpec copyConstructor(XConstructorElement constructor, CodeBlock body) {
List<ParameterSpec> params =
constructor.getParameters().stream()
.map(Generators::getParameterSpecWithNullable)
@@ -144,26 +137,26 @@
"super($L)", params.stream().map(param -> param.name).collect(joining(", ")))
.addCode(body);
- constructor.getAnnotationMirrors().stream()
- .filter(a -> Processors.hasAnnotation(a, AndroidClassNames.TARGET_API))
+ constructor.getAllAnnotations().stream()
+ .filter(a -> a.getTypeElement().hasAnnotation(AndroidClassNames.TARGET_API))
.collect(toOptional())
- .map(AnnotationSpec::get)
+ .map(JavaPoetExtKt::toAnnotationSpec)
.ifPresent(builder::addAnnotation);
return builder.build();
}
/** Copies SuppressWarnings annotations from the annotated element to the generated element. */
- static void copySuppressAnnotations(Element element, TypeSpec.Builder builder) {
+ static void copySuppressAnnotations(XElement element, TypeSpec.Builder builder) {
ImmutableSet<String> suppressValues =
SUPPRESS_ANNOTATION_PROPERTY_NAME.keySet().stream()
- .filter(annotation -> Processors.hasAnnotation(element, annotation))
- .map(
+ .filter(element::hasAnnotation)
+ .flatMap(
annotation ->
- AnnotationMirrors.getAnnotationValue(
- Processors.getAnnotationMirror(element, annotation),
- SUPPRESS_ANNOTATION_PROPERTY_NAME.get(annotation)))
- .flatMap(value -> Processors.getStringArrayAnnotationValue(value).stream())
+ element
+ .getAnnotation(annotation)
+ .getAsStringList(SUPPRESS_ANNOTATION_PROPERTY_NAME.get(annotation))
+ .stream())
.collect(toImmutableSet());
if (!suppressValues.isEmpty()) {
@@ -179,11 +172,9 @@
*
* <p>Note: For now we only copy over {@link android.annotation.TargetApi}.
*/
- static void copyLintAnnotations(Element element, TypeSpec.Builder builder) {
- if (Processors.hasAnnotation(element, AndroidClassNames.TARGET_API)) {
- builder.addAnnotation(
- AnnotationSpec.get(
- Processors.getAnnotationMirror(element, AndroidClassNames.TARGET_API)));
+ static void copyLintAnnotations(XElement element, TypeSpec.Builder builder) {
+ if (element.hasAnnotation(AndroidClassNames.TARGET_API)) {
+ builder.addAnnotation(toAnnotationSpec(element.getAnnotation(AndroidClassNames.TARGET_API)));
}
}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
index 1c5784d..5f263f2 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
@@ -16,6 +16,9 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
@@ -23,17 +26,15 @@
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.Modifier;
/** Generates an entry point that allows for injection of the given activity */
public final class InjectorEntryPointGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
- public InjectorEntryPointGenerator(
- ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
+ public InjectorEntryPointGenerator(XProcessingEnv env, AndroidEntryPointMetadata metadata) {
this.env = env;
this.metadata = metadata;
}
@@ -47,7 +48,6 @@
ClassName name = metadata.injectorClassName();
TypeSpec.Builder builder =
TypeSpec.interfaceBuilder(name.simpleName())
- .addOriginatingElement(metadata.element())
.addAnnotation(Processors.getOriginatingElementAnnotation(metadata.element()))
.addAnnotation(ClassNames.GENERATED_ENTRY_POINT)
.addAnnotation(metadata.injectorInstallInAnnotation())
@@ -60,9 +60,13 @@
Processors.upperToLowerCamel(metadata.elementClassName().simpleName()))
.build());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
Generators.copySuppressAnnotations(metadata.element(), builder);
- JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler());
+
+ env.getFiler()
+ .write(
+ JavaFile.builder(name.packageName(), builder.build()).build(), XFiler.Mode.Isolating);
}
}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/KspAndroidEntryPointProcessor.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/KspAndroidEntryPointProcessor.java
new file mode 100644
index 0000000..bffcbe0
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/KspAndroidEntryPointProcessor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.processor.internal.androidentrypoint;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/**
+ * Processor that creates a module for classes marked with {@link
+ * dagger.hilt.android.AndroidEntryPoint}.
+ */
+public final class KspAndroidEntryPointProcessor extends KspBaseProcessingStepProcessor {
+ public KspAndroidEntryPointProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new AndroidEntryPointProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspAndroidEntryPointProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspAndroidEntryPointProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
index 2673363..8e1405e 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
@@ -16,32 +16,36 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import static java.util.stream.Collectors.joining;
+
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeParameterElement;
+import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.Processors;
import java.io.IOException;
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
-import javax.lang.model.util.ElementFilter;
/** Generates an Hilt Service class for the @AndroidEntryPoint annotated class. */
public final class ServiceGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
private final ClassName generatedClassName;
- public ServiceGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
+ public ServiceGenerator(XProcessingEnv env, AndroidEntryPointMetadata metadata) {
this.env = env;
this.metadata = metadata;
-
generatedClassName = metadata.generatedClassName();
}
@@ -52,47 +56,52 @@
public void generate() throws IOException {
TypeSpec.Builder builder =
TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
.superclass(metadata.baseClassName())
.addModifiers(metadata.generatedClassModifiers())
.addMethods(baseClassConstructors())
.addMethod(onCreateMethod());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
Generators.copySuppressAnnotations(metadata.element(), builder);
metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
+ .map(XTypeParameterElement::getTypeVariableName)
.forEachOrdered(builder::addTypeVariable);
Generators.addInjectionMethods(metadata, builder);
Generators.addComponentOverride(metadata, builder);
- JavaFile.builder(generatedClassName.packageName(), builder.build())
- .build().writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(generatedClassName.packageName(), builder.build()).build(),
+ XFiler.Mode.Isolating);
}
- private List<MethodSpec> baseClassConstructors() {
- return ElementFilter.constructorsIn(metadata.baseElement().getEnclosedElements())
- .stream()
- .map((constructor) -> {
- List<ParameterSpec> params =
- constructor.getParameters()
- .stream()
- .map(p -> ParameterSpec.builder(TypeName.get(p.asType()), p.toString()).build())
- .collect(Collectors.toList());
+ private ImmutableList<MethodSpec> baseClassConstructors() {
+ return metadata.baseElement().getConstructors().stream()
+ .map(ServiceGenerator::toMethodSpec)
+ .collect(toImmutableList());
+ }
- return MethodSpec.constructorBuilder()
- .addParameters(params)
- .addStatement(
- "super($L)",
- params.stream().map(p -> p.name).collect(Collectors.joining(",")))
- .build();
- })
- .collect(Collectors.toList());
+ private static MethodSpec toMethodSpec(XConstructorElement constructor) {
+ ImmutableList<ParameterSpec> params =
+ constructor.getParameters().stream()
+ .map(ServiceGenerator::toParameterSpec)
+ .collect(toImmutableList());
+
+ return MethodSpec.constructorBuilder()
+ .addParameters(params)
+ .addStatement("super($L)", params.stream().map(p -> p.name).collect(joining(",")))
+ .build();
+ }
+
+ private static ParameterSpec toParameterSpec(XExecutableParameterElement parameter) {
+ return ParameterSpec.builder(parameter.getType().getTypeName(), getSimpleName(parameter))
+ .build();
}
// @CallSuper
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
index 11a00af..799ba1f 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
@@ -16,37 +16,35 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.XTypeKt.isInt;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.Visibility;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XExecutableParameterElement;
+import androidx.room.compiler.processing.XFiler;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeParameterElement;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
import dagger.hilt.android.processor.internal.AndroidClassNames;
import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
/** Generates an Hilt View class for the @AndroidEntryPoint annotated class. */
public final class ViewGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final AndroidEntryPointMetadata metadata;
private final ClassName generatedClassName;
- public ViewGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
+ public ViewGenerator(XProcessingEnv env, AndroidEntryPointMetadata metadata) {
this.env = env;
this.metadata = metadata;
-
generatedClassName = metadata.generatedClassName();
}
@@ -55,7 +53,7 @@
// ComponentManagerHolder<ViewComponentManager<$CLASS_EntryPoint>> {
// ...
// }
- public void generate() throws IOException {
+ public void generate() {
// Note: we do not use the Generators helper methods here because injection is called
// from the constructor where the double-check pattern doesn't work (due to the super
// constructor being called before fields are initialized) and because it isn't necessary
@@ -63,37 +61,37 @@
TypeSpec.Builder builder =
TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
.superclass(metadata.baseClassName())
.addModifiers(metadata.generatedClassModifiers());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.element());
Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
Processors.addGeneratedAnnotation(builder, env, getClass());
Generators.copyLintAnnotations(metadata.element(), builder);
Generators.copySuppressAnnotations(metadata.element(), builder);
metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
+ .map(XTypeParameterElement::getTypeVariableName)
.forEachOrdered(builder::addTypeVariable);
Generators.addComponentOverride(metadata, builder);
-
Generators.addInjectionMethods(metadata, builder);
- ElementFilter.constructorsIn(metadata.baseElement().getEnclosedElements()).stream()
+ metadata.baseElement().getConstructors().stream()
.filter(this::isConstructorVisibleToGeneratedClass)
- .forEach(constructor -> builder.addMethod(constructorMethod(constructor)));
+ .map(this::constructorMethod)
+ .forEach(builder::addMethod);
- JavaFile.builder(generatedClassName.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(generatedClassName.packageName(), builder.build()).build(),
+ XFiler.Mode.Isolating);
}
- private boolean isConstructorVisibleToGeneratedClass(ExecutableElement constructorElement) {
- if (Visibility.ofElement(constructorElement) == Visibility.DEFAULT
- && !isInOurPackage(constructorElement)) {
+ private boolean isConstructorVisibleToGeneratedClass(XConstructorElement constructor) {
+ if (Processors.hasJavaPackagePrivateVisibility(constructor) && !isInOurPackage(constructor)) {
return false;
- } else if (Visibility.ofElement(constructorElement) == Visibility.PRIVATE) {
+ } else if (constructor.isPrivate()) {
return false;
}
@@ -114,34 +112,33 @@
* }
* </pre>
*/
- private MethodSpec constructorMethod(ExecutableElement constructorElement) {
- MethodSpec.Builder constructor =
- Generators.copyConstructor(constructorElement).toBuilder();
+ private MethodSpec constructorMethod(XConstructorElement constructor) {
+ MethodSpec.Builder builder = Generators.copyConstructor(constructor).toBuilder();
// TODO(b/210544481): Once this bug is fixed we should require that the user adds this
// annotation to their constructor and we'll propagate it from there rather than trying to
// guess whether this needs @TargetApi from the signature. This check is a bit flawed. For
// example, the user could write a 5 parameter constructor that calls the restricted 4 parameter
// constructor and we would miss adding @TargetApi to it.
- if (isRestrictedApiConstructor(constructorElement)) {
+ if (isRestrictedApiConstructor(constructor)) {
// 4 parameter constructors are only available on @TargetApi(21).
- constructor.addAnnotation(
+ builder.addAnnotation(
AnnotationSpec.builder(AndroidClassNames.TARGET_API).addMember("value", "21").build());
}
- constructor.addStatement("inject()");
+ builder.addStatement("inject()");
- return constructor.build();
+ return builder.build();
}
- private boolean isRestrictedApiConstructor(ExecutableElement constructor) {
+ private boolean isRestrictedApiConstructor(XConstructorElement constructor) {
if (constructor.getParameters().size() != 4) {
return false;
}
- List<? extends VariableElement> constructorParams = constructor.getParameters();
+ List<XExecutableParameterElement> constructorParams = constructor.getParameters();
for (int i = 0; i < constructorParams.size(); i++) {
- TypeMirror type = constructorParams.get(i).asType();
+ XType type = constructorParams.get(i).getType();
switch (i) {
case 0:
if (!isFirstRestrictedParameter(type)) {
@@ -171,28 +168,28 @@
return true;
}
- private static boolean isFourthRestrictedParameter(TypeMirror type) {
- return type.getKind().isPrimitive()
- && Processors.getPrimitiveType(type).getKind() == TypeKind.INT;
+ private static boolean isFourthRestrictedParameter(XType type) {
+ return isPrimitive(type) && isInt(type);
}
- private static boolean isThirdRestrictedParameter(TypeMirror type) {
- return type.getKind().isPrimitive()
- && Processors.getPrimitiveType(type).getKind() == TypeKind.INT;
+ private static boolean isThirdRestrictedParameter(XType type) {
+ return isPrimitive(type) && isInt(type);
}
- private static boolean isSecondRestrictedParameter(TypeMirror type) {
- return type.getKind() == TypeKind.DECLARED
- && Processors.isAssignableFrom(asTypeElement(type), AndroidClassNames.ATTRIBUTE_SET);
+ private static boolean isSecondRestrictedParameter(XType type) {
+ return isDeclared(type)
+ && Processors.isAssignableFrom(type.getTypeElement(), AndroidClassNames.ATTRIBUTE_SET);
}
- private static boolean isFirstRestrictedParameter(TypeMirror type) {
- return type.getKind() == TypeKind.DECLARED
- && Processors.isAssignableFrom(asTypeElement(type), AndroidClassNames.CONTEXT);
+ private static boolean isFirstRestrictedParameter(XType type) {
+ return isDeclared(type)
+ && Processors.isAssignableFrom(type.getTypeElement(), AndroidClassNames.CONTEXT);
}
- private boolean isInOurPackage(ExecutableElement constructorElement) {
- return MoreElements.getPackage(constructorElement)
- .equals(MoreElements.getPackage(metadata.element()));
+ private boolean isInOurPackage(XConstructorElement constructor) {
+ return constructor
+ .getEnclosingElement()
+ .getPackageName()
+ .contentEquals(metadata.element().getPackageName());
}
}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
index 913fafe..5fb1736 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
@@ -30,7 +30,9 @@
srcs = [
"BindValueGenerator.java",
"BindValueMetadata.java",
+ "BindValueProcessingStep.java",
"BindValueProcessor.java",
+ "KspBindValueProcessor.java",
],
deps = [
"//:dagger_with_compiler",
@@ -41,14 +43,14 @@
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/kotlin",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
- "//third_party/java/jsr250_annotations",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
index 108a15d..15bb46d 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
@@ -20,8 +20,10 @@
import static com.google.common.base.CaseFormat.UPPER_CAMEL;
import static java.util.Comparator.comparing;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
@@ -34,11 +36,12 @@
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Components;
import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntoMap;
import dagger.multibindings.IntoSet;
import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
/**
@@ -47,15 +50,15 @@
final class BindValueGenerator {
private static final String SUFFIX = "_BindValueModule";
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final BindValueMetadata metadata;
private final ClassName testClassName;
private final ClassName className;
- BindValueGenerator(ProcessingEnvironment env, BindValueMetadata metadata) {
+ BindValueGenerator(XProcessingEnv env, BindValueMetadata metadata) {
this.env = env;
this.metadata = metadata;
- testClassName = ClassName.get(metadata.testElement());
+ testClassName = metadata.testElement().getClassName();
className = Processors.append(testClassName, SUFFIX);
}
@@ -65,16 +68,14 @@
// // providesMethods ...
// }
void generate() throws IOException {
- TypeSpec.Builder builder =
- TypeSpec.classBuilder(className)
- .addOriginatingElement(metadata.testElement())
- .addAnnotation(Processors.getOriginatingElementAnnotation(metadata.testElement()))
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .addAnnotation(Module.class)
- .addAnnotation(
- Components.getInstallInAnnotationSpec(
- ImmutableSet.of(ClassNames.SINGLETON_COMPONENT)))
- .addMethod(providesTestMethod());
+ TypeSpec.Builder builder = TypeSpec.classBuilder(className);
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.testElement())
+ .addAnnotation(Processors.getOriginatingElementAnnotation(metadata.testElement()))
+ .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .addAnnotation(Module.class)
+ .addAnnotation(
+ Components.getInstallInAnnotationSpec(ImmutableSet.of(ClassNames.SINGLETON_COMPONENT)))
+ .addMethod(providesTestMethod());
Processors.addGeneratedAnnotation(builder, env, getClass());
@@ -83,9 +84,8 @@
.sorted(comparing(MethodSpec::toString))
.forEachOrdered(builder::addMethod);
- JavaFile.builder(className.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(JavaFile.builder(className.packageName(), builder.build()).build(), Mode.Isolating);
}
// @Provides
@@ -121,25 +121,24 @@
// }
private MethodSpec providesMethod(BindValueElement bindValue) {
// We only allow fields in the Test class, which should have unique variable names.
- String methodName = "provides"
- + LOWER_CAMEL.to(UPPER_CAMEL, bindValue.variableElement().getSimpleName().toString());
+ String methodName =
+ "provides" + LOWER_CAMEL.to(UPPER_CAMEL, bindValue.fieldElement().getName());
MethodSpec.Builder builder =
MethodSpec.methodBuilder(methodName)
.addAnnotation(Provides.class)
.addModifiers(Modifier.STATIC)
- .returns(ClassName.get(bindValue.variableElement().asType()));
+ .returns(bindValue.fieldElement().getType().getTypeName());
- if (bindValue.variableElement().getModifiers().contains(Modifier.STATIC)) {
- builder.addStatement(
- "return $T.$L", testClassName, bindValue.variableElement().getSimpleName());
+ if (XElements.isStatic(bindValue.fieldElement())) {
+ builder.addStatement("return $T.$L", testClassName, bindValue.fieldElement().getName());
} else {
builder
.addParameter(testClassName, "test")
.addStatement(
"return $L",
bindValue.getterElement().isPresent()
- ? CodeBlock.of("test.$L()", bindValue.getterElement().get().getSimpleName())
- : CodeBlock.of("test.$L", bindValue.variableElement().getSimpleName()));
+ ? CodeBlock.of("test.$L()", bindValue.getterElement().get().getJvmName())
+ : CodeBlock.of("test.$L", bindValue.fieldElement().getName()));
}
ClassName annotationClassName = bindValue.annotationName();
@@ -148,13 +147,13 @@
// It is safe to call get() on the Optional<AnnotationMirror> returned by mapKey()
// because a @BindValueIntoMap is required to have one and is checked in
// BindValueMetadata.BindValueElement.create().
- builder.addAnnotation(AnnotationSpec.get(bindValue.mapKey().get()));
+ builder.addAnnotation(XAnnotations.getAnnotationSpec(bindValue.mapKey().get()));
} else if (BindValueMetadata.BIND_VALUE_INTO_SET_ANNOTATIONS.contains(annotationClassName)) {
builder.addAnnotation(IntoSet.class);
} else if (BindValueMetadata.BIND_ELEMENTS_INTO_SET_ANNOTATIONS.contains(annotationClassName)) {
builder.addAnnotation(ElementsIntoSet.class);
}
- bindValue.qualifier().ifPresent(q -> builder.addAnnotation(AnnotationSpec.get(q)));
+ bindValue.qualifier().ifPresent(q -> builder.addAnnotation(XAnnotations.getAnnotationSpec(q)));
return builder.build();
}
}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
index 375ab6c..00a6402 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
@@ -16,9 +16,16 @@
package dagger.hilt.android.processor.internal.bindvalue;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.asField;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XElementKt;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -28,15 +35,10 @@
import dagger.hilt.processor.internal.Processors;
import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtil;
import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.Collection;
import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
/**
* Represents metadata for a test class that has {@code BindValue} fields.
@@ -56,17 +58,22 @@
ImmutableSet.of(
ClassNames.ANDROID_BIND_VALUE_INTO_MAP);
- /** @return the {@code TestRoot} annotated class's name. */
- abstract TypeElement testElement();
+ /**
+ * @return the {@code TestRoot} annotated class's name.
+ */
+ abstract XTypeElement testElement();
/** @return a {@link ImmutableSet} of elements annotated with @BindValue. */
abstract ImmutableSet<BindValueElement> bindValueElements();
- /** @return a new BindValueMetadata instance. */
- static BindValueMetadata create(TypeElement testElement, Collection<Element> bindValueElements) {
+ /**
+ * @return a new BindValueMetadata instance.
+ */
+ static BindValueMetadata create(
+ XTypeElement testElement, Collection<XElement> bindValueElements) {
ImmutableSet.Builder<BindValueElement> elements = ImmutableSet.builder();
- for (Element element : bindValueElements) {
+ for (XElement element : bindValueElements) {
elements.add(BindValueElement.create(element));
}
@@ -75,101 +82,104 @@
@AutoValue
abstract static class BindValueElement {
- abstract VariableElement variableElement();
+ abstract XFieldElement fieldElement();
abstract ClassName annotationName();
- abstract Optional<AnnotationMirror> qualifier();
+ abstract Optional<XAnnotation> qualifier();
- abstract Optional<AnnotationMirror> mapKey();
+ abstract Optional<XAnnotation> mapKey();
- abstract Optional<ExecutableElement> getterElement();
+ abstract Optional<XMethodElement> getterElement();
- static BindValueElement create(Element element) {
- ImmutableList<ClassName> bindValues = BindValueProcessor.getBindValueAnnotations(element);
+ static BindValueElement create(XElement element) {
+ ImmutableList<ClassName> bindValues =
+ BindValueProcessingStep.getBindValueAnnotations(element);
ProcessorErrors.checkState(
bindValues.size() == 1,
element,
"Fields can be annotated with only one of @BindValue, @BindValueIntoMap,"
+ " @BindElementsIntoSet, @BindValueIntoSet. Found: %s",
bindValues.stream().map(m -> "@" + m.simpleName()).collect(toImmutableList()));
- ClassName annotationClassName = bindValues.get(0);
+ ClassName annotationClassName = getOnlyElement(bindValues);
ProcessorErrors.checkState(
- element.getKind() == ElementKind.FIELD,
+ XElementKt.isField(element),
element,
"@%s can only be used with fields. Found: %s",
annotationClassName.simpleName(),
- element);
+ XElements.toStableString(element));
+
+ XFieldElement field = asField(element);
KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- Optional<ExecutableElement> propertyGetter =
- metadataUtil.hasMetadata(element)
- ? metadataUtil.getPropertyGetter(MoreElements.asVariable(element))
+ Optional<XMethodElement> propertyGetter =
+ metadataUtil.hasMetadata(field)
+ ? metadataUtil.getPropertyGetter(field)
: Optional.empty();
if (propertyGetter.isPresent()) {
ProcessorErrors.checkState(
- !propertyGetter.get().getModifiers().contains(Modifier.PRIVATE),
- element,
+ !propertyGetter.get().isPrivate(),
+ field,
"@%s field getter cannot be private. Found: %s",
annotationClassName.simpleName(),
- element);
+ XElements.toStableString(field));
} else {
ProcessorErrors.checkState(
- !element.getModifiers().contains(Modifier.PRIVATE),
- element,
+ !XElements.isPrivate(field),
+ field,
"@%s fields cannot be private. Found: %s",
annotationClassName.simpleName(),
- element);
+ XElements.toStableString(field));
}
ProcessorErrors.checkState(
- !Processors.hasAnnotation(element, ClassNames.INJECT),
- element,
+ !field.hasAnnotation(ClassNames.INJECT),
+ field,
"@%s fields cannot be used with @Inject annotation. Found %s",
annotationClassName.simpleName(),
- element);
+ XElements.toStableString(field));
- ImmutableList<AnnotationMirror> qualifiers = Processors.getQualifierAnnotations(element);
+ ImmutableList<XAnnotation> qualifiers = Processors.getQualifierAnnotations(field);
ProcessorErrors.checkState(
qualifiers.size() <= 1,
- element,
+ field,
"@%s fields cannot have more than one qualifier. Found %s",
annotationClassName.simpleName(),
- qualifiers);
+ qualifiers.stream().map(XAnnotations::toStableString).collect(toImmutableList()));
- ImmutableList<AnnotationMirror> mapKeys = Processors.getMapKeyAnnotations(element);
- Optional<AnnotationMirror> optionalMapKeys;
+ ImmutableList<XAnnotation> mapKeys = Processors.getMapKeyAnnotations(field);
+ Optional<XAnnotation> optionalMapKeys;
if (BIND_VALUE_INTO_MAP_ANNOTATIONS.contains(annotationClassName)) {
ProcessorErrors.checkState(
mapKeys.size() == 1,
- element,
+ field,
"@BindValueIntoMap fields must have exactly one @MapKey. Found %s",
- mapKeys);
+ mapKeys.stream().map(XAnnotations::toStableString).collect(toImmutableList()));
optionalMapKeys = Optional.of(mapKeys.get(0));
} else {
ProcessorErrors.checkState(
mapKeys.isEmpty(),
- element,
+ field,
"@MapKey can only be used on @BindValueIntoMap fields, not @%s fields",
annotationClassName.simpleName());
optionalMapKeys = Optional.empty();
}
- ImmutableList<AnnotationMirror> scopes = Processors.getScopeAnnotations(element);
+ ImmutableList<XAnnotation> scopes = Processors.getScopeAnnotations(field);
ProcessorErrors.checkState(
scopes.isEmpty(),
- element,
+ field,
"@%s fields cannot be scoped. Found %s",
annotationClassName.simpleName(),
- scopes);
+ scopes.stream().map(XAnnotations::toStableString).collect(toImmutableList()));
return new AutoValue_BindValueMetadata_BindValueElement(
- (VariableElement) element,
+ field,
annotationClassName,
qualifiers.isEmpty()
- ? Optional.<AnnotationMirror>empty()
- : Optional.<AnnotationMirror>of(qualifiers.get(0)),
+ ? Optional.<XAnnotation>empty()
+ : Optional.<XAnnotation>of(qualifiers.get(0)),
optionalMapKeys,
propertyGetter);
}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessingStep.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessingStep.java
new file mode 100644
index 0000000..a555212
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessingStep.java
@@ -0,0 +1,103 @@
+/*
+ * 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.android.processor.internal.bindvalue;
+
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.util.Collection;
+import java.util.Map;
+
+/** Provides a test's @BindValue fields to the SINGLETON component. */
+public final class BindValueProcessingStep extends BaseProcessingStep {
+
+ private static final ImmutableSet<ClassName> SUPPORTED_ANNOTATIONS =
+ ImmutableSet.<ClassName>builder()
+ .addAll(BindValueMetadata.BIND_VALUE_ANNOTATIONS)
+ .addAll(BindValueMetadata.BIND_VALUE_INTO_SET_ANNOTATIONS)
+ .addAll(BindValueMetadata.BIND_ELEMENTS_INTO_SET_ANNOTATIONS)
+ .addAll(BindValueMetadata.BIND_VALUE_INTO_MAP_ANNOTATIONS)
+ .build();
+
+ private final ListMultimap<XTypeElement, XElement> testRootMap = ArrayListMultimap.create();
+
+ public BindValueProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return SUPPORTED_ANNOTATIONS;
+ }
+
+ @Override
+ protected void preProcess(XProcessingEnv env, XRoundEnv round) {
+ testRootMap.clear();
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ XElement enclosingElement = element.getEnclosingElement();
+ // Restrict BindValue to the direct test class (e.g. not allowed in a base test class) because
+ // otherwise generated BindValue modules from the base class will not associate with the
+ // correct test class. This would make the modules apply globally which would be a weird
+ // difference since just moving a declaration to the parent would change whether the module is
+ // limited to the test that declares it to global.
+ ProcessorErrors.checkState(
+ isTypeElement(enclosingElement)
+ && asTypeElement(enclosingElement).isClass()
+ && (enclosingElement.hasAnnotation(ClassNames.HILT_ANDROID_TEST)
+ ),
+ enclosingElement,
+ "@%s can only be used within a class annotated with "
+ + "@HiltAndroidTest. Found: %s",
+ annotation.simpleName(),
+ XElements.toStableString(enclosingElement));
+ testRootMap.put(asTypeElement(enclosingElement), element);
+ }
+
+ @Override
+ protected void postProcess(XProcessingEnv env, XRoundEnv round) throws Exception {
+ // Generate a module for each testing class with a @BindValue field.
+ for (Map.Entry<XTypeElement, Collection<XElement>> e : testRootMap.asMap().entrySet()) {
+ BindValueMetadata metadata = BindValueMetadata.create(e.getKey(), e.getValue());
+ new BindValueGenerator(processingEnv(), metadata).generate();
+ }
+ }
+
+ static ImmutableList<ClassName> getBindValueAnnotations(XElement element) {
+ return element.getAllAnnotations().stream()
+ .map(XAnnotation::getClassName)
+ .filter(SUPPORTED_ANNOTATIONS::contains)
+ .collect(toImmutableList());
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java
index 060b077..e8fe727 100644
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java
@@ -18,96 +18,18 @@
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.ArrayListMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Multimap;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeName;
-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 dagger.internal.codegen.extension.DaggerStreams;
-import java.util.Collection;
-import java.util.Map;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Provides a test's @BindValue fields to the SINGLETON component. */
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class BindValueProcessor extends BaseProcessor {
-
- private static final ImmutableSet<ClassName> SUPPORTED_ANNOTATIONS =
- ImmutableSet.<ClassName>builder()
- .addAll(BindValueMetadata.BIND_VALUE_ANNOTATIONS)
- .addAll(BindValueMetadata.BIND_VALUE_INTO_SET_ANNOTATIONS)
- .addAll(BindValueMetadata.BIND_ELEMENTS_INTO_SET_ANNOTATIONS)
- .addAll(BindValueMetadata.BIND_VALUE_INTO_MAP_ANNOTATIONS)
- .build();
-
- private final Multimap<TypeElement, Element> testRootMap = ArrayListMultimap.create();
-
+public final class BindValueProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public ImmutableSet<String> getSupportedAnnotationTypes() {
- return SUPPORTED_ANNOTATIONS.stream()
- .map(TypeName::toString)
- .collect(DaggerStreams.toImmutableSet());
- }
-
- @Override
- protected void preRoundProcess(RoundEnvironment roundEnv) {
- testRootMap.clear();
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- ClassName annotationClassName = ClassName.get(annotation);
- Element enclosingElement = element.getEnclosingElement();
- // Restrict BindValue to the direct test class (e.g. not allowed in a base test class) because
- // otherwise generated BindValue modules from the base class will not associate with the
- // correct test class. This would make the modules apply globally which would be a weird
- // difference since just moving a declaration to the parent would change whether the module is
- // limited to the test that declares it to global.
- ProcessorErrors.checkState(
- enclosingElement.getKind() == ElementKind.CLASS
- && (Processors.hasAnnotation(enclosingElement, ClassNames.HILT_ANDROID_TEST)
- ),
- enclosingElement,
- "@%s can only be used within a class annotated with "
- + "@HiltAndroidTest. Found: %s",
- annotationClassName.simpleName(),
- enclosingElement);
-
- testRootMap.put(MoreElements.asType(enclosingElement), element);
- }
-
- @Override
- public void postRoundProcess(RoundEnvironment roundEnvironment) throws Exception {
- // Generate a module for each testing class with a @BindValue field.
- for (Map.Entry<TypeElement, Collection<Element>> e : testRootMap.asMap().entrySet()) {
- BindValueMetadata metadata = BindValueMetadata.create(e.getKey(), e.getValue());
- new BindValueGenerator(getProcessingEnv(), metadata).generate();
- }
- }
-
- static ImmutableList<ClassName> getBindValueAnnotations(Element element) {
- ImmutableList.Builder<ClassName> builder = ImmutableList.builder();
- for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
- TypeName tn = AnnotationSpec.get(annotation).type;
- if (SUPPORTED_ANNOTATIONS.contains(tn)) {
- builder.add((ClassName) tn); // the cast is checked by .contains()
- }
- }
- return builder.build();
+ protected BaseProcessingStep processingStep() {
+ return new BindValueProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/KspBindValueProcessor.java b/java/dagger/hilt/android/processor/internal/bindvalue/KspBindValueProcessor.java
new file mode 100644
index 0000000..55546b5
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/bindvalue/KspBindValueProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * 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.android.processor.internal.bindvalue;
+
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Provides a test's @BindValue fields to the SINGLETON component. */
+public final class KspBindValueProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspBindValueProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new BindValueProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspBindValueProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment environment) {
+ return new KspBindValueProcessor(environment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
index 681ac79..a4fa94b 100644
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
@@ -29,7 +29,9 @@
srcs = [
"CustomTestApplicationGenerator.java",
"CustomTestApplicationMetadata.java",
+ "CustomTestApplicationProcessingStep.java",
"CustomTestApplicationProcessor.java",
+ "KspCustomTestApplicationProcessor.java",
],
deps = [
"//java/dagger/hilt/processor/internal:base_processor",
@@ -37,13 +39,14 @@
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java
index a9adbb9..5e4314c 100644
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java
@@ -20,6 +20,9 @@
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.VOLATILE;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
@@ -31,7 +34,6 @@
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.Modifier;
/** Generates an Android Application that holds the Singleton component. */
@@ -40,38 +42,37 @@
ParameterSpec.builder(ClassNames.TEST_APPLICATION_COMPONENT_MANAGER, "componentManager")
.build();
- private final ProcessingEnvironment processingEnv;
+ private final XProcessingEnv processingEnv;
private final CustomTestApplicationMetadata metadata;
public CustomTestApplicationGenerator(
- ProcessingEnvironment processingEnv, CustomTestApplicationMetadata metadata) {
+ XProcessingEnv processingEnv, CustomTestApplicationMetadata metadata) {
this.processingEnv = processingEnv;
this.metadata = metadata;
}
public void generate() throws IOException {
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(metadata.appName())
- .addOriginatingElement(metadata.element())
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .superclass(metadata.baseAppName())
- .addSuperinterface(
- ParameterizedTypeName.get(ClassNames.GENERATED_COMPONENT_MANAGER, TypeName.OBJECT))
- .addSuperinterface(ClassNames.TEST_APPLICATION_COMPONENT_MANAGER_HOLDER)
- .addField(
- FieldSpec.builder(ClassName.OBJECT, "componentManagerLock", PRIVATE, FINAL)
- .initializer("new $T()", ClassName.OBJECT)
- .build())
- .addField(getComponentManagerField())
- .addMethod(getComponentManagerMethod())
- .addMethod(getComponentMethod());
+ TypeSpec.Builder generator = TypeSpec.classBuilder(metadata.appName());
+ JavaPoetExtKt.addOriginatingElement(generator, metadata.element())
+ .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ .superclass(metadata.baseAppName())
+ .addSuperinterface(
+ ParameterizedTypeName.get(ClassNames.GENERATED_COMPONENT_MANAGER, TypeName.OBJECT))
+ .addSuperinterface(ClassNames.TEST_APPLICATION_COMPONENT_MANAGER_HOLDER)
+ .addField(
+ FieldSpec.builder(ClassName.OBJECT, "componentManagerLock", PRIVATE, FINAL)
+ .initializer("new $T()", ClassName.OBJECT)
+ .build())
+ .addField(getComponentManagerField())
+ .addMethod(getComponentManagerMethod())
+ .addMethod(getComponentMethod());
Processors.addGeneratedAnnotation(
generator, processingEnv, CustomTestApplicationProcessor.class);
- JavaFile.builder(metadata.appName().packageName(), generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
+ JavaFile javaFile =
+ JavaFile.builder(metadata.appName().packageName(), generator.build()).build();
+ processingEnv.getFiler().write(javaFile, Mode.Isolating);
}
// Initialize this in attachBaseContext to not pull it into the main dex.
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java
index de8e3f7..e9e9820 100644
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java
@@ -18,8 +18,11 @@
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XElementKt;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -27,19 +30,13 @@
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.Processors;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
+import dagger.internal.codegen.xprocessing.XElements;
/** Stores the metadata for a custom base test application. */
@AutoValue
abstract class CustomTestApplicationMetadata {
/** Returns the annotated element. */
- abstract TypeElement element();
+ abstract XTypeElement element();
/** Returns the name of the base application. */
abstract ClassName baseAppName();
@@ -47,49 +44,48 @@
/** Returns the name of the generated application */
ClassName appName() {
return Processors.append(
- Processors.getEnclosedClassName(ClassName.get(element())), "_Application");
+ Processors.getEnclosedClassName(element().getClassName()), "_Application");
}
- static CustomTestApplicationMetadata of(Element element, Elements elements) {
+ static CustomTestApplicationMetadata of(XElement element) {
Preconditions.checkState(
- Processors.hasAnnotation(element, ClassNames.CUSTOM_TEST_APPLICATION),
+ element.hasAnnotation(ClassNames.CUSTOM_TEST_APPLICATION),
"The given element, %s, is not annotated with @%s.",
- element,
+ XElements.toStableString(element),
ClassNames.CUSTOM_TEST_APPLICATION.simpleName());
ProcessorErrors.checkState(
- MoreElements.isType(element),
+ XElementKt.isTypeElement(element),
element,
"@%s should only be used on classes or interfaces but found: %s",
ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
- element);
+ XElements.toStableString(element));
- TypeElement baseAppElement = getBaseElement(element, elements);
+ XTypeElement baseAppElement = getBaseElement(element);
return new AutoValue_CustomTestApplicationMetadata(
- MoreElements.asType(element), ClassName.get(baseAppElement));
+ XElements.asTypeElement(element), baseAppElement.getClassName());
}
- private static TypeElement getBaseElement(Element element, Elements elements) {
- TypeElement baseElement =
- Processors.getAnnotationClassValue(
- elements,
- Processors.getAnnotationMirror(element, ClassNames.CUSTOM_TEST_APPLICATION),
- "value");
+ private static XTypeElement getBaseElement(XElement element) {
+ XTypeElement baseElement =
+ element.getAnnotation(ClassNames.CUSTOM_TEST_APPLICATION)
+ .getAsType("value")
+ .getTypeElement();
- TypeElement baseSuperclassElement = baseElement;
- while (!baseSuperclassElement.getSuperclass().getKind().equals(TypeKind.NONE)) {
+ XTypeElement baseSuperclassElement = baseElement;
+ while (baseSuperclassElement.getSuperClass() != null) {
ProcessorErrors.checkState(
- !Processors.hasAnnotation(baseSuperclassElement, ClassNames.HILT_ANDROID_APP),
+ !baseSuperclassElement.hasAnnotation(ClassNames.HILT_ANDROID_APP),
element,
"@%s value cannot be annotated with @%s. Found: %s",
ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
ClassNames.HILT_ANDROID_APP.simpleName(),
- baseSuperclassElement);
+ baseSuperclassElement.getClassName());
- ImmutableList<VariableElement> injectFields =
- ElementFilter.fieldsIn(baseSuperclassElement.getEnclosedElements()).stream()
- .filter(field -> Processors.hasAnnotation(field, ClassNames.INJECT))
+ ImmutableList<XFieldElement> injectFields =
+ baseSuperclassElement.getDeclaredFields().stream()
+ .filter(field -> field.hasAnnotation(ClassNames.INJECT))
.collect(toImmutableList());
ProcessorErrors.checkState(
injectFields.isEmpty(),
@@ -97,12 +93,12 @@
"@%s does not support application classes (or super classes) with @Inject fields. Found "
+ "%s with @Inject fields %s.",
ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
- baseSuperclassElement,
- injectFields);
+ baseSuperclassElement.getClassName(),
+ injectFields.stream().map(XElements::toStableString).collect(toImmutableList()));
- ImmutableList<ExecutableElement> injectMethods =
- ElementFilter.methodsIn(baseSuperclassElement.getEnclosedElements()).stream()
- .filter(method -> Processors.hasAnnotation(method, ClassNames.INJECT))
+ ImmutableList<XExecutableElement> injectMethods =
+ baseSuperclassElement.getDeclaredMethods().stream()
+ .filter(method -> method.hasAnnotation(ClassNames.INJECT))
.collect(toImmutableList());
ProcessorErrors.checkState(
injectMethods.isEmpty(),
@@ -110,12 +106,12 @@
"@%s does not support application classes (or super classes) with @Inject methods. Found "
+ "%s with @Inject methods %s.",
ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
- baseSuperclassElement,
- injectMethods);
+ baseSuperclassElement.getClassName(),
+ injectMethods.stream().map(XElements::toStableString).collect(toImmutableList()));
- ImmutableList<ExecutableElement> injectConstructors =
- ElementFilter.constructorsIn(baseSuperclassElement.getEnclosedElements()).stream()
- .filter(method -> Processors.hasAnnotation(method, ClassNames.INJECT))
+ ImmutableList<XExecutableElement> injectConstructors =
+ baseSuperclassElement.getConstructors().stream()
+ .filter(method -> method.hasAnnotation(ClassNames.INJECT))
.collect(toImmutableList());
ProcessorErrors.checkState(
injectConstructors.isEmpty(),
@@ -123,10 +119,10 @@
"@%s does not support application classes (or super classes) with @Inject constructors. "
+ "Found %s with @Inject constructors %s.",
ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
- baseSuperclassElement,
- injectConstructors);
+ baseSuperclassElement.getClassName().canonicalName(),
+ injectConstructors.stream().map(XElements::toStableString).collect(toImmutableList()));
- baseSuperclassElement = MoreTypes.asTypeElement(baseSuperclassElement.getSuperclass());
+ baseSuperclassElement = baseSuperclassElement.getSuperClass().getTypeElement();
}
// We check this last because if the base type is a @HiltAndroidApp we'd accidentally fail
@@ -137,7 +133,7 @@
"@%s value should be an instance of %s. Found: %s",
ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
ClassNames.APPLICATION,
- baseElement);
+ baseElement.getClassName());
return baseElement;
}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessingStep.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessingStep.java
new file mode 100644
index 0000000..572664d
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessingStep.java
@@ -0,0 +1,43 @@
+/*
+ * 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.android.processor.internal.customtestapplication;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+
+/** Processes usages of {@link dagger.hilt.android.testing.CustomTestApplication}. */
+public final class CustomTestApplicationProcessingStep extends BaseProcessingStep {
+
+ public CustomTestApplicationProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.CUSTOM_TEST_APPLICATION);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) throws Exception {
+ CustomTestApplicationMetadata metadata = CustomTestApplicationMetadata.of(element);
+ new CustomTestApplicationGenerator(processingEnv(), metadata).generate();
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java
index fd1a6c8..e65d2b9 100644
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java
@@ -19,28 +19,16 @@
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 dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processes usages of {@link dagger.hilt.android.testing.CustomTestApplication}. */
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class CustomTestApplicationProcessor extends BaseProcessor {
-
+public final class CustomTestApplicationProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public ImmutableSet<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.CUSTOM_TEST_APPLICATION.toString());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- CustomTestApplicationMetadata metadata =
- CustomTestApplicationMetadata.of(element, getElementUtils());
- new CustomTestApplicationGenerator(getProcessingEnv(), metadata).generate();
+ protected CustomTestApplicationProcessingStep processingStep() {
+ return new CustomTestApplicationProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/KspCustomTestApplicationProcessor.java b/java/dagger/hilt/android/processor/internal/customtestapplication/KspCustomTestApplicationProcessor.java
new file mode 100644
index 0000000..23a6e79
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/customtestapplication/KspCustomTestApplicationProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.android.processor.internal.customtestapplication;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Processes usages of {@link dagger.hilt.android.testing.CustomTestApplication}. */
+public final class KspCustomTestApplicationProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspCustomTestApplicationProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected CustomTestApplicationProcessingStep processingStep() {
+ return new CustomTestApplicationProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspCustomTestApplicationProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspCustomTestApplicationProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
index 353729d..f3686a1 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
@@ -28,8 +28,10 @@
kt_jvm_library(
name = "processor_lib",
srcs = [
+ "KspViewModelProcessor.kt",
"ViewModelMetadata.kt",
"ViewModelModuleGenerator.kt",
+ "ViewModelProcessingStep.kt",
"ViewModelProcessor.kt",
],
deps = [
@@ -38,11 +40,12 @@
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -59,8 +62,7 @@
deps = [
"//:spi",
"//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/processor/internal:processors",
- "//third_party/java/auto:common",
+ "//java/dagger/hilt/processor/internal:dagger_models",
"//third_party/java/auto:service",
"//third_party/java/guava/graph",
"//third_party/java/javapoet",
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/KspViewModelProcessor.kt b/java/dagger/hilt/android/processor/internal/viewmodel/KspViewModelProcessor.kt
new file mode 100644
index 0000000..793dd9b
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/KspViewModelProcessor.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.android.processor.internal.viewmodel
+
+import androidx.room.compiler.processing.ExperimentalProcessingApi
+import com.google.auto.service.AutoService
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+import dagger.hilt.processor.internal.BaseProcessingStep
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor
+
+/** Annotation processor for @ViewModelInject. */
+class KspViewModelProcessor(symbolProcessorEnvironment: SymbolProcessorEnvironment?) :
+ KspBaseProcessingStepProcessor(symbolProcessorEnvironment) {
+ @OptIn(ExperimentalProcessingApi::class)
+ override fun processingStep(): BaseProcessingStep = ViewModelProcessingStep(xProcessingEnv)
+
+ /** Provides the [KspViewModelProcessor]. */
+ @AutoService(SymbolProcessorProvider::class)
+ class Provider : SymbolProcessorProvider {
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return KspViewModelProcessor(environment)
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
index 789fbfe..49b35a7 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
@@ -16,76 +16,69 @@
package dagger.hilt.android.processor.internal.viewmodel
-import com.google.auto.common.MoreElements
+import androidx.room.compiler.processing.ExperimentalProcessingApi
+import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.XTypeElement
import com.squareup.javapoet.ClassName
import dagger.hilt.android.processor.internal.AndroidClassNames
import dagger.hilt.processor.internal.ClassNames
import dagger.hilt.processor.internal.ProcessorErrors
import dagger.hilt.processor.internal.Processors
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.Modifier
-import javax.lang.model.element.NestingKind
-import javax.lang.model.element.TypeElement
-import javax.lang.model.util.ElementFilter
+import dagger.internal.codegen.xprocessing.XAnnotations
+import dagger.internal.codegen.xprocessing.XTypes
-/**
- * Data class that represents a Hilt injected ViewModel
- */
-internal class ViewModelMetadata private constructor(
- val typeElement: TypeElement
-) {
- val className = ClassName.get(typeElement)
+/** Data class that represents a Hilt injected ViewModel */
+@OptIn(ExperimentalProcessingApi::class)
+internal class ViewModelMetadata private constructor(val typeElement: XTypeElement) {
+ val className = typeElement.className
- val modulesClassName = ClassName.get(
- MoreElements.getPackage(typeElement).qualifiedName.toString(),
- "${className.simpleNames().joinToString("_")}_HiltModules"
- )
+ val modulesClassName =
+ ClassName.get(
+ typeElement.packageName,
+ "${className.simpleNames().joinToString("_")}_HiltModules"
+ )
companion object {
internal fun create(
- processingEnv: ProcessingEnvironment,
- typeElement: TypeElement,
+ processingEnv: XProcessingEnv,
+ typeElement: XTypeElement,
): ViewModelMetadata? {
- val types = processingEnv.typeUtils
- val elements = processingEnv.elementUtils
-
ProcessorErrors.checkState(
- types.isSubtype(
- typeElement.asType(),
- elements.getTypeElement(AndroidClassNames.VIEW_MODEL.toString()).asType()
- ),
+ XTypes.isSubtype(typeElement.type, processingEnv.requireType(AndroidClassNames.VIEW_MODEL)),
typeElement,
"@HiltViewModel is only supported on types that subclass %s.",
AndroidClassNames.VIEW_MODEL
)
- ElementFilter.constructorsIn(typeElement.enclosedElements).filter { constructor ->
- ProcessorErrors.checkState(
- !Processors.hasAnnotation(constructor, ClassNames.ASSISTED_INJECT),
- constructor,
- "ViewModel constructor should be annotated with @Inject instead of @AssistedInject."
- )
- Processors.hasAnnotation(constructor, ClassNames.INJECT)
- }.let { injectConstructors ->
- ProcessorErrors.checkState(
- injectConstructors.size == 1,
- typeElement,
- "@HiltViewModel annotated class should contain exactly one @Inject " +
- "annotated constructor."
- )
-
- injectConstructors.forEach { constructor ->
+ typeElement
+ .getConstructors()
+ .filter { constructor ->
ProcessorErrors.checkState(
- !constructor.modifiers.contains(Modifier.PRIVATE),
+ !constructor.hasAnnotation(ClassNames.ASSISTED_INJECT),
constructor,
- "@Inject annotated constructors must not be private."
+ "ViewModel constructor should be annotated with @Inject instead of @AssistedInject."
)
+ constructor.hasAnnotation(ClassNames.INJECT)
}
- }
+ .let { injectConstructors ->
+ ProcessorErrors.checkState(
+ injectConstructors.size == 1,
+ typeElement,
+ "@HiltViewModel annotated class should contain exactly one @Inject " +
+ "annotated constructor."
+ )
+
+ injectConstructors.forEach { injectConstructor ->
+ ProcessorErrors.checkState(
+ !injectConstructor.isPrivate(),
+ injectConstructor,
+ "@Inject annotated constructors must not be private."
+ )
+ }
+ }
ProcessorErrors.checkState(
- typeElement.nestingKind != NestingKind.MEMBER ||
- typeElement.modifiers.contains(Modifier.STATIC),
+ !typeElement.isNested() || typeElement.isStatic(),
typeElement,
"@HiltViewModel may only be used on inner classes if they are static."
)
@@ -95,13 +88,11 @@
scopeAnnotations.isEmpty(),
typeElement,
"@HiltViewModel classes should not be scoped. Found: %s",
- scopeAnnotations.joinToString()
+ scopeAnnotations.joinToString { XAnnotations.toStableString(it) }
)
}
- return ViewModelMetadata(
- typeElement
- )
+ return ViewModelMetadata(typeElement)
}
}
}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelModuleGenerator.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelModuleGenerator.kt
index 1bc2e93..29f8c3c 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelModuleGenerator.kt
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelModuleGenerator.kt
@@ -16,7 +16,9 @@
package dagger.hilt.android.processor.internal.viewmodel
-import com.google.auto.common.GeneratedAnnotationSpecs
+import androidx.room.compiler.processing.ExperimentalProcessingApi
+import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.addOriginatingElement
import com.squareup.javapoet.AnnotationSpec
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.JavaFile
@@ -24,10 +26,8 @@
import com.squareup.javapoet.TypeSpec
import dagger.hilt.android.processor.internal.AndroidClassNames
import dagger.hilt.processor.internal.ClassNames
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.SourceVersion
+import dagger.hilt.processor.internal.Processors
import javax.lang.model.element.Modifier
-import javax.lang.model.util.Elements
/**
* Source generator to support Hilt injection of ViewModels.
@@ -57,49 +57,47 @@
* }
* ```
*/
+@OptIn(ExperimentalProcessingApi::class)
internal class ViewModelModuleGenerator(
- private val processingEnv: ProcessingEnvironment,
+ private val processingEnv: XProcessingEnv,
private val injectedViewModel: ViewModelMetadata
) {
fun generate() {
- val modulesTypeSpec = TypeSpec.classBuilder(injectedViewModel.modulesClassName)
- .addOriginatingElement(injectedViewModel.typeElement)
- .addGeneratedAnnotation(processingEnv.elementUtils, processingEnv.sourceVersion)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
- .addMember(
- "topLevelClass",
- "$T.class",
- injectedViewModel.className.topLevelClassName()
+ val modulesTypeSpec =
+ TypeSpec.classBuilder(injectedViewModel.modulesClassName)
+ .apply {
+ addOriginatingElement(injectedViewModel.typeElement)
+ Processors.addGeneratedAnnotation(this, processingEnv, ViewModelProcessor::class.java)
+ addAnnotation(
+ AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
+ .addMember(
+ "topLevelClass",
+ "$T.class",
+ injectedViewModel.className.topLevelClassName()
+ )
+ .build()
)
- .build()
- )
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .addType(getBindsModuleTypeSpec())
- .addType(getKeyModuleTypeSpec())
- .addMethod(
- MethodSpec.constructorBuilder()
- .addModifiers(Modifier.PRIVATE)
- .build()
- )
- .build()
- JavaFile.builder(injectedViewModel.modulesClassName.packageName(), modulesTypeSpec)
- .build()
- .writeTo(processingEnv.filer)
+ addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+ addType(getBindsModuleTypeSpec())
+ addType(getKeyModuleTypeSpec())
+ addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build())
+ }
+ .build()
+
+ processingEnv.filer.write(
+ JavaFile.builder(injectedViewModel.modulesClassName.packageName(), modulesTypeSpec).build()
+ )
}
- private fun getBindsModuleTypeSpec() = createModuleTypeSpec(
- className = "BindsModule",
- component = AndroidClassNames.VIEW_MODEL_COMPONENT
- )
- .addModifiers(Modifier.ABSTRACT)
- .addMethod(
- MethodSpec.constructorBuilder()
- .addModifiers(Modifier.PRIVATE)
- .build()
- )
- .addMethod(getViewModelBindsMethod())
- .build()
+ private fun getBindsModuleTypeSpec() =
+ createModuleTypeSpec(
+ className = "BindsModule",
+ component = AndroidClassNames.VIEW_MODEL_COMPONENT
+ )
+ .addModifiers(Modifier.ABSTRACT)
+ .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build())
+ .addMethod(getViewModelBindsMethod())
+ .build()
private fun getViewModelBindsMethod() =
MethodSpec.methodBuilder("binds")
@@ -116,18 +114,15 @@
.addParameter(injectedViewModel.className, "vm")
.build()
- private fun getKeyModuleTypeSpec() = createModuleTypeSpec(
- className = "KeyModule",
- component = AndroidClassNames.ACTIVITY_RETAINED_COMPONENT
- )
- .addModifiers(Modifier.FINAL)
- .addMethod(
- MethodSpec.constructorBuilder()
- .addModifiers(Modifier.PRIVATE)
- .build()
- )
- .addMethod(getViewModelKeyProvidesMethod())
- .build()
+ private fun getKeyModuleTypeSpec() =
+ createModuleTypeSpec(
+ className = "KeyModule",
+ component = AndroidClassNames.ACTIVITY_RETAINED_COMPONENT
+ )
+ .addModifiers(Modifier.FINAL)
+ .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build())
+ .addMethod(getViewModelKeyProvidesMethod())
+ .build()
private fun getViewModelKeyProvidesMethod() =
MethodSpec.methodBuilder("provide")
@@ -157,18 +152,5 @@
const val N = "\$N"
const val S = "\$S"
const val W = "\$W"
-
- private fun TypeSpec.Builder.addGeneratedAnnotation(
- elements: Elements,
- sourceVersion: SourceVersion
- ) = apply {
- GeneratedAnnotationSpecs.generatedAnnotationSpec(
- elements,
- sourceVersion,
- ViewModelProcessor::class.java
- ).ifPresent { generatedAnnotation ->
- addAnnotation(generatedAnnotation)
- }
- }
}
}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessingStep.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessingStep.kt
new file mode 100644
index 0000000..69f7ac2
--- /dev/null
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessingStep.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.android.processor.internal.viewmodel
+
+import androidx.room.compiler.processing.ExperimentalProcessingApi
+import androidx.room.compiler.processing.XElement
+import androidx.room.compiler.processing.XProcessingEnv
+import com.google.common.collect.ImmutableSet
+import com.squareup.javapoet.ClassName
+import dagger.hilt.android.processor.internal.AndroidClassNames
+import dagger.hilt.processor.internal.BaseProcessingStep
+import dagger.internal.codegen.xprocessing.XElements
+
+@OptIn(ExperimentalProcessingApi::class)
+/** Annotation processor for @ViewModelInject. */
+class ViewModelProcessingStep(env: XProcessingEnv) : BaseProcessingStep(env) {
+ override fun annotationClassNames() = ImmutableSet.of(AndroidClassNames.HILT_VIEW_MODEL)
+
+ override fun processEach(annotation: ClassName, element: XElement) {
+ val typeElement = XElements.asTypeElement(element)
+ ViewModelMetadata.create(
+ processingEnv(),
+ typeElement,
+ )
+ ?.let { viewModelMetadata ->
+ ViewModelModuleGenerator(processingEnv(), viewModelMetadata).generate()
+ }
+ }
+}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessor.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessor.kt
index 97ebe52..fd63e6e 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessor.kt
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessor.kt
@@ -16,49 +16,18 @@
package dagger.hilt.android.processor.internal.viewmodel
-import com.google.auto.common.MoreElements
+import androidx.room.compiler.processing.ExperimentalProcessingApi
import com.google.auto.service.AutoService
-import dagger.hilt.android.processor.internal.AndroidClassNames
-import dagger.hilt.processor.internal.BaseProcessor
+import dagger.hilt.processor.internal.BaseProcessingStep
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor
import javax.annotation.processing.Processor
-import javax.annotation.processing.RoundEnvironment
-import javax.lang.model.SourceVersion
-import javax.lang.model.element.Element
-import javax.lang.model.element.TypeElement
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor
import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType
-/**
- * Annotation processor for @ViewModelInject.
- */
+/** Annotation processor for @ViewModelInject. */
@AutoService(Processor::class)
@IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.ISOLATING)
-class ViewModelProcessor : BaseProcessor() {
-
- private val parsedElements = mutableSetOf<TypeElement>()
-
- override fun getSupportedAnnotationTypes() = setOf(
- AndroidClassNames.HILT_VIEW_MODEL.toString()
- )
-
- override fun getSupportedSourceVersion() = SourceVersion.latest()
-
- override fun processEach(annotation: TypeElement, element: Element) {
- val typeElement = MoreElements.asType(element)
- if (parsedElements.add(typeElement)) {
- ViewModelMetadata.create(
- processingEnv,
- typeElement,
- )?.let { viewModelMetadata ->
- ViewModelModuleGenerator(
- processingEnv,
- viewModelMetadata
- ).generate()
- }
- }
- }
-
- override fun postRoundProcess(roundEnv: RoundEnvironment?) {
- parsedElements.clear()
- }
+class ViewModelProcessor : JavacBaseProcessingStepProcessor() {
+ @OptIn(ExperimentalProcessingApi::class)
+ override fun processingStep(): BaseProcessingStep = ViewModelProcessingStep(xProcessingEnv)
}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
index a8e57dc..d5c3666 100644
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
+++ b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
@@ -16,28 +16,25 @@
package dagger.hilt.android.processor.internal.viewmodel
-import com.google.auto.common.MoreTypes.asElement
import com.google.auto.service.AutoService
import com.google.common.graph.EndpointPair
import com.google.common.graph.ImmutableNetwork
-import com.squareup.javapoet.ClassName
import dagger.hilt.android.processor.internal.AndroidClassNames
-import dagger.hilt.processor.internal.Processors.hasAnnotation
-import dagger.model.Binding
-import dagger.model.BindingGraph
-import dagger.model.BindingGraph.Edge
-import dagger.model.BindingGraph.Node
-import dagger.model.BindingKind
-import dagger.spi.BindingGraphPlugin
-import dagger.spi.DiagnosticReporter
+import dagger.hilt.processor.internal.asElement
+import dagger.hilt.processor.internal.getQualifiedName
+import dagger.hilt.processor.internal.hasAnnotation
+import dagger.spi.model.Binding
+import dagger.spi.model.BindingGraph
+import dagger.spi.model.BindingGraph.Edge
+import dagger.spi.model.BindingGraph.Node
+import dagger.spi.model.BindingGraphPlugin
+import dagger.spi.model.BindingKind
+import dagger.spi.model.DiagnosticReporter
import javax.tools.Diagnostic.Kind
-/**
- * Plugin to validate users do not inject @HiltViewModel classes.
- */
+/** Plugin to validate users do not inject @HiltViewModel classes. */
@AutoService(BindingGraphPlugin::class)
class ViewModelValidationPlugin : BindingGraphPlugin {
-
override fun visitGraph(bindingGraph: BindingGraph, diagnosticReporter: DiagnosticReporter) {
if (bindingGraph.rootComponentNode().isSubcomponent()) {
// This check does not work with partial graphs since it needs to take into account the source
@@ -50,9 +47,9 @@
val pair: EndpointPair<Node> = network.incidentNodes(edge)
val target: Node = pair.target()
val source: Node = pair.source()
- if (target is Binding &&
- isHiltViewModelBinding(target) &&
- !isInternalHiltViewModelUsage(source)
+ if (
+ target is Binding &&
+ isHiltViewModelBinding(target) && !isInternalHiltViewModelUsage(source)
) {
diagnosticReporter.reportDependency(
Kind.ERROR,
@@ -70,7 +67,7 @@
// Make sure this is from an @Inject constructor rather than an overridden binding like an
// @Provides and that the class is annotated with @HiltViewModel.
return target.kind() == BindingKind.INJECTION &&
- hasAnnotation(asElement(target.key().type()), AndroidClassNames.HILT_VIEW_MODEL)
+ target.key().type().asElement().hasAnnotation(AndroidClassNames.HILT_VIEW_MODEL)
}
private fun isInternalHiltViewModelUsage(source: Node): Boolean {
@@ -85,8 +82,8 @@
// TODO(erichang): Should we check for even more things?
return source is Binding &&
source.key().qualifier().isPresent() &&
- ClassName.get(source.key().qualifier().get().getAnnotationType()) ==
- AndroidClassNames.HILT_VIEW_MODEL_MAP_QUALIFIER &&
+ source.key().qualifier().get().getQualifiedName() ==
+ AndroidClassNames.HILT_VIEW_MODEL_MAP_QUALIFIER.canonicalName() &&
source.key().multibindingContributionIdentifier().isPresent()
}
}
diff --git a/java/dagger/hilt/android/testing/compile/BUILD b/java/dagger/hilt/android/testing/compile/BUILD
index 4f49ca5..7d41e0d 100644
--- a/java/dagger/hilt/android/testing/compile/BUILD
+++ b/java/dagger/hilt/android/testing/compile/BUILD
@@ -20,11 +20,14 @@
name = "compile",
testonly = 1,
srcs = [
+ "HiltCompilerProcessors.java",
"HiltCompilerTests.java",
],
deps = [
"//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
"//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib",
+ "//java/dagger/hilt/processor/internal:base_processor",
+ "//java/dagger/hilt/processor/internal:hilt_processing_env_configs",
"//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
"//java/dagger/hilt/processor/internal/aliasof:processor_lib",
"//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
@@ -35,10 +38,15 @@
"//java/dagger/hilt/processor/internal/root:root_processor_lib",
"//java/dagger/hilt/processor/internal/uninstallmodules:processor_lib",
"//java/dagger/internal/codegen:processor",
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//java/dagger/testing/compile",
+ "//third_party/java/auto:value",
"//third_party/java/compile_testing",
+ "//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/junit",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
diff --git a/java/dagger/hilt/android/testing/compile/HiltCompilerProcessors.java b/java/dagger/hilt/android/testing/compile/HiltCompilerProcessors.java
new file mode 100644
index 0000000..cb00f52
--- /dev/null
+++ b/java/dagger/hilt/android/testing/compile/HiltCompilerProcessors.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.android.testing.compile;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+import java.util.function.Function;
+
+/**
+ * A Javac and KSP processor to be used with the {@link HiltCompilerTests.hiltCompiler} to allow
+ * running custom processing steps during compilation tests.
+ */
+final class HiltCompilerProcessors {
+ /** A JavacBasicAnnotationProcessor that contains a single BaseProcessingStep. */
+ static final class JavacProcessor extends JavacBaseProcessingStepProcessor {
+ private final Function<XProcessingEnv, BaseProcessingStep> processingStep;
+
+ JavacProcessor(Function<XProcessingEnv, BaseProcessingStep> processingStep) {
+ this.processingStep = processingStep;
+ }
+
+ @Override
+ public BaseProcessingStep processingStep() {
+ return processingStep.apply(getXProcessingEnv());
+ }
+ }
+
+ /** A KSP processor that runs the given processing steps. */
+ static final class KspProcessor extends KspBaseProcessingStepProcessor {
+ private final Function<XProcessingEnv, BaseProcessingStep> processingStep;
+
+ private KspProcessor(
+ SymbolProcessorEnvironment symbolProcessorEnvironment,
+ Function<XProcessingEnv, BaseProcessingStep> processingStep) {
+ super(symbolProcessorEnvironment);
+ this.processingStep = processingStep;
+ }
+
+ @Override
+ public BaseProcessingStep processingStep() {
+ return processingStep.apply(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspComponentProcessor}. */
+ static final class Provider implements SymbolProcessorProvider {
+ private final Function<XProcessingEnv, BaseProcessingStep> processingStep;
+
+ Provider(Function<XProcessingEnv, BaseProcessingStep> processingStep) {
+ this.processingStep = processingStep;
+ }
+
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspProcessor(symbolProcessorEnvironment, processingStep);
+ }
+ }
+ }
+
+ private HiltCompilerProcessors() {}
+}
diff --git a/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
index 4b8e194..8f2abd3 100644
--- a/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
+++ b/java/dagger/hilt/android/testing/compile/HiltCompilerTests.java
@@ -16,38 +16,96 @@
package dagger.hilt.android.testing.compile;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static java.util.stream.Collectors.toMap;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.util.CompilationResultSubject;
+import androidx.room.compiler.processing.util.ProcessorTestExtKt;
import androidx.room.compiler.processing.util.Source;
import androidx.room.compiler.processing.util.compiler.TestCompilationArguments;
import androidx.room.compiler.processing.util.compiler.TestCompilationResult;
import androidx.room.compiler.processing.util.compiler.TestKotlinCompilerKt;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
import com.google.testing.compile.Compiler;
import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor;
+import dagger.hilt.android.processor.internal.androidentrypoint.KspAndroidEntryPointProcessor;
import dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor;
+import dagger.hilt.android.processor.internal.customtestapplication.KspCustomTestApplicationProcessor;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.HiltProcessingEnvConfigs;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor;
+import dagger.hilt.processor.internal.aggregateddeps.KspAggregatedDepsProcessor;
import dagger.hilt.processor.internal.aliasof.AliasOfProcessor;
+import dagger.hilt.processor.internal.aliasof.KspAliasOfProcessor;
import dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor;
+import dagger.hilt.processor.internal.definecomponent.KspDefineComponentProcessor;
import dagger.hilt.processor.internal.earlyentrypoint.EarlyEntryPointProcessor;
+import dagger.hilt.processor.internal.earlyentrypoint.KspEarlyEntryPointProcessor;
import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor;
+import dagger.hilt.processor.internal.generatesrootinput.KspGeneratesRootInputProcessor;
+import dagger.hilt.processor.internal.originatingelement.KspOriginatingElementProcessor;
import dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor;
import dagger.hilt.processor.internal.root.ComponentTreeDepsProcessor;
+import dagger.hilt.processor.internal.root.KspComponentTreeDepsProcessor;
+import dagger.hilt.processor.internal.root.KspRootProcessor;
import dagger.hilt.processor.internal.root.RootProcessor;
+import dagger.hilt.processor.internal.uninstallmodules.KspUninstallModulesProcessor;
import dagger.hilt.processor.internal.uninstallmodules.UninstallModulesProcessor;
import dagger.internal.codegen.ComponentProcessor;
+import dagger.internal.codegen.KspComponentProcessor;
import dagger.testing.compile.CompilerTests;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
+import java.util.function.Function;
import javax.annotation.processing.Processor;
import org.junit.rules.TemporaryFolder;
/** {@link Compiler} instances for testing Android Hilt. */
public final class HiltCompilerTests {
+ /** Returns the {@link XProcessingEnv.Backend} for the given {@link CompilationResultSubject}. */
+ public static XProcessingEnv.Backend backend(CompilationResultSubject subject) {
+ return CompilerTests.backend(subject);
+ }
+
+ /** Returns a {@link Source.KotlinSource} with the given file name and content. */
+ public static Source.KotlinSource kotlinSource(
+ String fileName, ImmutableCollection<String> srcLines) {
+ return CompilerTests.kotlinSource(fileName, srcLines);
+ }
+
+ /** Returns a {@link Source.KotlinSource} with the given file name and content. */
+ public static Source.KotlinSource kotlinSource(String fileName, String... srcLines) {
+ return CompilerTests.kotlinSource(fileName, srcLines);
+ }
+
+ /** Returns a {@link Source.JavaSource} with the given file name and content. */
+ public static Source.JavaSource javaSource(
+ String fileName, ImmutableCollection<String> srcLines) {
+ return CompilerTests.javaSource(fileName, srcLines);
+ }
+
+ /** Returns a {@link Source.JavaSource} with the given file name and content. */
+ public static Source.JavaSource javaSource(String fileName, String... srcLines) {
+ return CompilerTests.javaSource(fileName, srcLines);
+ }
+
+ /** Returns a {@link Compiler} instance with the given sources. */
+ public static HiltCompiler hiltCompiler(Source... sources) {
+ return hiltCompiler(ImmutableList.copyOf(sources));
+ }
+
+ /** Returns a {@link Compiler} instance with the given sources. */
+ public static HiltCompiler hiltCompiler(ImmutableCollection<Source> sources) {
+ return HiltCompiler.builder().sources(sources).build();
+ }
public static Compiler compiler(Processor... extraProcessors) {
return compiler(Arrays.asList(extraProcessors));
@@ -68,7 +126,8 @@
List<Source> sources,
TemporaryFolder tempFolder,
Consumer<TestCompilationResult> onCompilationResult) {
- compileWithKapt(sources, ImmutableMap.of(), tempFolder, onCompilationResult);
+ compileWithKapt(
+ sources, ImmutableMap.of(), ImmutableList.of(), tempFolder, onCompilationResult);
}
public static void compileWithKapt(
@@ -76,17 +135,40 @@
Map<String, String> processorOptions,
TemporaryFolder tempFolder,
Consumer<TestCompilationResult> onCompilationResult) {
- TestCompilationResult result = TestKotlinCompilerKt.compile(
- tempFolder.getRoot(),
- new TestCompilationArguments(
- sources,
- /*classpath=*/ ImmutableList.of(CompilerTests.compilerDepsJar()),
- /*inheritClasspath=*/ false,
- /*javacArguments=*/ ImmutableList.of(),
- /*kotlincArguments=*/ ImmutableList.of(),
- /*kaptProcessors=*/ defaultProcessors(),
- /*symbolProcessorProviders=*/ ImmutableList.of(),
- /*processorOptions=*/ processorOptions));
+ compileWithKapt(
+ sources, processorOptions, ImmutableList.of(), tempFolder, onCompilationResult);
+ }
+
+ public static void compileWithKapt(
+ List<Source> sources,
+ List<Processor> additionalProcessors,
+ TemporaryFolder tempFolder,
+ Consumer<TestCompilationResult> onCompilationResult) {
+ compileWithKapt(
+ sources, ImmutableMap.of(), additionalProcessors, tempFolder, onCompilationResult);
+ }
+
+ public static void compileWithKapt(
+ List<Source> sources,
+ Map<String, String> processorOptions,
+ List<Processor> additionalProcessors,
+ TemporaryFolder tempFolder,
+ Consumer<TestCompilationResult> onCompilationResult) {
+ TestCompilationResult result =
+ TestKotlinCompilerKt.compile(
+ tempFolder.getRoot(),
+ new TestCompilationArguments(
+ sources,
+ /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()),
+ /* inheritClasspath= */ false,
+ /* javacArguments= */ ImmutableList.of(),
+ /* kotlincArguments= */ ImmutableList.of(),
+ /* kaptProcessors= */ ImmutableList.<Processor>builder()
+ .addAll(defaultProcessors())
+ .addAll(additionalProcessors)
+ .build(),
+ /* symbolProcessorProviders= */ ImmutableList.of(),
+ /* processorOptions= */ processorOptions));
onCompilationResult.accept(result);
}
@@ -106,5 +188,134 @@
new UninstallModulesProcessor());
}
+ private static ImmutableList<SymbolProcessorProvider> kspDefaultProcessors() {
+ // TODO(bcorso): Add the rest of the KSP processors here.
+ return ImmutableList.of(
+ new KspAndroidEntryPointProcessor.Provider(),
+ new KspAliasOfProcessor.Provider(),
+ new KspAggregatedDepsProcessor.Provider(),
+ new KspComponentProcessor.Provider(),
+ new KspComponentTreeDepsProcessor.Provider(),
+ new KspCustomTestApplicationProcessor.Provider(),
+ new KspDefineComponentProcessor.Provider(),
+ new KspEarlyEntryPointProcessor.Provider(),
+ new KspGeneratesRootInputProcessor.Provider(),
+ new KspOriginatingElementProcessor.Provider(),
+ new KspRootProcessor.Provider(),
+ new KspUninstallModulesProcessor.Provider());
+ }
+
+ /** Used to compile Hilt sources and inspect the compiled results. */
+ @AutoValue
+ public abstract static class HiltCompiler {
+ static Builder builder() {
+ return new AutoValue_HiltCompilerTests_HiltCompiler.Builder()
+ // Set the builder defaults.
+ .processorOptions(ImmutableMap.of())
+ .additionalJavacProcessors(ImmutableList.of())
+ .additionalKspProcessors(ImmutableList.of())
+ .processingSteps(ImmutableList.of())
+ .javacArguments(ImmutableList.of());
+ }
+
+ /** Returns the sources being compiled */
+ abstract ImmutableCollection<Source> sources();
+
+ /** Returns the annotation processors options. */
+ abstract ImmutableMap<String, String> processorOptions();
+
+ /** Returns the extra Javac processors. */
+ abstract ImmutableCollection<Processor> additionalJavacProcessors();
+
+ /** Returns the extra KSP processors. */
+ abstract ImmutableCollection<SymbolProcessorProvider> additionalKspProcessors();
+
+ /** Returns the command-line options */
+ abstract ImmutableCollection<String> javacArguments();
+
+ /** Returns a new {@link HiltCompiler} instance with the annotation processors options. */
+ public HiltCompiler withProcessorOptions(ImmutableMap<String, String> processorOptions) {
+ return toBuilder().processorOptions(processorOptions).build();
+ }
+
+ /** Returns the processing steps suppliers. */
+ abstract ImmutableCollection<Function<XProcessingEnv, BaseProcessingStep>> processingSteps();
+
+ public HiltCompiler withProcessingSteps(
+ Function<XProcessingEnv, BaseProcessingStep>... mapping) {
+ return toBuilder().processingSteps(ImmutableList.copyOf(mapping)).build();
+ }
+
+ /** Returns a new {@link HiltCompiler} instance with the additional Javac processors. */
+ public HiltCompiler withAdditionalJavacProcessors(Processor... processors) {
+ return toBuilder().additionalJavacProcessors(ImmutableList.copyOf(processors)).build();
+ }
+
+ /** Returns a new {@link HiltCompiler} instance with the additional KSP processors. */
+ public HiltCompiler withAdditionalKspProcessors(SymbolProcessorProvider... processors) {
+ return toBuilder().additionalKspProcessors(ImmutableList.copyOf(processors)).build();
+ }
+
+ /** Returns a new {@link HiltCompiler} instance with command-line options. */
+ public HiltCompiler withJavacArguments(String... arguments) {
+ return toBuilder().javacArguments(ImmutableList.copyOf(arguments)).build();
+ }
+
+ /** Returns a new {@link HiltCompiler} instance with command-line options. */
+ public HiltCompiler withJavacArguments(ImmutableCollection<String> arguments) {
+ return toBuilder().javacArguments(arguments).build();
+ }
+
+ /** Returns a builder with the current values of this {@link Compiler} as default. */
+ abstract Builder toBuilder();
+
+ public void compile(Consumer<CompilationResultSubject> onCompilationResult) {
+ ProcessorTestExtKt.runProcessorTest(
+ sources().asList(),
+ /* classpath= */ ImmutableList.of(CompilerTests.compilerDepsJar()),
+ /* options= */ processorOptions(),
+ /* javacArguments= */ javacArguments().asList(),
+ /* kotlincArguments= */ ImmutableList.of(
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"),
+ /* config= */ HiltProcessingEnvConfigs.CONFIGS,
+ /* javacProcessors= */ ImmutableList.<Processor>builder()
+ .addAll(defaultProcessors())
+ .addAll(additionalJavacProcessors())
+ .addAll(
+ processingSteps().stream()
+ .map(HiltCompilerProcessors.JavacProcessor::new)
+ .collect(toImmutableList()))
+ .build(),
+ /* symbolProcessorProviders= */ ImmutableList.<SymbolProcessorProvider>builder()
+ .addAll(kspDefaultProcessors())
+ .addAll(additionalKspProcessors())
+ .addAll(
+ processingSteps().stream()
+ .map(HiltCompilerProcessors.KspProcessor.Provider::new)
+ .collect(toImmutableList()))
+ .build(),
+ result -> {
+ onCompilationResult.accept(result);
+ return null;
+ });
+ }
+
+ /** Used to build a {@link HiltCompiler}. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+ abstract Builder sources(ImmutableCollection<Source> sources);
+ abstract Builder processorOptions(ImmutableMap<String, String> processorOptions);
+ abstract Builder additionalJavacProcessors(ImmutableCollection<Processor> processors);
+ abstract Builder additionalKspProcessors(
+ ImmutableCollection<SymbolProcessorProvider> processors);
+ abstract Builder javacArguments(ImmutableCollection<String> arguments);
+
+ abstract Builder processingSteps(
+ ImmutableCollection<Function<XProcessingEnv, BaseProcessingStep>> processingSteps);
+
+ abstract HiltCompiler build();
+ }
+ }
+
private HiltCompilerTests() {}
}
diff --git a/java/dagger/hilt/processor/BUILD b/java/dagger/hilt/processor/BUILD
index 59f363d..ba7c9ee 100644
--- a/java/dagger/hilt/processor/BUILD
+++ b/java/dagger/hilt/processor/BUILD
@@ -58,7 +58,6 @@
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:metadata",
"//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
@@ -70,10 +69,11 @@
"//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:dagger_models",
"//java/dagger/hilt/processor/internal:component_descriptor",
"//java/dagger/hilt/processor/internal:component_names",
"//java/dagger/hilt/processor/internal:components",
- "//java/dagger/hilt/processor/internal:element_descriptors",
+ "//java/dagger/hilt/processor/internal:hilt_processing_env_configs",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
@@ -82,6 +82,7 @@
"//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:metadatas",
"//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",
@@ -99,19 +100,18 @@
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
],
artifact_target_maven_deps = [
- "com.google.auto:auto-common",
"com.google.code.findbugs:jsr305",
"com.google.dagger:dagger-compiler",
"com.google.dagger:dagger",
"com.google.dagger:dagger-spi",
+ "com.google.devtools.ksp:symbol-processing-api",
"com.google.guava:failureaccess",
"com.google.guava:guava",
"com.squareup:javapoet",
- "javax.annotation:javax.annotation-api",
+ "com.squareup:kotlinpoet",
"javax.inject:javax.inject",
"net.ltgt.gradle.incap:incap",
"org.jetbrains.kotlin:kotlin-stdlib",
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
],
javadoc_android_api_level = 32,
javadoc_root_packages = [
@@ -122,10 +122,6 @@
javadoc_srcs = [
"//java/dagger/hilt:hilt_processing_filegroup",
],
- # The shaded deps are added using jarjar, but they won't be shaded until later
- # due to: https://github.com/google/dagger/issues/2765. For the shaded rules see
- # util/deploy-hilt.sh
- shaded_deps = ["//third_party/java/auto:common"],
)
filegroup(
diff --git a/java/dagger/hilt/processor/internal/AggregatedElements.java b/java/dagger/hilt/processor/internal/AggregatedElements.java
index be593e9..db25a59 100644
--- a/java/dagger/hilt/processor/internal/AggregatedElements.java
+++ b/java/dagger/hilt/processor/internal/AggregatedElements.java
@@ -16,80 +16,66 @@
package dagger.hilt.processor.internal;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.xprocessing.XAnnotations;
import java.util.Optional;
-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 the class name of the proxy or {@link Optional#empty()} if a proxy is not needed. */
- public static Optional<ClassName> aggregatedElementProxyName(TypeElement aggregatedElement) {
- if (aggregatedElement.getModifiers().contains(PUBLIC)) {
+ public static Optional<ClassName> aggregatedElementProxyName(XTypeElement aggregatedElement) {
+ if (aggregatedElement.isPublic() && !aggregatedElement.isInternal()) {
// Public aggregated elements do not have proxies.
return Optional.empty();
}
- ClassName name = ClassName.get(aggregatedElement);
+ ClassName name = aggregatedElement.getClassName();
// To avoid going over the class name size limit, just prepend a single character.
return Optional.of(name.peerClass("_" + name.simpleName()));
}
/** Returns back the set of input {@code aggregatedElements} with all proxies unwrapped. */
- public static ImmutableSet<TypeElement> unwrapProxies(
- ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ public static ImmutableSet<XTypeElement> unwrapProxies(
+ ImmutableCollection<XTypeElement> aggregatedElements) {
return aggregatedElements.stream()
- .map(aggregatedElement -> unwrapProxy(aggregatedElement, elements))
+ .map(AggregatedElements::unwrapProxy)
.collect(toImmutableSet());
}
- private static TypeElement unwrapProxy(TypeElement element, Elements elements) {
- return Processors.hasAnnotation(element, ClassNames.AGGREGATED_ELEMENT_PROXY)
- ? Processors.getAnnotationClassValue(
- elements,
- Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_ELEMENT_PROXY),
- "value")
+ private static XTypeElement unwrapProxy(XTypeElement element) {
+ return element.hasAnnotation(ClassNames.AGGREGATED_ELEMENT_PROXY)
+ ? XAnnotations.getAsTypeElement(
+ element.getAnnotation(ClassNames.AGGREGATED_ELEMENT_PROXY), "value")
: element;
}
/** 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)
+ public static ImmutableSet<XTypeElement> from(
+ String aggregatingPackage, ClassName aggregatingAnnotation, XProcessingEnv env) {
+ ImmutableSet<XTypeElement> aggregatedElements =
+ env.getTypeElementsFromPackage(aggregatingPackage).stream()
// We're only interested in returning the original deps here. Proxies will be generated
// (if needed) and swapped just before generating @ComponentTreeDeps.
- .filter(
- element -> !Processors.hasAnnotation(element, ClassNames.AGGREGATED_ELEMENT_PROXY))
+ .filter(element -> !element.hasAnnotation(ClassNames.AGGREGATED_ELEMENT_PROXY))
.collect(toImmutableSet());
- ProcessorErrors.checkState(
- !aggregatedElements.isEmpty(),
- packageElement,
- "No dependencies found. Did you remove code in package %s?",
- packageElement);
-
- for (TypeElement aggregatedElement : aggregatedElements) {
+ for (XTypeElement aggregatedElement : aggregatedElements) {
ProcessorErrors.checkState(
- Processors.hasAnnotation(aggregatedElement, aggregatingAnnotation),
+ aggregatedElement.hasAnnotation(aggregatingAnnotation),
aggregatedElement,
"Expected element, %s, to be annotated with @%s, but only found: %s.",
- aggregatedElement.getSimpleName(),
+ aggregatedElement.getName(),
aggregatingAnnotation,
- aggregatedElement.getAnnotationMirrors());
+ aggregatedElement.getAllAnnotations().stream()
+ .map(XAnnotations::toStableString)
+ .collect(toImmutableList()));
}
return aggregatedElements;
diff --git a/java/dagger/hilt/processor/internal/AnnotationValues.java b/java/dagger/hilt/processor/internal/AnnotationValues.java
deleted file mode 100644
index 9ebeeeb..0000000
--- a/java/dagger/hilt/processor/internal/AnnotationValues.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2019 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 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;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-
-/** A utility class for working with {@link AnnotationValue} instances. */
-// TODO(bcorso): Update auto-common maven import so we can use it rather than this copy.
-public final class AnnotationValues {
-
- private AnnotationValues() {}
-
- private static class DefaultVisitor<T> extends SimpleAnnotationValueVisitor8<T, Void> {
- final Class<T> clazz;
-
- DefaultVisitor(Class<T> clazz) {
- this.clazz = checkNotNull(clazz);
- }
-
- @Override
- public T defaultAction(Object o, Void unused) {
- throw new IllegalArgumentException(
- "Expected a " + clazz.getSimpleName() + ", got instead: " + o);
- }
- }
-
- private static final class TypeMirrorVisitor extends DefaultVisitor<DeclaredType> {
- static final TypeMirrorVisitor INSTANCE = new TypeMirrorVisitor();
-
- TypeMirrorVisitor() {
- super(DeclaredType.class);
- }
-
- @Override
- public DeclaredType visitType(TypeMirror value, Void unused) {
- return MoreTypes.asDeclared(value);
- }
- }
-
- /**
- * Returns the value as a class.
- *
- * @throws IllegalArgumentException if the value is not a class.
- */
- public static DeclaredType getTypeMirror(AnnotationValue value) {
- return TypeMirrorVisitor.INSTANCE.visit(value);
- }
-
- private static final class EnumVisitor extends DefaultVisitor<VariableElement> {
- static final EnumVisitor INSTANCE = new EnumVisitor();
-
- EnumVisitor() {
- super(VariableElement.class);
- }
-
- @Override
- public VariableElement visitEnumConstant(VariableElement value, Void unused) {
- return value;
- }
- }
-
- /** 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.
- *
- * @throws IllegalArgumentException if the value is not an enum.
- */
- public static VariableElement getEnum(AnnotationValue value) {
- 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.
- *
- * @throws IllegalArgumentException if the value is not a string.
- */
- public static String getString(AnnotationValue value) {
- 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)) {
- throw new IllegalArgumentException(
- "Expected " + type.getSimpleName() + ", got instead: " + value);
- }
- return type.cast(value);
- }
-
- /** Returns the int value of an annotation */
- public static int getIntValue(AnnotationMirror annotation, String valueName) {
- return (int) getAnnotationValue(annotation, valueName).getValue();
- }
-
- /** Returns an optional int value of an annotation if the value name is present */
- public static Optional<Integer> getOptionalIntValue(
- AnnotationMirror annotation, String valueName) {
- return isValuePresent(annotation, valueName)
- ? Optional.of(getIntValue(annotation, valueName))
- : Optional.empty();
- }
-
- /** Returns the String value of an annotation */
- public static String getStringValue(AnnotationMirror annotation, String valueName) {
- return (String) getAnnotationValue(annotation, valueName).getValue();
- }
-
- /** Returns an optional String value of an annotation if the value name is present */
- public static Optional<String> getOptionalStringValue(
- AnnotationMirror annotation, String valueName) {
- return isValuePresent(annotation, valueName)
- ? Optional.of(getStringValue(annotation, valueName))
- : Optional.empty();
- }
-
- /** Returns the int array value of an annotation */
- public static int[] getIntArrayValue(AnnotationMirror annotation, String valueName) {
- return getAnnotationValues(getAnnotationValue(annotation, valueName)).stream()
- .mapToInt(it -> (int) it.getValue())
- .toArray();
- }
-
- /** Returns the String array value of an annotation */
- public static String[] getStringArrayValue(AnnotationMirror annotation, String valueName) {
- return getAnnotationValues(getAnnotationValue(annotation, valueName)).stream()
- .map(it -> (String) it.getValue())
- .toArray(String[]::new);
- }
-
- private static boolean isValuePresent(AnnotationMirror annotation, String valueName) {
- return getAnnotationValuesWithDefaults(annotation).keySet().stream()
- .anyMatch(member -> member.getSimpleName().contentEquals(valueName));
- }
-
- /**
- * Returns the list of values represented by an array annotation value.
- *
- * @throws IllegalArgumentException unless {@code annotationValue} represents an array
- */
- public static ImmutableList<AnnotationValue> getAnnotationValues(
- AnnotationValue annotationValue) {
- return annotationValue.accept(AS_ANNOTATION_VALUES, null);
- }
-
- private static final AnnotationValueVisitor<ImmutableList<AnnotationValue>, String>
- AS_ANNOTATION_VALUES =
- new SimpleAnnotationValueVisitor8<ImmutableList<AnnotationValue>, String>() {
- @Override
- public ImmutableList<AnnotationValue> visitArray(
- List<? extends AnnotationValue> vals, String elementName) {
- return ImmutableList.copyOf(vals);
- }
-
- @Override
- protected ImmutableList<AnnotationValue> defaultAction(Object o, String elementName) {
- throw new IllegalArgumentException(elementName + " is not an array: " + o);
- }
- };
-}
diff --git a/java/dagger/hilt/processor/internal/BUILD b/java/dagger/hilt/processor/internal/BUILD
index 2bf8c74..a2746ba 100644
--- a/java/dagger/hilt/processor/internal/BUILD
+++ b/java/dagger/hilt/processor/internal/BUILD
@@ -15,23 +15,37 @@
# Description:
# Internal code for implementing Hilt processors.
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+
package(default_visibility = ["//:src"])
java_library(
name = "base_processor",
srcs = [
- "BaseProcessor.java",
+ "BaseProcessingStep.java",
+ "JavacBaseProcessingStepProcessor.java",
+ "KspBaseProcessingStepProcessor.java",
"ProcessorErrorHandler.java",
],
deps = [
":compiler_options",
+ ":hilt_processing_env_configs",
":processor_errors",
- ":processors",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
+ ],
+)
+
+java_library(
+ name = "hilt_processing_env_configs",
+ srcs = ["HiltProcessingEnvConfigs.java"],
+ deps = [
+ "//java/dagger/internal/codegen/xprocessing",
],
)
@@ -43,6 +57,8 @@
"ProcessorErrors.java",
],
deps = [
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:common",
"//third_party/java/error_prone:annotations",
"//third_party/java/guava/base",
@@ -54,7 +70,6 @@
java_library(
name = "processors",
srcs = [
- "AnnotationValues.java",
"Processors.java",
],
deps = [
@@ -62,10 +77,11 @@
":processor_errors",
"//java/dagger/hilt/processor/internal/kotlin",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
"@maven//:org_jetbrains_kotlin_kotlin_stdlib",
],
)
@@ -81,16 +97,6 @@
)
java_library(
- name = "element_descriptors",
- srcs = [
- "ElementDescriptors.java",
- ],
- deps = [
- "//third_party/java/auto:common",
- ],
-)
-
-java_library(
name = "component_names",
srcs = [
"ComponentNames.java",
@@ -113,6 +119,7 @@
":processor_errors",
":processors",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:common",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
@@ -136,13 +143,10 @@
],
deps = [
":classnames",
- ":component_descriptor",
":processor_errors",
":processors",
- "//java/dagger/hilt/processor/internal/definecomponent:define_components",
- "//java/dagger/hilt/processor/internal/kotlin",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
@@ -156,12 +160,31 @@
":processor_errors",
"//java/dagger/hilt/processor/internal/optionvalues",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
],
)
+kt_jvm_library(
+ name = "dagger_models",
+ srcs = ["DaggerModels.kt"],
+ deps = [
+ ":processors",
+ "//:spi",
+ "//third_party/java/auto:common",
+ "//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
+ ],
+)
+
+# See: https://github.com/bazelbuild/rules_kotlin/issues/324
+alias(
+ name = "libdagger_models-src.jar",
+ actual = ":dagger_models-sources.jar",
+)
+
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 f57a34a..dc0ea0d 100644
--- a/java/dagger/hilt/processor/internal/BadInputException.java
+++ b/java/dagger/hilt/processor/internal/BadInputException.java
@@ -16,32 +16,31 @@
package dagger.hilt.processor.internal;
+
+import androidx.room.compiler.processing.XElement;
import com.google.common.collect.ImmutableList;
-import javax.lang.model.element.Element;
/**
* Exception to throw when input code has caused an error.
* Includes elements to point to for the cause of the error
*/
public final class BadInputException extends RuntimeException {
- private final ImmutableList<Element> badElements;
+ private final ImmutableList<XElement> badElements;
- public BadInputException(String message, Element badElement) {
- super(message);
- this.badElements = ImmutableList.of(badElement);
+ public BadInputException(String message) {
+ this(message, ImmutableList.of());
}
- public BadInputException(String message, Iterable<? extends Element> badElements) {
+ public BadInputException(String message, XElement badElement) {
+ this(message, ImmutableList.of(badElement));
+ }
+
+ public BadInputException(String message, Iterable<? extends XElement> badElements) {
super(message);
this.badElements = ImmutableList.copyOf(badElements);
}
- public BadInputException(String message) {
- super(message);
- this.badElements = ImmutableList.of();
- }
-
- public ImmutableList<Element> getBadElements() {
+ public ImmutableList<XElement> getBadElements() {
return badElements;
}
}
diff --git a/java/dagger/hilt/processor/internal/BaseProcessingStep.java b/java/dagger/hilt/processor/internal/BaseProcessingStep.java
new file mode 100644
index 0000000..c15d5ae
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/BaseProcessingStep.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XProcessingStep;
+import androidx.room.compiler.processing.XRoundEnv;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Implements default configurations for ProcessingSteps, and provides structure for exception
+ * handling.
+ *
+ * <p>In each round it will do the following:
+ *
+ * <ol>
+ * <li>#preProcess()
+ * <li>foreach element:
+ * <ul>
+ * <li>#processEach()
+ * </ul>
+ * <li>#postProcess()
+ * </ol>
+ *
+ * <p>#processEach() allows each element to be processed, even if exceptions are thrown. Due to the
+ * non-deterministic ordering of the processed elements, this is needed to ensure a consistent set
+ * of exceptions are thrown with each build.
+ */
+public abstract class BaseProcessingStep implements XProcessingStep {
+ private final ProcessorErrorHandler errorHandler;
+ boolean isAnnotationClassNamesOverridden = true;
+
+ private final XProcessingEnv processingEnv;
+
+ public BaseProcessingStep(XProcessingEnv env) {
+ errorHandler = new ProcessorErrorHandler(env);
+ processingEnv = env;
+ }
+
+ protected final XProcessingEnv processingEnv() {
+ return processingEnv;
+ }
+
+ @Override
+ public final ImmutableSet<String> annotations() {
+ ImmutableSet<ClassName> annotationClassNames = annotationClassNames();
+ if (!isAnnotationClassNamesOverridden) {
+ return ImmutableSet.of("*");
+ }
+ if (annotationClassNames == null || annotationClassNames.isEmpty()) {
+ throw new IllegalStateException("annotationClassNames() should return one or more elements.");
+ } else {
+ return annotationClassNames.stream().map(ClassName::canonicalName).collect(toImmutableSet());
+ }
+ }
+
+ // When this method is not implemented by users, all annotated elements will processed by this
+ // processing step.
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ isAnnotationClassNamesOverridden = false;
+ return ImmutableSet.of();
+ }
+
+ protected void processEach(ClassName annotation, XElement element) throws Exception {}
+
+ protected void preProcess(XProcessingEnv env, XRoundEnv round) {}
+
+ protected void postProcess(XProcessingEnv env, XRoundEnv round) throws Exception {}
+
+ public final void preRoundProcess(XProcessingEnv env, XRoundEnv round) {
+ preProcess(env, round);
+ }
+
+ public final void postRoundProcess(XProcessingEnv env, XRoundEnv round) {
+ if (errorHandler.isEmpty()) {
+ try {
+ postProcess(env, round);
+ } catch (Exception e) {
+ errorHandler.recordError(e);
+ }
+ }
+ if (!delayErrors() || round.isProcessingOver()) {
+ errorHandler.checkErrors();
+ }
+ }
+
+ @Override
+ public final ImmutableSet<XElement> process(
+ XProcessingEnv env,
+ Map<String, ? extends Set<? extends XElement>> elementsByAnnotation,
+ boolean isLastRound) {
+ ImmutableSet.Builder<XElement> elementsToReprocessBuilder = ImmutableSet.builder();
+ for (ClassName annotationName : annotationClassNames()) {
+ Set<? extends XElement> elements = elementsByAnnotation.get(annotationName.canonicalName());
+ if (elements != null) {
+ for (XElement element : elements) {
+ try {
+ processEach(annotationName, element);
+ } catch (Exception e) {
+ if (e instanceof ErrorTypeException && !isLastRound) {
+ // Allow an extra round to reprocess to try to resolve this type.
+ elementsToReprocessBuilder.add(element);
+ } else {
+ errorHandler.recordError(e);
+ }
+ }
+ }
+ }
+ }
+ return elementsToReprocessBuilder.build();
+ }
+
+ /**
+ * Returns true if you want to delay errors to the last round. Useful if the processor generates
+ * code for symbols used a lot in the user code. Delaying allows as much code to compile as
+ * possible for correctly configured types and reduces error spam.
+ */
+ protected boolean delayErrors() {
+ return false;
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/BaseProcessor.java b/java/dagger/hilt/processor/internal/BaseProcessor.java
deleted file mode 100644
index a921075..0000000
--- a/java/dagger/hilt/processor/internal/BaseProcessor.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2019 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 com.google.common.base.Preconditions.checkState;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.SetMultimap;
-import com.squareup.javapoet.ClassName;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.Messager;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-
-/**
- * Implements default configurations for Processors, and provides structure for exception handling.
- *
- * <p>By default #process() will do the following:
- *
- * <ol>
- * <li> #preRoundProcess()
- * <li> foreach element:
- * <ul><li> #processEach()</ul>
- * </li>
- * <li> #postRoundProcess()
- * <li> #claimAnnotation()
- * </ol>
- *
- * <p>#processEach() allows each element to be processed, even if exceptions are thrown. Due to the
- * non-deterministic ordering of the processed elements, this is needed to ensure a consistent set
- * of exceptions are thrown with each build.
- */
-public abstract class BaseProcessor extends AbstractProcessor {
- /** Stores the state of processing for a given annotation and element. */
- @AutoValue
- abstract static class ProcessingState {
- private static ProcessingState of(TypeElement annotation, Element element) {
- // We currently only support TypeElements directly annotated with the annotation.
- // TODO(bcorso): Switch to using BasicAnnotationProcessor if we need more than this.
- // Note: Switching to BasicAnnotationProcessor is currently not possible because of cyclic
- // references to generated types in our API. For example, an @AndroidEntryPoint annotated
- // element will indefinitely defer its own processing because it extends a generated type
- // that it's responsible for generating.
- checkState(MoreElements.isType(element));
- checkState(Processors.hasAnnotation(element, ClassName.get(annotation)));
- return new AutoValue_BaseProcessor_ProcessingState(
- ClassName.get(annotation),
- ClassName.get(MoreElements.asType(element)));
- }
-
- /** Returns the class name of the annotation. */
- abstract ClassName annotationClassName();
-
- /** Returns the type name of the annotated element. */
- abstract ClassName elementClassName();
-
- /** Returns the annotation that triggered the processing. */
- TypeElement annotation(Elements elements) {
- return elements.getTypeElement(elementClassName().toString());
- }
-
- /** Returns the annotated element to process. */
- TypeElement element(Elements elements) {
- return elements.getTypeElement(annotationClassName().toString());
- }
- }
-
- private final Set<ProcessingState> stateToReprocess = new LinkedHashSet<>();
- private Elements elements;
- private Types types;
- 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 ImmutableSet.<String>builder()
- .addAll(HiltCompilerOptions.getProcessorOptions())
- .addAll(additionalProcessingOptions())
- .build();
- }
-
- /** Returns additional processing options that should only be applied for a single processor. */
- protected Set<String> additionalProcessingOptions() {
- return ImmutableSet.of();
- }
-
- /** Used to perform initialization before each round of processing. */
- protected void preRoundProcess(RoundEnvironment roundEnv) {};
-
- /**
- * Called for each element in a round that uses a supported annotation.
- *
- * Note that an exception can be thrown for each element in the round. This is usually preferred
- * over throwing only the first exception in a round. Only throwing the first exception in the
- * round can lead to flaky errors that are dependent on the non-deterministic ordering that the
- * elements are processed in.
- */
- protected void processEach(TypeElement annotation, Element element) throws Exception {};
-
- /**
- * Used to perform post processing at the end of a round. This is especially useful for handling
- * additional processing that depends on aggregate data, that cannot be handled in #processEach().
- *
- * <p>Note: this will not be called if an exception is thrown during #processEach() -- if we have
- * already detected errors on an annotated element, performing post processing on an aggregate
- * will just produce more (perhaps non-deterministic) errors.
- */
- protected void postRoundProcess(RoundEnvironment roundEnv) throws Exception {};
-
- /** @return true if you want to claim annotations after processing each round. Default false. */
- protected boolean claimAnnotations() {
- return false;
- }
-
- /**
- * @return true if you want to delay errors to the last round. Useful if the processor
- * generates code for symbols used a lot in the user code. Delaying allows as much code to
- * compile as possible for correctly configured types and reduces error spam.
- */
- protected boolean delayErrors() {
- return false;
- }
-
-
- @Override
- public synchronized void init(ProcessingEnvironment processingEnvironment) {
- super.init(processingEnvironment);
- this.messager = processingEnv.getMessager();
- this.elements = processingEnv.getElementUtils();
- this.types = processingEnv.getTypeUtils();
- this.errorHandler = new ProcessorErrorHandler(processingEnvironment);
- HiltCompilerOptions.checkWrongAndDeprecatedOptions(processingEnvironment);
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latestSupported();
- }
-
- /**
- * This should not be overridden, as it defines the order of the processing.
- */
- @Override
- public final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- preRoundProcess(roundEnv);
-
- boolean roundError = false;
-
- // Gather the set of new and deferred elements to process, grouped by annotation.
- SetMultimap<TypeElement, Element> elementMultiMap = LinkedHashMultimap.create();
- for (ProcessingState processingState : stateToReprocess) {
- elementMultiMap.put(processingState.annotation(elements), processingState.element(elements));
- }
- for (TypeElement annotation : annotations) {
- elementMultiMap.putAll(annotation, roundEnv.getElementsAnnotatedWith(annotation));
- }
-
- // Clear the processing state before reprocessing.
- stateToReprocess.clear();
-
- for (Map.Entry<TypeElement, Collection<Element>> entry : elementMultiMap.asMap().entrySet()) {
- TypeElement annotation = entry.getKey();
- for (Element element : entry.getValue()) {
- try {
- processEach(annotation, element);
- } catch (Exception e) {
- if (e instanceof ErrorTypeException && !roundEnv.processingOver()) {
- // Allow an extra round to reprocess to try to resolve this type.
- stateToReprocess.add(ProcessingState.of(annotation, element));
- } else {
- errorHandler.recordError(e);
- roundError = true;
- }
- }
- }
- }
-
- if (!roundError) {
- try {
- postRoundProcess(roundEnv);
- } catch (Exception e) {
- errorHandler.recordError(e);
- }
- }
-
- if (!delayErrors() || roundEnv.processingOver()) {
- errorHandler.checkErrors();
- }
-
- return claimAnnotations();
- }
-
- /** @return the error handle for the processor. */
- protected final ProcessorErrorHandler getErrorHandler() {
- return errorHandler;
- }
-
- public final ProcessingEnvironment getProcessingEnv() {
- return processingEnv;
- }
-
- public final Elements getElementUtils() {
- return elements;
- }
-
- public final Types getTypeUtils() {
- return types;
- }
-
- public final Messager getMessager() {
- return messager;
- }
-}
diff --git a/java/dagger/hilt/processor/internal/ClassNames.java b/java/dagger/hilt/processor/internal/ClassNames.java
index 5a62715..ec2e73e 100644
--- a/java/dagger/hilt/processor/internal/ClassNames.java
+++ b/java/dagger/hilt/processor/internal/ClassNames.java
@@ -83,6 +83,7 @@
get("dagger.multibindings", "Multibinds");
public static final ClassName INTO_MAP = get("dagger.multibindings", "IntoMap");
public static final ClassName INTO_SET = get("dagger.multibindings", "IntoSet");
+ public static final ClassName ELEMENTS_INTO_SET = get("dagger.multibindings", "ElementsIntoSet");
public static final ClassName STRING_KEY = get("dagger.multibindings", "StringKey");
public static final ClassName PROVIDES =
get("dagger", "Provides");
diff --git a/java/dagger/hilt/processor/internal/Components.java b/java/dagger/hilt/processor/internal/Components.java
index 5ceeca0..a8650dc 100644
--- a/java/dagger/hilt/processor/internal/Components.java
+++ b/java/dagger/hilt/processor/internal/Components.java
@@ -16,63 +16,50 @@
package dagger.hilt.processor.internal;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.definecomponent.DefineComponents;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
+import dagger.internal.codegen.xprocessing.XElements;
/** Helper methods for defining components and the component hierarchy. */
public final class Components {
- // TODO(bcorso): Remove this once all usages are replaced with #getComponents().
- /**
- * Returns the {@link ComponentDescriptor}s for a given element annotated with {@link
- * dagger.hilt.InstallIn}.
- */
- public static ImmutableSet<ComponentDescriptor> getComponentDescriptors(
- Elements elements, Element element) {
- DefineComponents defineComponents = DefineComponents.create();
- return getComponents(elements, element).stream()
- .map(component -> elements.getTypeElement(component.canonicalName()))
- // TODO(b/144939893): Memoize ComponentDescriptors so we're not recalculating.
- .map(defineComponents::componentDescriptor)
- .collect(toImmutableSet());
- }
-
/** Returns the {@link dagger.hilt.InstallIn} components for a given element. */
- public static ImmutableSet<ClassName> getComponents(Elements elements, Element element) {
+ public static ImmutableSet<ClassName> getComponents(XElement element) {
ImmutableSet<ClassName> components;
- if (Processors.hasAnnotation(element, ClassNames.INSTALL_IN)
- || Processors.hasAnnotation(element, ClassNames.TEST_INSTALL_IN)) {
- components = getHiltInstallInComponents(elements, element);
+ if (element.hasAnnotation(ClassNames.INSTALL_IN)
+ || element.hasAnnotation(ClassNames.TEST_INSTALL_IN)) {
+ components = getHiltInstallInComponents(element);
} else {
// Check the enclosing element in case it passed in module is a companion object. This helps
// in cases where the element was arrived at by checking a binding method and moving outward.
- Element enclosing = element.getEnclosingElement();
+ XElement enclosing = element.getEnclosingElement();
if (enclosing != null
- && MoreElements.isType(enclosing)
- && MoreElements.isType(element)
- && Processors.hasAnnotation(enclosing, ClassNames.MODULE)
- && KotlinMetadataUtils.getMetadataUtil().isCompanionObjectClass(
- MoreElements.asType(element))) {
- return getComponents(elements, enclosing);
+ && isTypeElement(enclosing)
+ && isTypeElement(element)
+ && enclosing.hasAnnotation(ClassNames.MODULE)
+ && asTypeElement(element).isCompanionObject()) {
+ return getComponents(enclosing);
}
if (Processors.hasErrorTypeAnnotation(element)) {
throw new BadInputException(
- "Error annotation found on element " + element + ". Look above for compilation errors",
+ String.format(
+ "Error annotation found on element %s. Look above for compilation errors",
+ XElements.toStableString(element)),
element);
} else {
throw new BadInputException(
String.format(
"An @InstallIn annotation is required for: %s." ,
- element),
+ XElements.toStableString(element)),
element);
}
}
@@ -87,36 +74,30 @@
return builder.build();
}
- private static ImmutableSet<ClassName> getHiltInstallInComponents(
- Elements elements, Element element) {
+ private static ImmutableSet<ClassName> getHiltInstallInComponents(XElement element) {
Preconditions.checkArgument(
- Processors.hasAnnotation(element, ClassNames.INSTALL_IN)
- || Processors.hasAnnotation(element, ClassNames.TEST_INSTALL_IN));
+ element.hasAnnotation(ClassNames.INSTALL_IN)
+ || element.hasAnnotation(ClassNames.TEST_INSTALL_IN));
- ImmutableSet<TypeElement> components =
- ImmutableSet.copyOf(
- Processors.hasAnnotation(element, ClassNames.INSTALL_IN)
- ? Processors.getAnnotationClassValues(
- elements,
- Processors.getAnnotationMirror(element, ClassNames.INSTALL_IN),
- "value")
- : Processors.getAnnotationClassValues(
- elements,
- Processors.getAnnotationMirror(element, ClassNames.TEST_INSTALL_IN),
- "components"));
+ ImmutableList<XTypeElement> components =
+ element.hasAnnotation(ClassNames.INSTALL_IN)
+ ? Processors.getAnnotationClassValues(
+ element.getAnnotation(ClassNames.INSTALL_IN), "value")
+ : Processors.getAnnotationClassValues(
+ element.getAnnotation(ClassNames.TEST_INSTALL_IN), "components");
- ImmutableSet<TypeElement> undefinedComponents =
+ ImmutableSet<XTypeElement> undefinedComponents =
components.stream()
- .filter(component -> !Processors.hasAnnotation(component, ClassNames.DEFINE_COMPONENT))
+ .filter(component -> !component.hasAnnotation(ClassNames.DEFINE_COMPONENT))
.collect(toImmutableSet());
ProcessorErrors.checkState(
undefinedComponents.isEmpty(),
element,
"@InstallIn, can only be used with @DefineComponent-annotated classes, but found: %s",
- undefinedComponents);
+ undefinedComponents.stream().map(XElements::toStableString).collect(toImmutableList()));
- return components.stream().map(ClassName::get).collect(toImmutableSet());
+ return components.stream().map(XTypeElement::getClassName).collect(toImmutableSet());
}
private Components() {}
diff --git a/java/dagger/hilt/processor/internal/DaggerModels.kt b/java/dagger/hilt/processor/internal/DaggerModels.kt
new file mode 100644
index 0000000..7d64d23
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/DaggerModels.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal
+
+import com.google.auto.common.MoreTypes
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.squareup.javapoet.ClassName
+import dagger.spi.model.DaggerAnnotation
+import dagger.spi.model.DaggerElement
+import dagger.spi.model.DaggerProcessingEnv
+import dagger.spi.model.DaggerType
+
+
+fun DaggerType.asElement(): DaggerElement =
+ when (checkNotNull(backend())) {
+ DaggerProcessingEnv.Backend.JAVAC -> {
+ val javaType = checkNotNull(java())
+ DaggerElement.fromJavac(MoreTypes.asElement(javaType))
+ }
+ DaggerProcessingEnv.Backend.KSP -> {
+ val kspType = checkNotNull(ksp())
+ DaggerElement.fromKsp(kspType.declaration)
+ }
+ }
+
+fun DaggerElement.hasAnnotation(className: ClassName) =
+ when (checkNotNull(backend())) {
+ DaggerProcessingEnv.Backend.JAVAC -> {
+ val javaElement = checkNotNull(java())
+ Processors.hasAnnotation(javaElement, className)
+ }
+ DaggerProcessingEnv.Backend.KSP -> {
+ val kspAnnotated = checkNotNull(ksp())
+ kspAnnotated.hasAnnotation(className)
+ }
+ }
+
+fun DaggerAnnotation.getQualifiedName() =
+ when (checkNotNull(backend())) {
+ DaggerProcessingEnv.Backend.JAVAC -> {
+ val javaAnnotation = checkNotNull(java())
+ MoreTypes.asTypeElement(javaAnnotation.annotationType).qualifiedName.toString()
+ }
+ DaggerProcessingEnv.Backend.KSP -> {
+ val kspAnnotation = checkNotNull(ksp())
+ kspAnnotation.annotationType.resolve().declaration.qualifiedName!!.asString()
+ }
+ }
+
+private fun KSAnnotated.hasAnnotation(className: ClassName) =
+ annotations.any {
+ it.annotationType.resolve().declaration.qualifiedName!!.asString() == className.canonicalName()
+ }
diff --git a/java/dagger/hilt/processor/internal/ElementDescriptors.java b/java/dagger/hilt/processor/internal/ElementDescriptors.java
deleted file mode 100644
index 07b2c07..0000000
--- a/java/dagger/hilt/processor/internal/ElementDescriptors.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2022 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 com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.isType;
-
-import java.util.stream.Collectors;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ErrorType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.IntersectionType;
-import javax.lang.model.type.NoType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/** Utility class for getting field and method descriptors. */
-public final class ElementDescriptors {
- private ElementDescriptors() {}
-
- /**
- * Returns the field descriptor of the given {@code element}.
- *
- * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2">JVM
- * specification, section 4.3.2</a>.
- */
- public static String getFieldDescriptor(VariableElement element) {
- return element.getSimpleName() + ":" + getDescriptor(element.asType());
- }
-
- /**
- * Returns the method descriptor of the given {@code element}.
- *
- * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3">JVM
- * specification, section 4.3.3</a>.
- */
- public static String getMethodDescriptor(ExecutableElement element) {
- return element.getSimpleName() + getDescriptor(element.asType());
- }
-
- private static String getDescriptor(TypeMirror t) {
- return t.accept(JVM_DESCRIPTOR_TYPE_VISITOR, null);
- }
-
- private static final SimpleTypeVisitor8<String, Void> JVM_DESCRIPTOR_TYPE_VISITOR =
- new SimpleTypeVisitor8<String, Void>() {
-
- @Override
- public String visitArray(ArrayType arrayType, Void v) {
- return "[" + getDescriptor(arrayType.getComponentType());
- }
-
- @Override
- public String visitDeclared(DeclaredType declaredType, Void v) {
- return "L" + getInternalName(declaredType.asElement()) + ";";
- }
-
- @Override
- public String visitError(ErrorType errorType, Void v) {
- // For descriptor generating purposes we don't need a fully modeled type since we are
- // only interested in obtaining the class name in its "internal form".
- return visitDeclared(errorType, v);
- }
-
- @Override
- public String visitExecutable(ExecutableType executableType, Void v) {
- String parameterDescriptors =
- executableType.getParameterTypes().stream()
- .map(ElementDescriptors::getDescriptor)
- .collect(Collectors.joining());
- String returnDescriptor = getDescriptor(executableType.getReturnType());
- return "(" + parameterDescriptors + ")" + returnDescriptor;
- }
-
- @Override
- public String visitIntersection(IntersectionType intersectionType, Void v) {
- // For a type variable with multiple bounds: "the erasure of a type variable is determined
- // by the first type in its bound" - JVM Spec Sec 4.4
- return getDescriptor(intersectionType.getBounds().get(0));
- }
-
- @Override
- public String visitNoType(NoType noType, Void v) {
- return "V";
- }
-
- @Override
- public String visitPrimitive(PrimitiveType primitiveType, Void v) {
- switch (primitiveType.getKind()) {
- case BOOLEAN:
- return "Z";
- case BYTE:
- return "B";
- case SHORT:
- return "S";
- case INT:
- return "I";
- case LONG:
- return "J";
- case CHAR:
- return "C";
- case FLOAT:
- return "F";
- case DOUBLE:
- return "D";
- default:
- throw new IllegalArgumentException("Unknown primitive type.");
- }
- }
-
- @Override
- public String visitTypeVariable(TypeVariable typeVariable, Void v) {
- // The erasure of a type variable is the erasure of its leftmost bound. - JVM Spec Sec 4.6
- return getDescriptor(typeVariable.getUpperBound());
- }
-
- @Override
- public String defaultAction(TypeMirror typeMirror, Void v) {
- throw new IllegalArgumentException("Unsupported type: " + typeMirror);
- }
-
- @Override
- public String visitWildcard(WildcardType wildcardType, Void v) {
- return "";
- }
-
- /**
- * Returns the name of this element in its "internal form".
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2">JVM
- * specification, section 4.2</a>.
- */
- private String getInternalName(Element element) {
- if (isType(element)) {
- TypeElement typeElement = asType(element);
- switch (typeElement.getNestingKind()) {
- case TOP_LEVEL:
- return typeElement.getQualifiedName().toString().replace('.', '/');
- case MEMBER:
- return getInternalName(typeElement.getEnclosingElement())
- + "$"
- + typeElement.getSimpleName();
- default:
- throw new IllegalArgumentException("Unsupported nesting kind.");
- }
- }
- return element.getSimpleName().toString();
- }
- };
-}
diff --git a/java/dagger/hilt/processor/internal/ErrorTypeException.java b/java/dagger/hilt/processor/internal/ErrorTypeException.java
index 6f8f67e..4ba4991 100644
--- a/java/dagger/hilt/processor/internal/ErrorTypeException.java
+++ b/java/dagger/hilt/processor/internal/ErrorTypeException.java
@@ -16,7 +16,7 @@
package dagger.hilt.processor.internal;
-import javax.lang.model.element.Element;
+import androidx.room.compiler.processing.XElement;
/**
* Exception to throw when a required {@link Element} is or inherits from an error kind.
@@ -24,14 +24,14 @@
* <p>Includes element to point to for the cause of the error
*/
public final class ErrorTypeException extends RuntimeException {
- private final Element badElement;
+ private final XElement badElement;
- public ErrorTypeException(String message, Element badElement) {
+ public ErrorTypeException(String message, XElement badElement) {
super(message);
this.badElement = badElement;
}
- public Element getBadElement() {
+ public XElement getBadElement() {
return badElement;
}
}
diff --git a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
index 4c2d158..cdb2d6c 100644
--- a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
+++ b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
@@ -16,8 +16,11 @@
package dagger.hilt.processor.internal;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static com.google.common.base.Ascii.toUpperCase;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import dagger.hilt.processor.internal.optionvalues.BooleanValue;
import dagger.hilt.processor.internal.optionvalues.GradleProjectType;
@@ -26,8 +29,6 @@
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
/** Hilt annotation processor options. */
@@ -42,10 +43,10 @@
* 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) {
+ public static boolean isAndroidSuperClassValidationDisabled(XTypeElement element) {
EnumOption<BooleanValue> option = DISABLE_ANDROID_SUPERCLASS_VALIDATION;
- return option.get(env) == BooleanValue.TRUE;
+ XProcessingEnv processorEnv = getProcessingEnv(element);
+ return option.get(processorEnv) == BooleanValue.TRUE;
}
/**
@@ -60,13 +61,13 @@
* HiltAndroidApp} or {@code HiltAndroidTest} usages in the same compilation unit.
*/
public static boolean isCrossCompilationRootValidationDisabled(
- ImmutableSet<TypeElement> rootElements, ProcessingEnvironment env) {
+ ImmutableSet<XTypeElement> rootElements, XProcessingEnv env) {
EnumOption<BooleanValue> option = DISABLE_CROSS_COMPILATION_ROOT_VALIDATION;
return option.get(env) == BooleanValue.TRUE;
}
/** Returns {@code true} if the check for {@link dagger.hilt.InstallIn} is disabled. */
- public static boolean isModuleInstallInCheckDisabled(ProcessingEnvironment env) {
+ public static boolean isModuleInstallInCheckDisabled(XProcessingEnv env) {
return DISABLE_MODULES_HAVE_INSTALL_IN_CHECK.get(env) == BooleanValue.TRUE;
}
@@ -78,7 +79,7 @@
* 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) {
+ public static boolean isSharedTestComponentsEnabled(XProcessingEnv env) {
return SHARE_TEST_COMPONENTS.get(env) == BooleanValue.TRUE;
}
@@ -87,7 +88,7 @@
*
* <p>Note:This is for internal use only!
*/
- public static boolean useAggregatingRootProcessor(ProcessingEnvironment env) {
+ public static boolean useAggregatingRootProcessor(XProcessingEnv env) {
return USE_AGGREGATING_ROOT_PROCESSOR.get(env) == BooleanValue.TRUE;
}
@@ -96,7 +97,7 @@
*
* <p>Note:This is for internal use only!
*/
- public static GradleProjectType getGradleProjectType(ProcessingEnvironment env) {
+ public static GradleProjectType getGradleProjectType(XProcessingEnv env) {
return GRADLE_PROJECT_TYPE.get(env);
}
@@ -126,7 +127,7 @@
private static final ImmutableSet<String> DEPRECATED_OPTIONS =
ImmutableSet.of("dagger.hilt.android.useFragmentGetContextFix");
- public static void checkWrongAndDeprecatedOptions(ProcessingEnvironment env) {
+ public static void checkWrongAndDeprecatedOptions(XProcessingEnv env) {
Set<String> knownOptions = getProcessorOptions();
for (String option : env.getOptions().keySet()) {
if (knownOptions.contains(option)) {
@@ -173,7 +174,7 @@
return "dagger.hilt." + name;
}
- E get(ProcessingEnvironment env) {
+ E get(XProcessingEnv env) {
String value = env.getOptions().get(getQualifiedName());
if (value == null) {
return defaultValue;
diff --git a/java/dagger/hilt/processor/internal/HiltProcessingEnvConfigs.java b/java/dagger/hilt/processor/internal/HiltProcessingEnvConfigs.java
new file mode 100644
index 0000000..fa41b9a
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/HiltProcessingEnvConfigs.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal;
+
+import androidx.room.compiler.processing.XProcessingEnvConfig;
+
+/** The {@link XProcessingEnvConfig} used when processing Hilt. */
+public final class HiltProcessingEnvConfigs {
+ public static final XProcessingEnvConfig CONFIGS =
+ new XProcessingEnvConfig.Builder()
+ // In Hilt we disable the default element validation because we would otherwise run into a
+ // cycle where our Hilt processors are waiting on the "Hilt_Foo" classes to be generated
+ // before processing "Foo", but "Hilt_Foo" can't be generated until "Foo" is processed.
+ // Thus, we disable that validation here and we perform our own validation when necessary.
+ .disableAnnotatedElementValidation(true)
+ .build();
+
+ private HiltProcessingEnvConfigs() {}
+}
diff --git a/java/dagger/hilt/processor/internal/JavacBaseProcessingStepProcessor.java b/java/dagger/hilt/processor/internal/JavacBaseProcessingStepProcessor.java
new file mode 100644
index 0000000..74bb47f
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/JavacBaseProcessingStepProcessor.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XProcessingStep;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import javax.lang.model.SourceVersion;
+
+/** A JavacBasicAnnotationProcessor that contains a single BaseProcessingStep. */
+public abstract class JavacBaseProcessingStepProcessor extends JavacBasicAnnotationProcessor {
+ private BaseProcessingStep processingStep;
+
+ public JavacBaseProcessingStepProcessor() {
+ super(HiltProcessingEnvConfigs.CONFIGS);
+ }
+
+ @Override
+ public void initialize(XProcessingEnv env) {
+ HiltCompilerOptions.checkWrongAndDeprecatedOptions(env);
+ processingStep = processingStep();
+ }
+
+ @Override
+ public final SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @Override
+ public final ImmutableSet<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 ImmutableSet.<String>builder()
+ .addAll(HiltCompilerOptions.getProcessorOptions())
+ .addAll(additionalProcessingOptions())
+ .build();
+ }
+
+ @Override
+ public final ImmutableList<XProcessingStep> processingSteps() {
+ return ImmutableList.of(processingStep);
+ }
+
+ @Override
+ public void preRound(XProcessingEnv env, XRoundEnv round) {
+ processingStep.preRoundProcess(env, round);
+ }
+
+ protected abstract BaseProcessingStep processingStep();
+
+ @Override
+ public void postRound(XProcessingEnv env, XRoundEnv round) {
+ processingStep.postRoundProcess(env, round);
+ }
+
+ /** Returns additional processing options that should only be applied for a single processor. */
+ protected Set<String> additionalProcessingOptions() {
+ return ImmutableSet.of();
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/KspBaseProcessingStepProcessor.java b/java/dagger/hilt/processor/internal/KspBaseProcessingStepProcessor.java
new file mode 100644
index 0000000..df9546b
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/KspBaseProcessingStepProcessor.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XProcessingStep;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+
+/** A KspBasicAnnotationProcessor that contains a single BaseProcessingStep. */
+public abstract class KspBaseProcessingStepProcessor extends KspBasicAnnotationProcessor {
+ private BaseProcessingStep processingStep;
+
+ public KspBaseProcessingStepProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment, HiltProcessingEnvConfigs.CONFIGS);
+ }
+
+ @Override
+ public void initialize(XProcessingEnv env) {
+ HiltCompilerOptions.checkWrongAndDeprecatedOptions(env);
+ processingStep = processingStep();
+ }
+
+ protected abstract BaseProcessingStep processingStep();
+
+ @Override
+ public void preRound(XProcessingEnv env, XRoundEnv round) {
+ processingStep.preRoundProcess(env, round);
+ }
+
+ @Override
+ public final ImmutableList<XProcessingStep> processingSteps() {
+ return ImmutableList.of(processingStep);
+ }
+
+ @Override
+ public void postRound(XProcessingEnv env, XRoundEnv round) {
+ processingStep.postRoundProcess(env, round);
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java b/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java
index 2ecc0f0..87413fb 100644
--- a/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java
+++ b/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java
@@ -16,22 +16,23 @@
package dagger.hilt.processor.internal;
-import com.google.auto.common.MoreElements;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XMessager;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.google.auto.value.AutoValue;
import com.google.common.base.Throwables;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.util.Elements;
import javax.tools.Diagnostic.Kind;
/** Utility class to handle keeping track of errors during processing. */
final class ProcessorErrorHandler {
- private static final String FAILURE_PREFIX = "[Hilt]\n";
+ private static final String FAILURE_PREFIX = "[Hilt] ";
// Special characters to make the tag red and bold to draw attention since
// this error can get drowned out by other errors resulting from missing
@@ -39,14 +40,13 @@
private static final String FAILURE_SUFFIX =
"\n\033[1;31m[Hilt] Processing did not complete. See error above for details.\033[0m";
- private final Messager messager;
- private final Elements elements;
- private final List<HiltError> hiltErrors;
+ private final XProcessingEnv processingEnv;
+ private final XMessager messager;
+ private final List<HiltError> hiltErrors = new ArrayList<>();
- ProcessorErrorHandler(ProcessingEnvironment env) {
- this.messager = env.getMessager();
- this.elements = env.getElementUtils();
- this.hiltErrors = new ArrayList<>();
+ ProcessorErrorHandler(XProcessingEnv processingEnv) {
+ this.processingEnv = processingEnv;
+ this.messager = processingEnv.getMessager();
}
/**
@@ -65,7 +65,7 @@
if (badInput.getBadElements().isEmpty()) {
hiltErrors.add(HiltError.of(badInput.getMessage()));
}
- for (Element element : badInput.getBadElements()) {
+ for (XElement element : badInput.getBadElements()) {
hiltErrors.add(HiltError.of(badInput.getMessage(), element));
}
} else if (t instanceof ErrorTypeException) {
@@ -84,16 +84,15 @@
hiltErrors.forEach(
hiltError -> {
if (hiltError.element().isPresent()) {
- Element element = hiltError.element().get();
- if (MoreElements.isType(element)) {
+ XElement element = hiltError.element().get();
+ if (isTypeElement(element)) {
// If the error type is a TypeElement, get a new one just in case it was thrown in a
// previous round we can report the correct instance. Otherwise, this leads to
// issues in AndroidStudio when linking an error to the proper element.
// TODO(bcorso): Consider only allowing TypeElement errors when delaying errors,
// or maybe even removing delayed errors altogether.
element =
- elements.getTypeElement(
- MoreElements.asType(element).getQualifiedName().toString());
+ processingEnv.requireTypeElement(asTypeElement(element).getQualifiedName());
}
messager.printMessage(Kind.ERROR, hiltError.message(), element);
} else {
@@ -104,23 +103,27 @@
}
}
+ public boolean isEmpty() {
+ return hiltErrors.isEmpty();
+ }
+
@AutoValue
abstract static class HiltError {
static HiltError of(String message) {
return of(message, Optional.empty());
}
- static HiltError of(String message, Element element) {
+ static HiltError of(String message, XElement element) {
return of(message, Optional.of(element));
}
- private static HiltError of(String message, Optional<Element> element) {
+ private static HiltError of(String message, Optional<XElement> element) {
return new AutoValue_ProcessorErrorHandler_HiltError(
FAILURE_PREFIX + message + FAILURE_SUFFIX, element);
}
abstract String message();
- abstract Optional<Element> element();
+ abstract Optional<XElement> element();
}
}
diff --git a/java/dagger/hilt/processor/internal/ProcessorErrors.java b/java/dagger/hilt/processor/internal/ProcessorErrors.java
index d75bb62..db1e979 100644
--- a/java/dagger/hilt/processor/internal/ProcessorErrors.java
+++ b/java/dagger/hilt/processor/internal/ProcessorErrors.java
@@ -16,18 +16,13 @@
package dagger.hilt.processor.internal;
-import com.google.auto.common.MoreTypes;
+
+import androidx.room.compiler.processing.XElement;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.FormatMethod;
import com.google.errorprone.annotations.FormatString;
import java.util.Collection;
-import java.util.stream.Collectors;
import javax.annotation.Nullable;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
/** Static helper methods for throwing errors during code generation. */
public final class ProcessorErrors {
@@ -40,9 +35,7 @@
* string using {@link String#valueOf(Object)}
* @throws BadInputException if {@code expression} is false
*/
- public static void checkState(
- boolean expression,
- @Nullable Object errorMessage) {
+ public static void checkState(boolean expression, @Nullable Object errorMessage) {
if (!expression) {
throw new BadInputException(String.valueOf(errorMessage));
}
@@ -85,9 +78,7 @@
* @throws BadInputException if {@code expression} is false
*/
public static void checkState(
- boolean expression,
- Element badElement,
- @Nullable Object errorMessage) {
+ boolean expression, XElement badElement, @Nullable Object errorMessage) {
Preconditions.checkNotNull(badElement);
if (!expression) {
throw new BadInputException(String.valueOf(errorMessage), badElement);
@@ -116,7 +107,7 @@
@FormatMethod
public static void checkState(
boolean expression,
- Element badElement,
+ XElement badElement,
@Nullable @FormatString String errorMessageTemplate,
@Nullable Object... errorMessageArgs) {
Preconditions.checkNotNull(badElement);
@@ -131,27 +122,6 @@
* involving any parameters to the calling method.
*
* @param expression a boolean expression
- * @param badElements the element that were at fault
- * @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,
- Collection<? extends Element> badElements,
- @Nullable Object errorMessage) {
- Preconditions.checkNotNull(badElements);
- if (!expression) {
- Preconditions.checkState(!badElements.isEmpty());
- throw new BadInputException(String.valueOf(errorMessage), badElements);
- }
- }
-
- /**
- * 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 badElements the elements that were at fault
* @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
@@ -164,10 +134,12 @@
* @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
* {@code errorMessageArgs} is null (don't let this happen)
*/
+ // TODO(bcorso): Rename this checkState once the javac API is removed (overloading doesn't work
+ // here since they have the same erasured signature).
@FormatMethod
- public static void checkState(
+ public static void checkStateX(
boolean expression,
- Collection<? extends Element> badElements,
+ Collection<? extends XElement> badElements,
@Nullable @FormatString String errorMessageTemplate,
@Nullable Object... errorMessageArgs) {
Preconditions.checkNotNull(badElements);
@@ -178,30 +150,5 @@
}
}
- /**
- * Ensures that the given element is not an error kind and does not inherit from an error kind.
- *
- * @param element the element to check
- * @throws ErrorTypeException if {@code element} inherits from an error kind.
- */
- public static void checkNotErrorKind(TypeElement element) {
- TypeMirror currType = element.asType();
- ImmutableList.Builder<String> typeHierarchy = ImmutableList.builder();
- while (currType.getKind() != TypeKind.NONE) {
- typeHierarchy.add(currType.toString());
- if (currType.getKind() == TypeKind.ERROR) {
- throw new ErrorTypeException(
- String.format(
- "%s, type hierarchy contains error kind, %s."
- + "\n\tThe partially resolved hierarchy is:\n\t\t%s",
- element,
- currType,
- typeHierarchy.build().stream().collect(Collectors.joining(" -> "))),
- element);
- }
- currType = MoreTypes.asTypeElement(currType).getSuperclass();
- }
- }
-
private ProcessorErrors() {}
}
diff --git a/java/dagger/hilt/processor/internal/Processors.java b/java/dagger/hilt/processor/internal/Processors.java
index 3fdb8c0..c843821 100644
--- a/java/dagger/hilt/processor/internal/Processors.java
+++ b/java/dagger/hilt/processor/internal/Processors.java
@@ -16,72 +16,45 @@
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 androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils.getMetadataUtil;
import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import static javax.lang.model.element.Modifier.ABSTRACT;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-import com.google.auto.common.AnnotationMirrors;
-import com.google.auto.common.GeneratedAnnotations;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XAnnotationValue;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XHasModifiers;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.CaseFormat;
-import com.google.common.base.Equivalence.Wrapper;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
-import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedHashMultimap;
-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;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtil;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils;
-import dagger.internal.codegen.extension.DaggerStreams;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.util.LinkedHashSet;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.internal.codegen.xprocessing.XTypes;
import java.util.List;
-import java.util.Map;
+import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
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.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ErrorType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.SimpleAnnotationValueVisitor7;
-import javax.lang.model.util.SimpleTypeVisitor7;
/** Static helper methods for writing a processor. */
public final class Processors {
@@ -90,386 +63,112 @@
public static final String STATIC_INITIALIZER_NAME = "<clinit>";
- private static final String JAVA_CLASS = "java.lang.Class";
-
+ /** Generates the aggregating metadata class for an aggregating annotation. */
public static void generateAggregatingClass(
String aggregatingPackage,
AnnotationSpec aggregatingAnnotation,
- TypeElement element,
- Class<?> generatedAnnotationClass,
- ProcessingEnvironment env) throws IOException {
- ClassName name = ClassName.get(aggregatingPackage, "_" + getFullEnclosedName(element));
+ XTypeElement originatingElement,
+ Class<?> generatorClass) {
+ generateAggregatingClass(
+ aggregatingPackage,
+ aggregatingAnnotation,
+ originatingElement,
+ generatorClass,
+ Mode.Isolating);
+ }
+
+ /** Generates the aggregating metadata class for an aggregating annotation. */
+ public static void generateAggregatingClass(
+ String aggregatingPackage,
+ AnnotationSpec aggregatingAnnotation,
+ XTypeElement originatingElement,
+ Class<?> generatorClass,
+ Mode mode) {
+ ClassName name =
+ ClassName.get(aggregatingPackage, "_" + getFullEnclosedName(originatingElement));
+ XProcessingEnv env = getProcessingEnv(originatingElement);
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");;
+ .addJavadoc("This class aggregates information across multiple compilations.\n");
+ JavaPoetExtKt.addOriginatingElement(builder, originatingElement);
+ addGeneratedAnnotation(builder, env, generatorClass);
- addGeneratedAnnotation(builder, env, generatedAnnotationClass);
-
- JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler());
+ env.getFiler().write(JavaFile.builder(name.packageName(), builder.build()).build(), mode);
}
- /** Returns a map from {@link AnnotationMirror} attribute name to {@link AnnotationValue}s */
- public static ImmutableMap<String, AnnotationValue> getAnnotationValues(Elements elements,
- AnnotationMirror annotation) {
- ImmutableMap.Builder<String, AnnotationValue> annotationMembers = ImmutableMap.builder();
- for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
- : elements.getElementValuesWithDefaults(annotation).entrySet()) {
- annotationMembers.put(e.getKey().getSimpleName().toString(), e.getValue());
+ /** Returns a map from {@link XAnnotation} attribute name to {@link XAnnotationValue}s */
+ public static ImmutableMap<String, XAnnotationValue> getAnnotationValues(XAnnotation annotation) {
+ ImmutableMap.Builder<String, XAnnotationValue> annotationMembers = ImmutableMap.builder();
+ for (XAnnotationValue value : annotation.getAnnotationValues()) {
+ annotationMembers.put(value.getName(), value);
}
return annotationMembers.build();
}
- /**
- * Returns a multimap from attribute name to the values that are an array of annotation mirrors.
- * The returned map will not contain mappings for any attributes that are not Annotation Arrays.
- *
- * <p>e.g. if the input was the annotation mirror for
- * <pre>
- * {@literal @}Foo({{@literal @}Bar("hello"), {@literal @}Bar("world")})
- * </pre>
- * the map returned would have "value" map to a set containing the two @Bar annotation mirrors.
- */
- public static Multimap<String, AnnotationMirror> getAnnotationAnnotationArrayValues(
- Elements elements, AnnotationMirror annotation) {
- SetMultimap<String, AnnotationMirror> annotationMembers = LinkedHashMultimap.create();
- for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
- : elements.getElementValuesWithDefaults(annotation).entrySet()) {
- String attribute = e.getKey().getSimpleName().toString();
- Set<AnnotationMirror> annotationMirrors = new LinkedHashSet<>();
- e.getValue().accept(new AnnotationMirrorAnnotationValueVisitor(), annotationMirrors);
- annotationMembers.putAll(attribute, annotationMirrors);
- }
- return annotationMembers;
- }
-
- private static final class AnnotationMirrorAnnotationValueVisitor
- extends SimpleAnnotationValueVisitor7<Void, Set<AnnotationMirror>> {
-
- @Override
- public Void visitArray(List<? extends AnnotationValue> vals, Set<AnnotationMirror> types) {
- for (AnnotationValue val : vals) {
- val.accept(this, types);
- }
- return null;
- }
-
- @Override
- public Void visitAnnotation(AnnotationMirror a, Set<AnnotationMirror> annotationMirrors) {
- annotationMirrors.add(a);
- return null;
- }
- }
-
- /** Returns the {@link TypeElement} for a class attribute on an annotation. */
- public static TypeElement getAnnotationClassValue(
- Elements elements, AnnotationMirror annotation, String key) {
- return Iterables.getOnlyElement(getAnnotationClassValues(elements, annotation, key));
- }
-
- /** Returns a list of {@link TypeElement}s for a class attribute on an annotation. */
- public static ImmutableList<TypeElement> getAnnotationClassValues(
- Elements elements, AnnotationMirror annotation, String key) {
- ImmutableList<TypeElement> values = getOptionalAnnotationClassValues(elements, annotation, key);
+ /** Returns a list of {@link XTypeElement}s for a class attribute on an annotation. */
+ public static ImmutableList<XTypeElement> getAnnotationClassValues(
+ XAnnotation annotation, String key) {
+ ImmutableList<XTypeElement> values = XAnnotations.getAsTypeElementList(annotation, key);
ProcessorErrors.checkState(
values.size() >= 1,
- // TODO(b/152801981): Point to the annotation value rather than the annotated element.
- annotation.getAnnotationType().asElement(),
+ annotation.getTypeElement(),
"@%s, '%s' class is invalid or missing: %s",
- annotation.getAnnotationType().asElement().getSimpleName(),
+ annotation.getName(),
key,
- annotation);
+ XAnnotations.toStableString(annotation));
return values;
}
- /** Returns a multimap from attribute name to elements for class valued attributes. */
- private static Multimap<String, DeclaredType> getAnnotationClassValues(
- Elements elements, AnnotationMirror annotation) {
- Element javaClass = elements.getTypeElement(JAVA_CLASS);
- SetMultimap<String, DeclaredType> annotationMembers = LinkedHashMultimap.create();
- for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e :
- elements.getElementValuesWithDefaults(annotation).entrySet()) {
- Optional<DeclaredType> returnType = getOptionalDeclaredType(e.getKey().getReturnType());
- if (returnType.isPresent() && returnType.get().asElement().equals(javaClass)) {
- String attribute = e.getKey().getSimpleName().toString();
- Set<DeclaredType> declaredTypes = new LinkedHashSet<DeclaredType>();
- e.getValue().accept(new DeclaredTypeAnnotationValueVisitor(), declaredTypes);
- annotationMembers.putAll(attribute, declaredTypes);
- }
- }
- return annotationMembers;
- }
-
- /** Returns an optional {@link TypeElement} for a class attribute on an annotation. */
- public static Optional<TypeElement> getOptionalAnnotationClassValue(
- Elements elements, AnnotationMirror annotation, String key) {
- return getAnnotationClassValues(elements, annotation).get(key).stream()
- .map(MoreTypes::asTypeElement)
- .collect(toOptional());
- }
-
- /** Returns a list of {@link TypeElement}s for a class attribute on an annotation. */
- public static ImmutableList<TypeElement> getOptionalAnnotationClassValues(
- Elements elements, AnnotationMirror annotation, String key) {
- return ImmutableList.copyOf(
- getAnnotationClassValues(elements, annotation).get(key).stream()
- .map(MoreTypes::asTypeElement)
- .collect(Collectors.toList()));
- }
-
- private static final class DeclaredTypeAnnotationValueVisitor
- extends SimpleAnnotationValueVisitor7<Void, Set<DeclaredType>> {
-
- @Override public Void visitArray(
- List<? extends AnnotationValue> vals, Set<DeclaredType> types) {
- for (AnnotationValue val : vals) {
- val.accept(this, types);
- }
- return null;
- }
-
- @Override public Void visitType(TypeMirror t, Set<DeclaredType> types) {
- DeclaredType declared = MoreTypes.asDeclared(t);
- checkNotNull(declared);
- types.add(declared);
- return null;
- }
- }
-
- /**
- * If the received mirror represents a primitive type or an array of primitive types, this returns
- * the represented primitive type. Otherwise throws an IllegalStateException.
- */
- public static PrimitiveType getPrimitiveType(TypeMirror type) {
- return type.accept(
- new SimpleTypeVisitor7<PrimitiveType, Void> () {
- @Override public PrimitiveType visitArray(ArrayType type, Void unused) {
- return getPrimitiveType(type.getComponentType());
- }
-
- @Override public PrimitiveType visitPrimitive(PrimitiveType type, Void unused) {
- return type;
- }
-
- @Override public PrimitiveType defaultAction(TypeMirror type, Void unused) {
- throw new IllegalStateException("Unhandled type: " + type);
- }
- }, null /* the Void accumulator */);
- }
-
- /**
- * Returns an {@link Optional#of} the declared type if the received mirror represents a declared
- * type or an array of declared types, otherwise returns {@link Optional#empty}.
- */
- public static Optional<DeclaredType> getOptionalDeclaredType(TypeMirror type) {
- return Optional.ofNullable(
- type.accept(
- new SimpleTypeVisitor7<DeclaredType, Void>(null /* defaultValue */) {
- @Override
- public DeclaredType visitArray(ArrayType type, Void unused) {
- return MoreTypes.asDeclared(type.getComponentType());
+ public static ImmutableList<XTypeElement> getOptionalAnnotationClassValues(
+ XAnnotation annotation, String key) {
+ return getOptionalAnnotationValues(annotation, key).stream()
+ .filter(XAnnotationValue::hasTypeValue)
+ .map(
+ annotationValue -> {
+ try {
+ return annotationValue.asType();
+ } catch (TypeNotPresentException e) {
+ // TODO(b/277367118): we may need a way to ignore error types in XProcessing.
+ // TODO(b/278560196): we should throw ErrorTypeException and clean up broken tests.
+ return null;
}
-
- @Override
- public DeclaredType visitDeclared(DeclaredType type, Void unused) {
- return type;
- }
-
- @Override
- public DeclaredType visitError(ErrorType type, Void unused) {
- return type;
- }
- },
- null /* the Void accumulator */));
+ })
+ .filter(Objects::nonNull)
+ .map(XType::getTypeElement)
+ .collect(toImmutableList());
}
- /**
- * Returns the declared type if the received mirror represents a declared type or an array of
- * declared types, otherwise throws an {@link IllegalStateException}.
- */
- public static DeclaredType getDeclaredType(TypeMirror type) {
- return getOptionalDeclaredType(type)
- .orElseThrow(() -> new IllegalStateException("Not a declared type: " + type));
+ private static ImmutableList<XAnnotationValue> getOptionalAnnotationValues(
+ XAnnotation annotation, String key) {
+ return annotation.getAnnotationValues().stream()
+ .filter(annotationValue -> annotationValue.getName().equals(key))
+ .collect(toOptional())
+ .map(
+ annotationValue ->
+ (annotationValue.hasListValue()
+ ? ImmutableList.copyOf(annotationValue.asAnnotationValueList())
+ : ImmutableList.of(annotationValue)))
+ .orElse(ImmutableList.of());
}
- /** Gets the values from an annotation value representing a string array. */
- public static ImmutableList<String> getStringArrayAnnotationValue(AnnotationValue value) {
- return value.accept(new SimpleAnnotationValueVisitor7<ImmutableList<String>, Void>() {
- @Override
- public ImmutableList<String> defaultAction(Object o, Void unused) {
- throw new IllegalStateException("Expected an array, got instead: " + o);
- }
-
- @Override
- public ImmutableList<String> visitArray(List<? extends AnnotationValue> values,
- Void unused) {
- ImmutableList.Builder<String> builder = ImmutableList.builder();
- for (AnnotationValue value : values) {
- builder.add(getStringAnnotationValue(value));
- }
- return builder.build();
- }
- }, /* unused accumulator */ null);
- }
-
- /** Gets the values from an annotation value representing an int. */
- public static Boolean getBooleanAnnotationValue(AnnotationValue value) {
- return value.accept(
- new SimpleAnnotationValueVisitor7<Boolean, Void>() {
- @Override
- public Boolean defaultAction(Object o, Void unused) {
- throw new IllegalStateException("Expected a boolean, got instead: " + o);
- }
-
- @Override
- public Boolean visitBoolean(boolean value, Void unused) {
- return value;
- }
- }, /* unused accumulator */
- null);
- }
-
- /** Gets the values from an annotation value representing an int. */
- public static Integer getIntAnnotationValue(AnnotationValue value) {
- return value.accept(new SimpleAnnotationValueVisitor7<Integer, Void>() {
- @Override
- public Integer defaultAction(Object o, Void unused) {
- throw new IllegalStateException("Expected an int, got instead: " + o);
- }
-
- @Override
- public Integer visitInt(int value, Void unused) {
- return value;
- }
- }, /* unused accumulator */ null);
- }
-
- /** Gets the values from an annotation value representing a long. */
- public static Long getLongAnnotationValue(AnnotationValue value) {
- return value.accept(
- new SimpleAnnotationValueVisitor7<Long, Void>() {
- @Override
- public Long defaultAction(Object o, Void unused) {
- throw new IllegalStateException("Expected an int, got instead: " + o);
- }
-
- @Override
- public Long visitLong(long value, Void unused) {
- return value;
- }
- },
- null /* unused accumulator */);
- }
-
- /** Gets the values from an annotation value representing a string. */
- public static String getStringAnnotationValue(AnnotationValue value) {
- return value.accept(new SimpleAnnotationValueVisitor7<String, Void>() {
- @Override
- public String defaultAction(Object o, Void unused) {
- throw new IllegalStateException("Expected a string, got instead: " + o);
- }
-
- @Override
- public String visitString(String value, Void unused) {
- return value;
- }
- }, /* unused accumulator */ null);
- }
-
- /** Gets the values from an annotation value representing a DeclaredType. */
- public static DeclaredType getDeclaredTypeAnnotationValue(AnnotationValue value) {
- return value.accept(
- new SimpleAnnotationValueVisitor7<DeclaredType, Void>() {
- @Override
- public DeclaredType defaultAction(Object o, Void unused) {
- throw new IllegalStateException("Expected a TypeMirror, got instead: " + o);
- }
-
- @Override
- public DeclaredType visitType(TypeMirror typeMirror, Void unused) {
- return MoreTypes.asDeclared(typeMirror);
- }
- }, /* unused accumulator */
- null);
- }
-
- private static final SimpleAnnotationValueVisitor7<ImmutableSet<VariableElement>, Void>
- ENUM_ANNOTATION_VALUE_VISITOR =
- new SimpleAnnotationValueVisitor7<ImmutableSet<VariableElement>, Void>() {
- @Override
- public ImmutableSet<VariableElement> defaultAction(Object o, Void unused) {
- throw new IllegalStateException(
- "Expected an Enum or an Enum array, got instead: " + o);
- }
-
- @Override
- public ImmutableSet<VariableElement> visitArray(
- List<? extends AnnotationValue> values, Void unused) {
- ImmutableSet.Builder<VariableElement> builder = ImmutableSet.builder();
- for (AnnotationValue value : values) {
- builder.addAll(value.accept(this, null));
- }
- return builder.build();
- }
-
- @Override
- public ImmutableSet<VariableElement> visitEnumConstant(
- VariableElement value, Void unused) {
- return ImmutableSet.of(value);
- }
- };
-
- /** Gets the values from an annotation value representing a Enum array. */
- public static ImmutableSet<VariableElement> getEnumArrayAnnotationValue(AnnotationValue value) {
- return value.accept(ENUM_ANNOTATION_VALUE_VISITOR, /* unused accumulator */ null);
- }
-
- /** Converts an annotation value map to be keyed by the attribute name. */
- public static ImmutableMap<String, AnnotationValue> convertToAttributeNameMap(
- Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues) {
- ImmutableMap.Builder<String, AnnotationValue> builder = ImmutableMap.builder();
- for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> e
- : annotationValues.entrySet()) {
- String attribute = e.getKey().getSimpleName().toString();
- builder.put(attribute, e.getValue());
- }
- return builder.build();
- }
-
- /** Returns the given elements containing package element. */
- public static PackageElement getPackageElement(Element originalElement) {
+ public static XTypeElement getTopLevelType(XElement originalElement) {
checkNotNull(originalElement);
- for (Element e = originalElement; e != null; e = e.getEnclosingElement()) {
- if (e instanceof PackageElement) {
- return (PackageElement) e;
- }
- }
- throw new IllegalStateException("Cannot find a package for " + originalElement);
- }
-
- public static TypeElement getTopLevelType(Element originalElement) {
- checkNotNull(originalElement);
- for (Element e = originalElement; e != null; e = e.getEnclosingElement()) {
+ for (XElement e = originalElement; e != null; e = e.getEnclosingElement()) {
if (isTopLevel(e)) {
- return MoreElements.asType(e);
+ return XElements.asTypeElement(e);
}
}
- throw new IllegalStateException("Cannot find a top-level type for " + originalElement);
+ throw new IllegalStateException(
+ "Cannot find a top-level type for " + XElements.toStableString(originalElement));
}
- /** Returns true if the given element is a top-level element. */
- public static boolean isTopLevel(Element element) {
- return element.getEnclosingElement().getKind() == ElementKind.PACKAGE;
- }
-
- /** Returns true if the given element is annotated with the given annotation. */
- public static boolean hasAnnotation(Element element, Class<? extends Annotation> annotation) {
- return element.getAnnotation(annotation) != null;
+ public static boolean isTopLevel(XElement element) {
+ return element.getEnclosingElement() == null;
}
/** Returns true if the given element has an annotation with the given class name. */
@@ -477,41 +176,27 @@
return getAnnotationMirrorOptional(element, className).isPresent();
}
- /** Returns true if the given element has an annotation with the given class name. */
- public static boolean hasAnnotation(AnnotationMirror mirror, ClassName className) {
- return hasAnnotation(mirror.getAnnotationType().asElement(), className);
- }
-
- /** Returns true if the given element is annotated with the given annotation. */
- public static boolean hasAnnotation(
- AnnotationMirror mirror, Class<? extends Annotation> annotation) {
- return hasAnnotation(mirror.getAnnotationType().asElement(), annotation);
- }
-
/** Returns true if the given element has an annotation that is an error kind. */
- public static boolean hasErrorTypeAnnotation(Element element) {
- for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
- if (annotationMirror.getAnnotationType().getKind() == TypeKind.ERROR) {
+ public static boolean hasErrorTypeAnnotation(XElement element) {
+ for (XAnnotation annotation : element.getAllAnnotations()) {
+ if (annotation.getType().isError()) {
return true;
}
}
return false;
}
-
/**
- * Returns all elements in the round that are annotated with at least 1 of the given
- * annotations.
+ * Returns the annotation mirror from the given element that corresponds to the given class.
+ *
+ * @throws IllegalArgumentException if 2 or more annotations are found.
+ * @return {@link Optional#empty()} if no annotation is found on the element.
*/
- @SafeVarargs
- public static ImmutableSet<Element> getElementsAnnotatedWith(RoundEnvironment roundEnv,
- Class<? extends Annotation>... annotations) {
- ImmutableSet.Builder<Element> builder = ImmutableSet.builder();
- for (Class<? extends Annotation> annotation : annotations){
- builder.addAll(roundEnv.getElementsAnnotatedWith(annotation));
- }
-
- return builder.build();
+ static Optional<AnnotationMirror> getAnnotationMirrorOptional(
+ Element element, ClassName className) {
+ return element.getAnnotationMirrors().stream()
+ .filter(mirror -> ClassName.get(mirror.getAnnotationType()).equals(className))
+ .collect(toOptional());
}
/**
@@ -522,11 +207,6 @@
return Joiner.on('_').join(name.simpleNames());
}
- /** Returns the name of a class. See {@link #getEnclosedName(ClassName)}. */
- public static String getEnclosedName(TypeElement element) {
- return getEnclosedName(ClassName.get(element));
- }
-
/**
* Returns an equivalent class name with the {@code .} (dots) used for inner classes replaced with
* {@code _}.
@@ -539,13 +219,8 @@
* 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);
+ public static ClassName getEnclosedClassName(XTypeElement typeElement) {
+ return getEnclosedClassName(typeElement.getClassName());
}
/**
@@ -553,18 +228,19 @@
* elements, this continues to append the simple name of elements. For example,
* foo_bar_Outer_Inner_fooMethod.
*/
- public static String getFullEnclosedName(Element element) {
+ public static String getFullEnclosedName(XElement element) {
Preconditions.checkNotNull(element);
String qualifiedName = "";
while (element != null) {
- if (element.getKind().equals(ElementKind.PACKAGE)) {
- qualifiedName = asPackage(element).getQualifiedName() + qualifiedName;
+ if (element.getEnclosingElement() == null) {
+ qualifiedName =
+ element.getClosestMemberContainer().asClassName().getCanonicalName() + qualifiedName;
} else {
// This check is needed to keep the name stable when compiled with jdk8 vs jdk11. jdk11
- // contains newly added "module" enclosing elements of packages, which adds an addtional "_"
- // prefix to the name due to an empty module element compared with jdk8.
- if (!element.getSimpleName().toString().isEmpty()) {
- qualifiedName = "." + element.getSimpleName() + qualifiedName;
+ // contains newly added "module" enclosing elements of packages, which adds an additional
+ // "_" prefix to the name due to an empty module element compared with jdk8.
+ if (!XElements.getSimpleName(element).isEmpty()) {
+ qualifiedName = "." + XElements.getSimpleName(element) + qualifiedName;
}
}
element = element.getEnclosingElement();
@@ -587,85 +263,53 @@
*
* @throws BadInputException if the simple name of {@code type} does not end with {@code suffix}
*/
- public static ClassName removeNameSuffix(TypeElement type, String suffix) {
- ClassName originalName = ClassName.get(type);
+ public static ClassName removeNameSuffix(XTypeElement type, String suffix) {
+ ClassName originalName = type.getClassName();
String originalSimpleName = originalName.simpleName();
- ProcessorErrors.checkState(originalSimpleName.endsWith(suffix),
- type, "Name of type %s must end with '%s'", originalName, suffix);
+ ProcessorErrors.checkState(
+ originalSimpleName.endsWith(suffix),
+ type,
+ "Name of type %s must end with '%s'",
+ originalName,
+ suffix);
String withoutSuffix =
originalSimpleName.substring(0, originalSimpleName.length() - suffix.length());
return originalName.peerClass(withoutSuffix);
}
- /** @see #getAnnotationMirror(Element, ClassName) */
- public static AnnotationMirror getAnnotationMirror(
- Element element, Class<? extends Annotation> annotationClass) {
- return getAnnotationMirror(element, ClassName.get(annotationClass));
- }
-
- /**
- * Returns the annotation mirror from the given element that corresponds to the given class.
- *
- * @throws IllegalStateException if the given element isn't annotated with that annotation.
- */
- public static AnnotationMirror getAnnotationMirror(Element element, ClassName className) {
- Optional<AnnotationMirror> annotationMirror = getAnnotationMirrorOptional(element, className);
- if (annotationMirror.isPresent()) {
- return annotationMirror.get();
- } else {
- throw new IllegalStateException(
- String.format(
- "Couldn't find annotation %s on element %s. Found annotations: %s",
- className, element.getSimpleName(), element.getAnnotationMirrors()));
- }
- }
-
- /**
- * Returns the annotation mirror from the given element that corresponds to the given class.
- *
- * @throws {@link IllegalArgumentException} if 2 or more annotations are found.
- * @return {@link Optional#empty()} if no annotation is found on the element.
- */
- static Optional<AnnotationMirror> getAnnotationMirrorOptional(
- Element element, ClassName className) {
- return element.getAnnotationMirrors().stream()
- .filter(mirror -> ClassName.get(mirror.getAnnotationType()).equals(className))
- .collect(toOptional());
- }
-
- /** @return true if element inherits directly or indirectly from the className */
- public static boolean isAssignableFrom(TypeElement element, ClassName className) {
+ /** Returns {@code true} if element inherits directly or indirectly from the className. */
+ public static boolean isAssignableFrom(XTypeElement element, ClassName className) {
return isAssignableFromAnyOf(element, ImmutableSet.of(className));
}
- /** @return true if element inherits directly or indirectly from any of the classNames */
- public static boolean isAssignableFromAnyOf(TypeElement element,
- ImmutableSet<ClassName> classNames) {
+ /** Returns {@code true} if element inherits directly or indirectly from any of the classNames. */
+ public static boolean isAssignableFromAnyOf(
+ XTypeElement element, ImmutableSet<ClassName> classNames) {
for (ClassName className : classNames) {
- if (ClassName.get(element).equals(className)) {
+ if (element.getClassName().equals(className)) {
return true;
}
}
- TypeMirror superClass = element.getSuperclass();
+ XType superClass = element.getSuperClass();
// None type is returned if this is an interface or Object
// Error type is returned for classes that are generated by this processor
- if ((superClass.getKind() != TypeKind.NONE) && (superClass.getKind() != TypeKind.ERROR)) {
- Preconditions.checkState(superClass.getKind() == TypeKind.DECLARED);
- if (isAssignableFromAnyOf(MoreTypes.asTypeElement(superClass), classNames)) {
+ if (superClass != null && !superClass.isNone() && !superClass.isError()) {
+ Preconditions.checkState(XTypes.isDeclared(superClass));
+ if (isAssignableFromAnyOf(superClass.getTypeElement(), classNames)) {
return true;
}
}
- for (TypeMirror iface : element.getInterfaces()) {
+ for (XType iface : element.getSuperInterfaces()) {
// Skip errors and keep looking. This is especially needed for classes generated by this
// processor.
- if (iface.getKind() == TypeKind.ERROR) {
+ if (iface.isError()) {
continue;
}
- Preconditions.checkState(iface.getKind() == TypeKind.DECLARED,
- "Interface type is %s", iface.getKind());
- if (isAssignableFromAnyOf(MoreTypes.asTypeElement(iface), classNames)) {
+ Preconditions.checkState(
+ XTypes.isDeclared(iface), "Interface type is %s", XTypes.getKindName(iface));
+ if (isAssignableFromAnyOf(iface.getTypeElement(), classNames)) {
return true;
}
}
@@ -673,215 +317,23 @@
return false;
}
- /** Returns methods from a given TypeElement, not including constructors. */
- public static ImmutableList<ExecutableElement> getMethods(TypeElement element) {
- ImmutableList.Builder<ExecutableElement> builder = ImmutableList.builder();
- for (Element e : element.getEnclosedElements()) {
- // Only look for executable elements, not fields, etc
- if (e instanceof ExecutableElement) {
- ExecutableElement method = (ExecutableElement) e;
- if (!method.getSimpleName().contentEquals(CONSTRUCTOR_NAME)
- && !method.getSimpleName().contentEquals(STATIC_INITIALIZER_NAME)) {
- builder.add(method);
- }
- }
- }
- return builder.build();
- }
-
- public static ImmutableList<ExecutableElement> getConstructors(TypeElement element) {
- ImmutableList.Builder<ExecutableElement> builder = ImmutableList.builder();
- for (Element enclosed : element.getEnclosedElements()) {
- // Only look for executable elements, not fields, etc
- if (enclosed instanceof ExecutableElement) {
- ExecutableElement method = (ExecutableElement) enclosed;
- if (method.getSimpleName().contentEquals(CONSTRUCTOR_NAME)) {
- builder.add(method);
- }
- }
- }
- return builder.build();
- }
-
- /**
- * Returns all transitive methods from a given TypeElement, not including constructors. Also does
- * not include methods from Object or that override methods on Object.
- */
- public static ImmutableList<ExecutableElement> getAllMethods(TypeElement element) {
- ImmutableList.Builder<ExecutableElement> builder = ImmutableList.builder();
- builder.addAll(
- Iterables.filter(
- getMethods(element),
- method -> {
- return !isObjectMethod(method);
- }));
- TypeMirror superclass = element.getSuperclass();
- if (superclass.getKind() != TypeKind.NONE) {
- TypeElement superclassElement = MoreTypes.asTypeElement(superclass);
- builder.addAll(getAllMethods(superclassElement));
- }
- for (TypeMirror iface : element.getInterfaces()) {
- builder.addAll(getAllMethods(MoreTypes.asTypeElement(iface)));
- }
- return builder.build();
- }
-
- /** Checks that the given element is not the error type. */
- public static void checkForCompilationError(TypeElement e) {
- ProcessorErrors.checkState(e.asType().getKind() != TypeKind.ERROR, e,
- "Unable to resolve the type %s. Look for compilation errors above related to this type.",
- e);
- }
-
- private static void addInterfaceMethods(
- TypeElement type, ImmutableList.Builder<ExecutableElement> interfaceMethods) {
- for (TypeMirror interfaceMirror : type.getInterfaces()) {
- TypeElement interfaceElement = MoreTypes.asTypeElement(interfaceMirror);
- interfaceMethods.addAll(getMethods(interfaceElement));
- addInterfaceMethods(interfaceElement, interfaceMethods);
- }
- }
-
- /**
- * Finds methods of interfaces implemented by {@code type}. This method also checks the
- * superinterfaces of those interfaces. This method does not check the interfaces of any
- * superclass of {@code type}.
- */
- public static ImmutableList<ExecutableElement> methodsOnInterfaces(TypeElement type) {
- ImmutableList.Builder<ExecutableElement> interfaceMethods = new ImmutableList.Builder<>();
- addInterfaceMethods(type, interfaceMethods);
- return interfaceMethods.build();
- }
-
/** Returns MapKey annotated annotations found on an element. */
- public static ImmutableList<AnnotationMirror> getMapKeyAnnotations(Element element) {
- ImmutableSet<? extends AnnotationMirror> mapKeys =
- AnnotationMirrors.getAnnotatedAnnotations(element, ClassNames.MAP_KEY.canonicalName());
+ public static ImmutableList<XAnnotation> getMapKeyAnnotations(XElement element) {
// Normally, we wouldn't need to handle Kotlin metadata because map keys are typically used
// only on methods. However, with @BindValueIntoMap, this can be used on fields so we need
// to check annotations on the property as well, just like with qualifiers.
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- if (element.getKind() == ElementKind.FIELD
- // static fields are generally not supported, no need to get map keys from Kotlin metadata
- && !element.getModifiers().contains(STATIC)
- && metadataUtil.hasMetadata(element)) {
- VariableElement fieldElement = asVariable(element);
- return Stream.concat(
- mapKeys.stream(),
- metadataUtil.isMissingSyntheticPropertyForAnnotations(fieldElement)
- ? Stream.empty()
- : metadataUtil
- .getSyntheticPropertyAnnotations(fieldElement, ClassNames.MAP_KEY)
- .stream())
- .map(AnnotationMirrors.equivalence()::wrap)
- .distinct()
- .map(Wrapper::get)
- .collect(DaggerStreams.toImmutableList());
- } else {
- return ImmutableList.copyOf(mapKeys);
- }
+ return getMetadataUtil().getAnnotationsAnnotatedWith(element, ClassNames.MAP_KEY);
}
/** Returns Qualifier annotated annotations found on an element. */
- public static ImmutableList<AnnotationMirror> getQualifierAnnotations(Element element) {
- // TODO(bcorso): Consolidate this logic with InjectionAnnotations in Dagger
- ImmutableSet<? extends AnnotationMirror> qualifiers =
- AnnotationMirrors.getAnnotatedAnnotations(element, ClassNames.QUALIFIER.canonicalName());
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- if (element.getKind() == ElementKind.FIELD
- // static fields are generally not supported, no need to get qualifier from kotlin metadata
- && !element.getModifiers().contains(STATIC)
- && metadataUtil.hasMetadata(element)) {
- VariableElement fieldElement = asVariable(element);
- return Stream.concat(
- qualifiers.stream(),
- metadataUtil.isMissingSyntheticPropertyForAnnotations(fieldElement)
- ? Stream.empty()
- : metadataUtil
- .getSyntheticPropertyAnnotations(fieldElement, ClassNames.QUALIFIER)
- .stream())
- .map(AnnotationMirrors.equivalence()::wrap)
- .distinct()
- .map(Wrapper::get)
- .collect(DaggerStreams.toImmutableList());
- } else {
- return ImmutableList.copyOf(qualifiers);
- }
+ public static ImmutableList<XAnnotation> getQualifierAnnotations(XElement element) {
+ return getMetadataUtil().getAnnotationsAnnotatedWith(element, ClassNames.QUALIFIER);
}
/** Returns Scope annotated annotations found on an element. */
- public static ImmutableList<AnnotationMirror> getScopeAnnotations(Element element) {
- return getAnnotationsAnnotatedWith(element, ClassNames.SCOPE);
- }
-
- /** Returns annotations of element that are annotated with subAnnotation */
- public static ImmutableList<AnnotationMirror> getAnnotationsAnnotatedWith(
- Element element, ClassName subAnnotation) {
- ImmutableList.Builder<AnnotationMirror> builder = ImmutableList.builder();
- element.getAnnotationMirrors().stream()
- .filter(annotation -> hasAnnotation(annotation, subAnnotation))
- .forEach(builder::add);
- return builder.build();
- }
-
- /** Returns true if there are any annotations of element that are annotated with subAnnotation */
- public static boolean hasAnnotationsAnnotatedWith(Element element, ClassName subAnnotation) {
- return !getAnnotationsAnnotatedWith(element, subAnnotation).isEmpty();
- }
-
- /**
- * Returns true iff the given {@code method} is one of the public or protected methods on {@link
- * Object}, or an overridden version thereof.
- *
- * <p>This method ignores the return type of the given method, but this is generally fine since
- * two methods which only differ by their return type will cause a compiler error. (e.g. a
- * non-static method with the signature {@code int equals(Object)})
- */
- public static boolean isObjectMethod(ExecutableElement method) {
- // First check if this method is directly defined on Object
- Element enclosingElement = method.getEnclosingElement();
- if (enclosingElement.getKind() == ElementKind.CLASS
- && TypeName.get(enclosingElement.asType()).equals(TypeName.OBJECT)) {
- return true;
- }
-
- if (method.getModifiers().contains(Modifier.STATIC)) {
- return false;
- }
- switch (method.getSimpleName().toString()) {
- case "equals":
- return (method.getParameters().size() == 1)
- && (method.getParameters().get(0).asType().toString().equals("java.lang.Object"));
- case "hashCode":
- case "toString":
- case "clone":
- case "getClass":
- case "notify":
- case "notifyAll":
- case "finalize":
- return method.getParameters().isEmpty();
- case "wait":
- if (method.getParameters().isEmpty()) {
- return true;
- } else if ((method.getParameters().size() == 1)
- && (method.getParameters().get(0).asType().toString().equals("long"))) {
- return true;
- } else if ((method.getParameters().size() == 2)
- && (method.getParameters().get(0).asType().toString().equals("long"))
- && (method.getParameters().get(1).asType().toString().equals("int"))) {
- return true;
- }
- return false;
- default:
- return false;
- }
- }
-
- public static ParameterSpec parameterSpecFromVariableElement(VariableElement element) {
- return ParameterSpec.builder(
- ClassName.get(element.asType()),
- upperToLowerCamel(element.getSimpleName().toString()))
- .build();
+ public static ImmutableList<XAnnotation> getScopeAnnotations(XElement element) {
+ return ImmutableList.copyOf(
+ element.getAnnotationsAnnotatedWith(ClassNames.SCOPE));
}
/**
@@ -914,78 +366,62 @@
.addTypeVariables(methodSpec.typeVariables);
}
- /** @return A method spec for an empty constructor (useful for abstract Dagger modules). */
- public static MethodSpec privateEmptyConstructor() {
- return MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build();
- }
-
/**
- * Returns true if the given method is annotated with one of the annotations Dagger recognizes
- * for abstract methods (e.g. @Binds).
+ * Returns true if the given method is annotated with one of the annotations Dagger recognizes for
+ * abstract methods (e.g. @Binds).
*/
- public static boolean hasDaggerAbstractMethodAnnotation(ExecutableElement method) {
- return hasAnnotation(method, ClassNames.BINDS)
- || hasAnnotation(method, ClassNames.BINDS_OPTIONAL_OF)
- || hasAnnotation(method, ClassNames.MULTIBINDS)
- || hasAnnotation(method, ClassNames.CONTRIBUTES_ANDROID_INJECTOR);
+ public static boolean hasDaggerAbstractMethodAnnotation(XExecutableElement method) {
+ return method.hasAnnotation(ClassNames.BINDS)
+ || method.hasAnnotation(ClassNames.BINDS_OPTIONAL_OF)
+ || method.hasAnnotation(ClassNames.MULTIBINDS)
+ || method.hasAnnotation(ClassNames.CONTRIBUTES_ANDROID_INJECTOR);
}
- public static ImmutableSet<TypeElement> toTypeElements(Elements elements, String[] classes) {
- return FluentIterable.from(classes).transform(elements::getTypeElement).toSet();
- }
-
- public static ImmutableSet<ClassName> toClassNames(Iterable<TypeElement> elements) {
- return FluentIterable.from(elements).transform(ClassName::get).toSet();
- }
-
- public static boolean requiresModuleInstance(Elements elements, TypeElement module) {
+ public static boolean requiresModuleInstance(XTypeElement module) {
// Binding methods that lack ABSTRACT or STATIC require module instantiation.
// Required by Dagger. See b/31489617.
- 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);
+ return module.getDeclaredMethods().stream()
+ .filter(Processors::isBindingMethod)
+ .anyMatch(method -> !method.isAbstract() && !method.isStatic())
+ && !module.isKotlinObject();
}
- public static boolean hasVisibleEmptyConstructor(TypeElement type) {
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
+ public static boolean hasVisibleEmptyConstructor(XTypeElement type) {
+ List<XConstructorElement> constructors = type.getConstructors();
return constructors.isEmpty()
|| constructors.stream()
.filter(constructor -> constructor.getParameters().isEmpty())
.anyMatch(
constructor ->
- !constructor.getModifiers().contains(Modifier.PRIVATE)
+ !constructor.isPrivate()
);
}
- private static boolean isBindingMethod(ExecutableElement method) {
- return hasAnnotation(method, ClassNames.PROVIDES)
- || hasAnnotation(method, ClassNames.BINDS)
- || hasAnnotation(method, ClassNames.BINDS_OPTIONAL_OF)
- || hasAnnotation(method, ClassNames.MULTIBINDS);
+ private static boolean isBindingMethod(XExecutableElement method) {
+ return method.hasAnnotation(ClassNames.PROVIDES)
+ || method.hasAnnotation(ClassNames.BINDS)
+ || method.hasAnnotation(ClassNames.BINDS_OPTIONAL_OF)
+ || method.hasAnnotation(ClassNames.MULTIBINDS);
}
public static void addGeneratedAnnotation(
- TypeSpec.Builder typeSpecBuilder, ProcessingEnvironment env, Class<?> generatorClass) {
+ TypeSpec.Builder typeSpecBuilder, XProcessingEnv env, Class<?> generatorClass) {
addGeneratedAnnotation(typeSpecBuilder, env, generatorClass.getName());
}
public static void addGeneratedAnnotation(
- TypeSpec.Builder typeSpecBuilder, ProcessingEnvironment env, String generatorClass) {
- GeneratedAnnotations.generatedAnnotation(env.getElementUtils(), env.getSourceVersion())
- .ifPresent(
- annotation ->
- typeSpecBuilder.addAnnotation(
- AnnotationSpec.builder(ClassName.get(annotation))
- .addMember("value", "$S", generatorClass)
- .build()));
+ TypeSpec.Builder typeSpecBuilder, XProcessingEnv env, String generatorClass) {
+ XTypeElement annotation = env.findGeneratedAnnotation();
+ if (annotation != null) {
+ typeSpecBuilder.addAnnotation(
+ AnnotationSpec.builder(annotation.getClassName())
+ .addMember("value", "$S", generatorClass)
+ .build());
+ }
}
- public static AnnotationSpec getOriginatingElementAnnotation(TypeElement element) {
- TypeName rawType = rawTypeName(ClassName.get(getTopLevelType(element)));
+ public static AnnotationSpec getOriginatingElementAnnotation(XTypeElement element) {
+ TypeName rawType = rawTypeName(getTopLevelType(element).getClassName());
return AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
.addMember("topLevelClass", "$T.class", rawType)
.build();
@@ -1001,27 +437,29 @@
: 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))
+ public static Optional<XTypeElement> getOriginatingTestElement(XElement element) {
+ XTypeElement topLevelType = getOriginatingTopLevelType(element);
+ return topLevelType.hasAnnotation(ClassNames.HILT_ANDROID_TEST)
+ ? Optional.of(topLevelType)
: Optional.empty();
}
- private static TypeElement getOriginatingTopLevelType(Element element, Elements elements) {
- TypeElement topLevelType = getTopLevelType(element);
- if (hasAnnotation(topLevelType, ClassNames.ORIGINATING_ELEMENT)) {
+ private static XTypeElement getOriginatingTopLevelType(XElement element) {
+ XTypeElement topLevelType = getTopLevelType(element);
+ if (topLevelType.hasAnnotation(ClassNames.ORIGINATING_ELEMENT)) {
return getOriginatingTopLevelType(
- getAnnotationClassValue(
- elements,
- getAnnotationMirror(topLevelType, ClassNames.ORIGINATING_ELEMENT),
- "topLevelClass"),
- elements);
+ XAnnotations.getAsTypeElement(
+ topLevelType.getAnnotation(ClassNames.ORIGINATING_ELEMENT), "topLevelClass"));
}
-
return topLevelType;
}
+ public static boolean hasJavaPackagePrivateVisibility(XHasModifiers element) {
+ return !element.isPrivate()
+ && !element.isProtected()
+ && !element.isInternal()
+ && !element.isPublic();
+ }
+
private Processors() {}
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java
index 84fb5a1..4068ac7 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java
@@ -16,14 +16,12 @@
package dagger.hilt.processor.internal.aggregateddeps;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
import java.util.Optional;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
/**
* Generates the @AggregatedDeps annotated class used to pass information
@@ -35,30 +33,27 @@
ClassName.get("dagger.hilt.processor.internal.aggregateddeps", "AggregatedDeps");
private final String dependencyType;
- private final TypeElement dependency;
+ private final XTypeElement dependency;
private final Optional<ClassName> testName;
private final ImmutableSet<ClassName> components;
private final ImmutableSet<ClassName> replacedDependencies;
- private final ProcessingEnvironment processingEnv;
AggregatedDepsGenerator(
String dependencyType,
- TypeElement dependency,
+ XTypeElement dependency,
Optional<ClassName> testName,
ImmutableSet<ClassName> components,
- ImmutableSet<ClassName> replacedDependencies,
- ProcessingEnvironment processingEnv) {
+ ImmutableSet<ClassName> replacedDependencies) {
this.dependencyType = dependencyType;
this.dependency = dependency;
this.testName = testName;
this.components = components;
this.replacedDependencies = replacedDependencies;
- this.processingEnv = processingEnv;
}
- void generate() throws IOException {
+ void generate() {
Processors.generateAggregatingClass(
- AGGREGATING_PACKAGE, aggregatedDepsAnnotation(), dependency, getClass(), processingEnv);
+ AGGREGATING_PACKAGE, aggregatedDepsAnnotation(), dependency, getClass());
}
private AnnotationSpec aggregatedDepsAnnotation() {
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
index bc7a4d2..840ba9c 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsMetadata.java
@@ -16,26 +16,24 @@
package dagger.hilt.processor.internal.aggregateddeps;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
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 androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XAnnotationValue;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
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 dagger.hilt.processor.internal.root.ir.AggregatedDepsIr;
import java.util.Optional;
import java.util.stream.Collectors;
-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
@@ -52,97 +50,93 @@
}
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
- public abstract Optional<TypeElement> testElement();
+ public abstract Optional<XTypeElement> testElement();
- public abstract ImmutableSet<TypeElement> componentElements();
+ public abstract ImmutableSet<XTypeElement> componentElements();
abstract DependencyType dependencyType();
- public abstract TypeElement dependency();
+ public abstract XTypeElement dependency();
- public abstract ImmutableSet<TypeElement> replacedDependencies();
+ public abstract ImmutableSet<XTypeElement> replacedDependencies();
public boolean isModule() {
return dependencyType() == DependencyType.MODULE;
}
/** Returns metadata for all aggregated elements in the aggregating package. */
- public static ImmutableSet<AggregatedDepsMetadata> from(Elements elements) {
- return from(
- AggregatedElements.from(AGGREGATED_DEPS_PACKAGE, ClassNames.AGGREGATED_DEPS, elements),
- elements);
+ public static ImmutableSet<AggregatedDepsMetadata> from(XProcessingEnv env) {
+ return from(AggregatedElements.from(AGGREGATED_DEPS_PACKAGE, ClassNames.AGGREGATED_DEPS, env));
}
/** Returns metadata for each aggregated element. */
public static ImmutableSet<AggregatedDepsMetadata> from(
- ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ ImmutableSet<XTypeElement> aggregatedElements) {
return aggregatedElements.stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ .map(aggregatedElement -> create(aggregatedElement, getProcessingEnv(aggregatedElement)))
.collect(toImmutableSet());
}
public static AggregatedDepsIr toIr(AggregatedDepsMetadata metadata) {
return new AggregatedDepsIr(
- ClassName.get(metadata.aggregatingElement()),
+ metadata.aggregatingElement().getClassName(),
metadata.componentElements().stream()
- .map(ClassName::get)
+ .map(XTypeElement::getClassName)
.map(ClassName::canonicalName)
.collect(Collectors.toList()),
- metadata.testElement()
- .map(ClassName::get)
+ metadata
+ .testElement()
+ .map(XTypeElement::getClassName)
.map(ClassName::canonicalName)
.orElse(null),
metadata.replacedDependencies().stream()
- .map(ClassName::get)
+ .map(XTypeElement::getClassName)
.map(ClassName::canonicalName)
.collect(Collectors.toList()),
metadata.dependencyType() == DependencyType.MODULE
- ? ClassName.get(metadata.dependency()).canonicalName()
+ ? metadata.dependency().getClassName().canonicalName()
: null,
metadata.dependencyType() == DependencyType.ENTRY_POINT
- ? ClassName.get(metadata.dependency()).canonicalName()
+ ? metadata.dependency().getClassName().canonicalName()
: null,
metadata.dependencyType() == DependencyType.COMPONENT_ENTRY_POINT
- ? ClassName.get(metadata.dependency()).canonicalName()
+ ? metadata.dependency().getClassName().canonicalName()
: null);
}
- private static AggregatedDepsMetadata create(TypeElement element, Elements elements) {
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_DEPS);
-
- ImmutableMap<String, AnnotationValue> values =
- Processors.getAnnotationValues(elements, annotationMirror);
+ private static AggregatedDepsMetadata create(XTypeElement element, XProcessingEnv env) {
+ XAnnotation annotation = element.getAnnotation(ClassNames.AGGREGATED_DEPS);
return new AutoValue_AggregatedDepsMetadata(
element,
- getTestElement(values.get("test"), elements),
- getComponents(values.get("components"), elements),
+ getTestElement(annotation.getAnnotationValue("test"), env),
+ getComponents(annotation.getAnnotationValue("components"), env),
getDependencyType(
- values.get("modules"), values.get("entryPoints"), values.get("componentEntryPoints")),
+ annotation.getAnnotationValue("modules"),
+ annotation.getAnnotationValue("entryPoints"),
+ annotation.getAnnotationValue("componentEntryPoints")),
getDependency(
- values.get("modules"),
- values.get("entryPoints"),
- values.get("componentEntryPoints"),
- elements),
- getReplacedDependencies(values.get("replaces"), elements));
+ annotation.getAnnotationValue("modules"),
+ annotation.getAnnotationValue("entryPoints"),
+ annotation.getAnnotationValue("componentEntryPoints"),
+ env),
+ getReplacedDependencies(annotation.getAnnotationValue("replaces"), env));
}
- private static Optional<TypeElement> getTestElement(
- AnnotationValue testValue, Elements elements) {
+ private static Optional<XTypeElement> getTestElement(
+ XAnnotationValue testValue, XProcessingEnv env) {
checkNotNull(testValue);
- String test = AnnotationValues.getString(testValue);
- return test.isEmpty() ? Optional.empty() : Optional.of(elements.getTypeElement(test));
+ String test = testValue.asString();
+ return test.isEmpty() ? Optional.empty() : Optional.of(env.findTypeElement(test));
}
- private static ImmutableSet<TypeElement> getComponents(
- AnnotationValue componentsValue, Elements elements) {
+ private static ImmutableSet<XTypeElement> getComponents(
+ XAnnotationValue componentsValue, XProcessingEnv env) {
checkNotNull(componentsValue);
- ImmutableSet<TypeElement> componentNames =
- AnnotationValues.getAnnotationValues(componentsValue).stream()
- .map(AnnotationValues::getString)
+ ImmutableSet<XTypeElement> componentNames =
+ componentsValue.asStringList().stream()
.map(
// This is a temporary hack to map the old ApplicationComponent to the new
// SingletonComponent. Technically, this is only needed for backwards compatibility
@@ -153,71 +147,70 @@
"dagger.hilt.android.components.ApplicationComponent")
? ClassNames.SINGLETON_COMPONENT.canonicalName()
: componentName)
- .map(elements::getTypeElement)
+ .map(env::requireTypeElement)
.collect(toImmutableSet());
checkState(!componentNames.isEmpty());
return componentNames;
}
private static DependencyType getDependencyType(
- AnnotationValue modulesValue,
- AnnotationValue entryPointsValue,
- AnnotationValue componentEntryPointsValue) {
+ XAnnotationValue modulesValue,
+ XAnnotationValue entryPointsValue,
+ XAnnotationValue componentEntryPointsValue) {
checkNotNull(modulesValue);
checkNotNull(entryPointsValue);
checkNotNull(componentEntryPointsValue);
ImmutableSet.Builder<DependencyType> dependencyTypes = ImmutableSet.builder();
- if (!AnnotationValues.getAnnotationValues(modulesValue).isEmpty()) {
+ if (!modulesValue.asAnnotationValueList().isEmpty()) {
dependencyTypes.add(DependencyType.MODULE);
}
- if (!AnnotationValues.getAnnotationValues(entryPointsValue).isEmpty()) {
+ if (!entryPointsValue.asAnnotationValueList().isEmpty()) {
dependencyTypes.add(DependencyType.ENTRY_POINT);
}
- if (!AnnotationValues.getAnnotationValues(componentEntryPointsValue).isEmpty()) {
+ if (!componentEntryPointsValue.asAnnotationValueList().isEmpty()) {
dependencyTypes.add(DependencyType.COMPONENT_ENTRY_POINT);
}
return getOnlyElement(dependencyTypes.build());
}
- private static TypeElement getDependency(
- AnnotationValue modulesValue,
- AnnotationValue entryPointsValue,
- AnnotationValue componentEntryPointsValue,
- Elements elements) {
+ private static XTypeElement getDependency(
+ XAnnotationValue modulesValue,
+ XAnnotationValue entryPointsValue,
+ XAnnotationValue componentEntryPointsValue,
+ XProcessingEnv env) {
checkNotNull(modulesValue);
checkNotNull(entryPointsValue);
checkNotNull(componentEntryPointsValue);
String dependencyName =
- AnnotationValues.getString(
- getOnlyElement(
- ImmutableSet.<AnnotationValue>builder()
- .addAll(AnnotationValues.getAnnotationValues(modulesValue))
- .addAll(AnnotationValues.getAnnotationValues(entryPointsValue))
- .addAll(AnnotationValues.getAnnotationValues(componentEntryPointsValue))
- .build()));
- TypeElement dependency = elements.getTypeElement(dependencyName);
+ getOnlyElement(
+ ImmutableSet.<XAnnotationValue>builder()
+ .addAll(modulesValue.asAnnotationValueList())
+ .addAll(entryPointsValue.asAnnotationValueList())
+ .addAll(componentEntryPointsValue.asAnnotationValueList())
+ .build())
+ .asString();
+ XTypeElement dependency = env.findTypeElement(dependencyName);
checkNotNull(dependency, "Could not get element for %s", dependencyName);
return dependency;
}
- private static ImmutableSet<TypeElement> getReplacedDependencies(
- AnnotationValue replacedDependenciesValue, Elements elements) {
+ private static ImmutableSet<XTypeElement> getReplacedDependencies(
+ XAnnotationValue replacedDependenciesValue, XProcessingEnv env) {
// 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))
+ : replacedDependenciesValue.asStringList().stream()
+ .map(env::requireTypeElement)
+ .map(replacedDep -> getPublicDependency(replacedDep, env))
.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()))
+ private static XTypeElement getPublicDependency(XTypeElement dependency, XProcessingEnv env) {
+ return PkgPrivateMetadata.of(dependency, ClassNames.MODULE)
+ .map(metadata -> env.requireTypeElement(metadata.generatedClassName().toString()))
.orElse(dependency);
}
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessingStep.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessingStep.java
new file mode 100644
index 0000000..f19ec74
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessingStep.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2019 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.collect.Iterables.getOnlyElement;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.isModuleInstallInCheckDisabled;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XElementKt;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.Components;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.extension.DaggerStreams;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+/** Processor that outputs dummy files to propagate information through multiple javac runs. */
+public final class AggregatedDepsProcessingStep extends BaseProcessingStep {
+
+ 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);
+
+ private static final ImmutableSet<ClassName> MODULE_ANNOTATIONS =
+ ImmutableSet.of(
+ ClassNames.MODULE);
+
+ private static final ImmutableSet<ClassName> INSTALL_IN_ANNOTATIONS =
+ ImmutableSet.of(ClassNames.INSTALL_IN, ClassNames.TEST_INSTALL_IN);
+
+ private final Set<XElement> seen = new HashSet<>();
+
+ public AggregatedDepsProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.<ClassName>builder()
+ .addAll(INSTALL_IN_ANNOTATIONS)
+ .addAll(MODULE_ANNOTATIONS)
+ .addAll(ENTRY_POINT_ANNOTATIONS)
+ .build();
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) throws Exception {
+ if (!seen.add(element)) {
+ return;
+ }
+
+ Optional<ClassName> installInAnnotation = getAnnotation(element, INSTALL_IN_ANNOTATIONS);
+ Optional<ClassName> entryPointAnnotation = getAnnotation(element, ENTRY_POINT_ANNOTATIONS);
+ Optional<ClassName> moduleAnnotation = getAnnotation(element, MODULE_ANNOTATIONS);
+
+ boolean hasInstallIn = installInAnnotation.isPresent();
+ boolean isEntryPoint = entryPointAnnotation.isPresent();
+ boolean isModule = moduleAnnotation.isPresent();
+
+ ProcessorErrors.checkState(
+ !hasInstallIn || isEntryPoint || isModule,
+ element,
+ "@%s-annotated classes must also be annotated with @Module or @EntryPoint: %s",
+ installInAnnotation.map(ClassName::simpleName).orElse("@InstallIn"),
+ XElements.toStableString(element));
+
+ ProcessorErrors.checkState(
+ !(isEntryPoint && isModule),
+ element,
+ "@%s and @%s cannot be used on the same interface: %s",
+ moduleAnnotation.map(ClassName::simpleName).orElse("@Module"),
+ entryPointAnnotation.map(ClassName::simpleName).orElse("@EntryPoint"),
+ XElements.toStableString(element));
+
+ if (isModule) {
+ processModule(element, installInAnnotation, moduleAnnotation.get());
+ } else if (isEntryPoint) {
+ processEntryPoint(element, installInAnnotation, entryPointAnnotation.get());
+ } else {
+ throw new AssertionError();
+ }
+ }
+
+ private void processModule(
+ XElement element, Optional<ClassName> installInAnnotation, ClassName moduleAnnotation)
+ throws Exception {
+ ProcessorErrors.checkState(
+ installInAnnotation.isPresent()
+ || isDaggerGeneratedModule(element)
+ || installInCheckDisabled(element),
+ element,
+ "%s is missing an @InstallIn annotation. If this was intentional, see"
+ + " https://dagger.dev/hilt/flags#disable-install-in-check for how to disable this"
+ + " check.",
+ XElements.toStableString(element));
+
+ if (!installInAnnotation.isPresent()) {
+ // Modules without @InstallIn or @TestInstallIn annotations don't need to be processed further
+ return;
+ }
+
+ ProcessorErrors.checkState(
+ XElementKt.isTypeElement(element),
+ element,
+ "Only classes and interfaces can be annotated with @Module: %s",
+ XElements.toStableString(element));
+
+ XTypeElement module = XElements.asTypeElement(element);
+
+ ProcessorErrors.checkState(
+ module.isClass() || module.isInterface() || module.isKotlinObject(),
+ module,
+ "Only classes and interfaces can be annotated with @Module: %s",
+ XElements.toStableString(module));
+
+ ProcessorErrors.checkState(
+ Processors.isTopLevel(module)
+ || module.isStatic()
+ || module.isAbstract()
+ || module.getEnclosingElement().hasAnnotation(ClassNames.HILT_ANDROID_TEST),
+ module,
+ "Nested @%s modules must be static unless they are directly nested within a test. "
+ + "Found: %s",
+ installInAnnotation.get().simpleName(),
+ XElements.toStableString(module));
+
+ // 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(module.getClassName())
+ || !Processors.requiresModuleInstance(module)
+ || Processors.hasVisibleEmptyConstructor(module),
+ module,
+ "Modules that need to be instantiated by Hilt must have a visible, empty constructor.");
+
+ // TODO(b/28989613): This should really be fixed in Dagger. Remove once Dagger bug is fixed.
+ ImmutableList<XExecutableElement> abstractMethodsWithMissingBinds =
+ module.getDeclaredMethods().stream()
+ .filter(XMethodElement::isAbstract)
+ .filter(method -> !Processors.hasDaggerAbstractMethodAnnotation(method))
+ .collect(toImmutableList());
+ ProcessorErrors.checkState(
+ abstractMethodsWithMissingBinds.isEmpty(),
+ module,
+ "Found unimplemented abstract methods, %s, in an abstract module, %s. "
+ + "Did you forget to add a Dagger binding annotation (e.g. @Binds)?",
+ abstractMethodsWithMissingBinds.stream()
+ .map(XElements::toStableString)
+ .collect(DaggerStreams.toImmutableList()),
+ XElements.toStableString(module));
+
+ ImmutableList<XTypeElement> replacedModules = ImmutableList.of();
+ if (module.hasAnnotation(ClassNames.TEST_INSTALL_IN)) {
+ Optional<XTypeElement> originatingTestElement = Processors.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",
+ originatingTestElement.map(XTypeElement::getQualifiedName).orElse(""));
+
+ XAnnotation testInstallIn = module.getAnnotation(ClassNames.TEST_INSTALL_IN);
+ replacedModules = Processors.getAnnotationClassValues(testInstallIn, "replaces");
+
+ ProcessorErrors.checkState(
+ !replacedModules.isEmpty(),
+ // TODO(b/152801981): this should really error on the annotation value
+ module,
+ "@TestInstallIn#replaces() cannot be empty. Use @InstallIn instead.");
+
+ ImmutableList<XTypeElement> nonInstallInModules =
+ replacedModules.stream()
+ .filter(replacedModule -> !replacedModule.hasAnnotation(ClassNames.INSTALL_IN))
+ .collect(toImmutableList());
+
+ ProcessorErrors.checkState(
+ nonInstallInModules.isEmpty(),
+ // TODO(b/152801981): this should really error on the annotation value
+ module,
+ "@TestInstallIn#replaces() can only contain @InstallIn modules, but found: %s",
+ nonInstallInModules.stream()
+ .map(XElements::toStableString)
+ .collect(DaggerStreams.toImmutableList()));
+
+ ImmutableList<XTypeElement> hiltWrapperModules =
+ replacedModules.stream()
+ .filter(
+ replacedModule ->
+ replacedModule.getClassName().simpleName().startsWith("HiltWrapper_"))
+ .collect(toImmutableList());
+
+ ProcessorErrors.checkState(
+ hiltWrapperModules.isEmpty(),
+ // TODO(b/152801981): this should really error on the annotation value
+ module,
+ "@TestInstallIn#replaces() cannot contain Hilt generated public wrapper modules, "
+ + "but found: %s. ",
+ hiltWrapperModules.stream()
+ .map(XElements::toStableString)
+ .collect(DaggerStreams.toImmutableList()));
+
+ if (!module.getPackageName().startsWith("dagger.hilt")) {
+ // Prevent external users from overriding Hilt's internal modules. Techincally, except for
+ // ApplicationContextModule, making all modules pkg-private should be enough but this is an
+ // extra measure of precaution.
+ ImmutableList<XTypeElement> hiltInternalModules =
+ replacedModules.stream()
+ .filter(replacedModule -> replacedModule.getPackageName().startsWith("dagger.hilt"))
+ .collect(toImmutableList());
+
+ ProcessorErrors.checkState(
+ hiltInternalModules.isEmpty(),
+ // TODO(b/152801981): this should really error on the annotation value
+ module,
+ "@TestInstallIn#replaces() cannot contain internal Hilt modules, but found: %s. ",
+ hiltInternalModules.stream()
+ .map(XElements::toStableString)
+ .collect(DaggerStreams.toImmutableList()));
+ }
+
+ // Prevent users from uninstalling test-specific @InstallIn modules.
+ ImmutableList<XTypeElement> replacedTestSpecificInstallIn =
+ replacedModules.stream()
+ .filter(
+ replacedModule ->
+ Processors.getOriginatingTestElement(replacedModule).isPresent())
+ .collect(toImmutableList());
+
+ ProcessorErrors.checkState(
+ replacedTestSpecificInstallIn.isEmpty(),
+ // TODO(b/152801981): this should really error on the annotation value
+ module,
+ "@TestInstallIn#replaces() cannot replace test specific @InstallIn modules, but found: "
+ + "%s. Please remove the @InstallIn module manually rather than replacing it.",
+ replacedTestSpecificInstallIn.stream()
+ .map(XElements::toStableString)
+ .collect(DaggerStreams.toImmutableList()));
+ }
+
+ generateAggregatedDeps(
+ "modules",
+ module,
+ moduleAnnotation,
+ replacedModules.stream().map(XTypeElement::getClassName).collect(toImmutableSet()));
+ }
+
+ private void processEntryPoint(
+ XElement element, Optional<ClassName> installInAnnotation, ClassName entryPointAnnotation)
+ throws Exception {
+ ProcessorErrors.checkState(
+ installInAnnotation.isPresent() ,
+ element,
+ "@%s %s must also be annotated with @InstallIn",
+ entryPointAnnotation.simpleName(),
+ XElements.toStableString(element));
+
+ ProcessorErrors.checkState(
+ !element.hasAnnotation(ClassNames.TEST_INSTALL_IN),
+ element,
+ "@TestInstallIn can only be used with modules");
+
+ ProcessorErrors.checkState(
+ XElementKt.isTypeElement(element) && XElements.asTypeElement(element).isInterface(),
+ element,
+ "Only interfaces can be annotated with @%s: %s",
+ entryPointAnnotation.simpleName(),
+ XElements.toStableString(element));
+ XTypeElement entryPoint = XElements.asTypeElement(element);
+
+ if (entryPointAnnotation.equals(ClassNames.EARLY_ENTRY_POINT)) {
+ ImmutableSet<ClassName> components = Components.getComponents(element);
+ ProcessorErrors.checkState(
+ components.equals(ImmutableSet.of(ClassNames.SINGLETON_COMPONENT)),
+ element,
+ "@EarlyEntryPoint can only be installed into the SingletonComponent. Found: %s",
+ components);
+
+ Optional<XTypeElement> optionalTestElement = Processors.getOriginatingTestElement(element);
+ 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.",
+ entryPoint.getQualifiedName(),
+ optionalTestElement.map(testElement -> testElement.getQualifiedName()).orElse(""));
+ }
+
+ generateAggregatedDeps(
+ entryPointAnnotation.equals(ClassNames.COMPONENT_ENTRY_POINT)
+ ? "componentEntryPoints"
+ : "entryPoints",
+ entryPoint,
+ entryPointAnnotation,
+ ImmutableSet.of());
+ }
+
+ private void generateAggregatedDeps(
+ String key,
+ XTypeElement element,
+ ClassName annotation,
+ ImmutableSet<ClassName> replacedModules)
+ throws Exception {
+ // Get @InstallIn components here to catch errors before skipping user's pkg-private element.
+ ImmutableSet<ClassName> components = Components.getComponents(element);
+
+ if (isValidKind(element)) {
+ Optional<PkgPrivateMetadata> pkgPrivateMetadata = PkgPrivateMetadata.of(element, annotation);
+ if (pkgPrivateMetadata.isPresent()) {
+ if (key.contentEquals("modules")) {
+ new PkgPrivateModuleGenerator(processingEnv(), pkgPrivateMetadata.get()).generate();
+ } else {
+ new PkgPrivateEntryPointGenerator(processingEnv(), pkgPrivateMetadata.get()).generate();
+ }
+ } else {
+ Optional<ClassName> testName =
+ Processors.getOriginatingTestElement(element).map(XTypeElement::getClassName);
+ new AggregatedDepsGenerator(key, element, testName, components, replacedModules).generate();
+ }
+ }
+ }
+
+ private static Optional<ClassName> getAnnotation(
+ XElement element, ImmutableSet<ClassName> annotations) {
+ ImmutableSet<ClassName> usedAnnotations =
+ annotations.stream().filter(element::hasAnnotation).collect(toImmutableSet());
+
+ if (usedAnnotations.isEmpty()) {
+ return Optional.empty();
+ }
+
+ ProcessorErrors.checkState(
+ usedAnnotations.size() == 1,
+ element,
+ "Only one of the following annotations can be used on %s: %s",
+ XElements.toStableString(element),
+ usedAnnotations);
+
+ return Optional.of(getOnlyElement(usedAnnotations));
+ }
+
+ private static boolean isValidKind(XElement 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.
+ return !XElements.asTypeElement(element).getType().isError();
+ }
+
+ private boolean installInCheckDisabled(XElement element) {
+ return isModuleInstallInCheckDisabled(processingEnv())
+ || element.hasAnnotation(ClassNames.DISABLE_INSTALL_IN_CHECK);
+ }
+
+ /**
+ * When using Dagger Producers, don't process generated modules. They will not have the expected
+ * annotations.
+ */
+ private static boolean isDaggerGeneratedModule(XElement element) {
+ if (!element.hasAnnotation(ClassNames.MODULE)) {
+ return false;
+ }
+ return element.getAllAnnotations().stream()
+ .filter(annotation -> isGenerated(annotation))
+ .map(annotation -> getOnlyElement(annotation.getAsStringList("value")))
+ .anyMatch(value -> value.startsWith("dagger"));
+ }
+
+ private static boolean isGenerated(XAnnotation annotation) {
+ String name = annotation.getTypeElement().getQualifiedName();
+
+ return name.equals("javax.annotation.Generated")
+ || name.equals("javax.annotation.processing.Generated");
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
index 184894a..73cbc59 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
@@ -16,431 +16,20 @@
package dagger.hilt.processor.internal.aggregateddeps;
-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.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.lang.model.element.ElementKind.CLASS;
-import static javax.lang.model.element.ElementKind.INTERFACE;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.STATIC;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
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.Components;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processor that outputs dummy files to propagate information through multiple javac runs. */
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-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);
-
- private static final ImmutableSet<ClassName> MODULE_ANNOTATIONS =
- ImmutableSet.of(
- ClassNames.MODULE);
-
- private static final ImmutableSet<ClassName> INSTALL_IN_ANNOTATIONS =
- ImmutableSet.of(ClassNames.INSTALL_IN, ClassNames.TEST_INSTALL_IN);
-
- private final Set<Element> seen = new HashSet<>();
-
+public final class AggregatedDepsProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.builder()
- .addAll(INSTALL_IN_ANNOTATIONS)
- .addAll(MODULE_ANNOTATIONS)
- .addAll(ENTRY_POINT_ANNOTATIONS)
- .build()
- .stream()
- .map(Object::toString)
- .collect(toImmutableSet());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- if (!seen.add(element)) {
- return;
- }
-
- Optional<ClassName> installInAnnotation = getAnnotation(element, INSTALL_IN_ANNOTATIONS);
- Optional<ClassName> entryPointAnnotation = getAnnotation(element, ENTRY_POINT_ANNOTATIONS);
- Optional<ClassName> moduleAnnotation = getAnnotation(element, MODULE_ANNOTATIONS);
-
- boolean hasInstallIn = installInAnnotation.isPresent();
- boolean isEntryPoint = entryPointAnnotation.isPresent();
- boolean isModule = moduleAnnotation.isPresent();
-
- ProcessorErrors.checkState(
- !hasInstallIn || isEntryPoint || isModule,
- element,
- "@%s-annotated classes must also be annotated with @Module or @EntryPoint: %s",
- installInAnnotation.map(ClassName::simpleName).orElse("@InstallIn"),
- element);
-
- ProcessorErrors.checkState(
- !(isEntryPoint && isModule),
- element,
- "@%s and @%s cannot be used on the same interface: %s",
- moduleAnnotation.map(ClassName::simpleName).orElse("@Module"),
- entryPointAnnotation.map(ClassName::simpleName).orElse("@EntryPoint"),
- element);
-
- if (isModule) {
- processModule(element, installInAnnotation, moduleAnnotation.get());
- } else if (isEntryPoint) {
- processEntryPoint(element, installInAnnotation, entryPointAnnotation.get());
- } else {
- throw new AssertionError();
- }
- }
-
- private void processModule(
- Element element, Optional<ClassName> installInAnnotation, ClassName moduleAnnotation)
- throws Exception {
- ProcessorErrors.checkState(
- installInAnnotation.isPresent()
- || isDaggerGeneratedModule(element)
- || installInCheckDisabled(element),
- element,
- "%s is missing an @InstallIn annotation. If this was intentional, see"
- + " https://dagger.dev/hilt/flags#disable-install-in-check for how to disable this"
- + " check.",
- element);
-
- if (!installInAnnotation.isPresent()) {
- // Modules without @InstallIn or @TestInstallIn annotations don't need to be processed further
- return;
- }
-
- ProcessorErrors.checkState(
- element.getKind() == CLASS || element.getKind() == INTERFACE,
- element,
- "Only classes and interfaces can be annotated with @Module: %s",
- element);
- TypeElement module = asType(element);
-
- ProcessorErrors.checkState(
- Processors.isTopLevel(module)
- || module.getModifiers().contains(STATIC)
- || module.getModifiers().contains(ABSTRACT)
- || Processors.hasAnnotation(module.getEnclosingElement(), ClassNames.HILT_ANDROID_TEST),
- module,
- "Nested @%s modules must be static unless they are directly nested within a test. "
- + "Found: %s",
- installInAnnotation.get().simpleName(),
- module);
-
- // 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)
- || Processors.hasVisibleEmptyConstructor(module),
- module,
- "Modules that need to be instantiated by Hilt must have a visible, empty constructor.");
-
- // TODO(b/28989613): This should really be fixed in Dagger. Remove once Dagger bug is fixed.
- ImmutableList<ExecutableElement> abstractMethodsWithMissingBinds =
- ElementFilter.methodsIn(module.getEnclosedElements()).stream()
- .filter(method -> method.getModifiers().contains(ABSTRACT))
- .filter(method -> !Processors.hasDaggerAbstractMethodAnnotation(method))
- .collect(toImmutableList());
- ProcessorErrors.checkState(
- abstractMethodsWithMissingBinds.isEmpty(),
- module,
- "Found unimplemented abstract methods, %s, in an abstract module, %s. "
- + "Did you forget to add a Dagger binding annotation (e.g. @Binds)?",
- abstractMethodsWithMissingBinds,
- module);
-
- ImmutableList<TypeElement> replacedModules = ImmutableList.of();
- if (Processors.hasAnnotation(module, ClassNames.TEST_INSTALL_IN)) {
- Optional<TypeElement> originatingTestElement =
- Processors.getOriginatingTestElement(module, getElementUtils());
- 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",
- originatingTestElement
- .map(testElement -> testElement.getQualifiedName().toString())
- .orElse(""));
-
- AnnotationMirror testInstallIn =
- Processors.getAnnotationMirror(module, ClassNames.TEST_INSTALL_IN);
- replacedModules =
- Processors.getAnnotationClassValues(getElementUtils(), testInstallIn, "replaces");
-
- ProcessorErrors.checkState(
- !replacedModules.isEmpty(),
- // TODO(b/152801981): this should really error on the annotation value
- module,
- "@TestInstallIn#replaces() cannot be empty. Use @InstallIn instead.");
-
- ImmutableList<TypeElement> nonInstallInModules =
- replacedModules.stream()
- .filter(
- replacedModule ->
- !Processors.hasAnnotation(replacedModule, ClassNames.INSTALL_IN))
- .collect(toImmutableList());
-
- ProcessorErrors.checkState(
- nonInstallInModules.isEmpty(),
- // TODO(b/152801981): this should really error on the annotation value
- module,
- "@TestInstallIn#replaces() can only contain @InstallIn modules, but found: %s",
- nonInstallInModules);
-
- ImmutableList<TypeElement> hiltWrapperModules =
- replacedModules.stream()
- .filter(
- replacedModule ->
- replacedModule.getSimpleName().toString().startsWith("HiltWrapper_"))
- .collect(toImmutableList());
-
- ProcessorErrors.checkState(
- hiltWrapperModules.isEmpty(),
- // TODO(b/152801981): this should really error on the annotation value
- module,
- "@TestInstallIn#replaces() cannot contain Hilt generated public wrapper modules, "
- + "but found: %s. ",
- hiltWrapperModules);
-
- if (!getPackage(module).getQualifiedName().toString().startsWith("dagger.hilt")) {
- // Prevent external users from overriding Hilt's internal modules. Techincally, except for
- // ApplicationContextModule, making all modules pkg-private should be enough but this is an
- // extra measure of precaution.
- ImmutableList<TypeElement> hiltInternalModules =
- replacedModules.stream()
- .filter(
- replacedModule ->
- getPackage(replacedModule)
- .getQualifiedName()
- .toString()
- .startsWith("dagger.hilt"))
- .collect(toImmutableList());
-
- ProcessorErrors.checkState(
- hiltInternalModules.isEmpty(),
- // TODO(b/152801981): this should really error on the annotation value
- module,
- "@TestInstallIn#replaces() cannot contain internal Hilt modules, but found: %s. ",
- hiltInternalModules);
- }
-
- // Prevent users from uninstalling test-specific @InstallIn modules.
- ImmutableList<TypeElement> replacedTestSpecificInstallIn =
- replacedModules.stream()
- .filter(
- replacedModule ->
- Processors.getOriginatingTestElement(replacedModule, getElementUtils())
- .isPresent())
- .collect(toImmutableList());
-
- ProcessorErrors.checkState(
- replacedTestSpecificInstallIn.isEmpty(),
- // TODO(b/152801981): this should really error on the annotation value
- module,
- "@TestInstallIn#replaces() cannot replace test specific @InstallIn modules, but found: "
- + "%s. Please remove the @InstallIn module manually rather than replacing it.",
- replacedTestSpecificInstallIn);
- }
-
- generateAggregatedDeps(
- "modules",
- module,
- moduleAnnotation,
- replacedModules.stream().map(ClassName::get).collect(toImmutableSet()));
- }
-
- private void processEntryPoint(
- Element element, Optional<ClassName> installInAnnotation, ClassName entryPointAnnotation)
- throws Exception {
- ProcessorErrors.checkState(
- installInAnnotation.isPresent() ,
- element,
- "@%s %s must also be annotated with @InstallIn",
- entryPointAnnotation.simpleName(),
- element);
-
- ProcessorErrors.checkState(
- !Processors.hasAnnotation(element, ClassNames.TEST_INSTALL_IN),
- element,
- "@TestInstallIn can only be used with modules");
-
- ProcessorErrors.checkState(
- element.getKind() == INTERFACE,
- element,
- "Only interfaces can be annotated with @%s: %s",
- entryPointAnnotation.simpleName(),
- 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"
- : "entryPoints",
- entryPoint,
- entryPointAnnotation,
- ImmutableSet.of());
- }
-
- private void generateAggregatedDeps(
- String key,
- TypeElement element,
- ClassName annotation,
- ImmutableSet<ClassName> replacedModules)
- throws Exception {
- // Get @InstallIn components here to catch errors before skipping user's pkg-private element.
- ImmutableSet<ClassName> components = Components.getComponents(getElementUtils(), element);
-
- if (isValidKind(element)) {
- Optional<PkgPrivateMetadata> pkgPrivateMetadata =
- PkgPrivateMetadata.of(getElementUtils(), element, annotation);
- if (pkgPrivateMetadata.isPresent()) {
- if (key.contentEquals("modules")) {
- new PkgPrivateModuleGenerator(getProcessingEnv(), pkgPrivateMetadata.get()).generate();
- } else {
- new PkgPrivateEntryPointGenerator(getProcessingEnv(), pkgPrivateMetadata.get())
- .generate();
- }
- } else {
- Optional<ClassName> testName =
- Processors.getOriginatingTestElement(element, getElementUtils()).map(ClassName::get);
- new AggregatedDepsGenerator(
- key, element, testName, components, replacedModules, getProcessingEnv())
- .generate();
- }
- }
- }
-
- private static Optional<ClassName> getAnnotation(
- Element element, ImmutableSet<ClassName> annotations) {
- ImmutableSet<ClassName> usedAnnotations =
- annotations.stream()
- .filter(annotation -> Processors.hasAnnotation(element, annotation))
- .collect(toImmutableSet());
-
- if (usedAnnotations.isEmpty()) {
- return Optional.empty();
- }
-
- ProcessorErrors.checkState(
- usedAnnotations.size() == 1,
- element,
- "Only one of the following annotations can be used on %s: %s",
- element,
- usedAnnotations);
-
- return Optional.of(getOnlyElement(usedAnnotations));
- }
-
- 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.
- return element.asType().getKind() != TypeKind.ERROR;
- }
-
- private boolean installInCheckDisabled(Element element) {
- return isModuleInstallInCheckDisabled(getProcessingEnv())
- || Processors.hasAnnotation(element, ClassNames.DISABLE_INSTALL_IN_CHECK);
- }
-
- /**
- * When using Dagger Producers, don't process generated modules. They will not have the expected
- * annotations.
- */
- private static boolean isDaggerGeneratedModule(Element element) {
- if (!Processors.hasAnnotation(element, ClassNames.MODULE)) {
- return false;
- }
- return element.getAnnotationMirrors().stream()
- .filter(mirror -> isGenerated(mirror))
- .map(mirror -> asString(getOnlyElement(asList(getAnnotationValue(mirror, "value")))))
- .anyMatch(value -> value.startsWith("dagger"));
- }
-
- private static List<? extends AnnotationValue> asList(AnnotationValue value) {
- return value.accept(
- new SimpleAnnotationValueVisitor8<List<? extends AnnotationValue>, Void>() {
- @Override
- public List<? extends AnnotationValue> visitArray(
- List<? extends AnnotationValue> value, Void unused) {
- return value;
- }
- },
- null);
- }
-
- private static String asString(AnnotationValue value) {
- return value.accept(
- new SimpleAnnotationValueVisitor8<String, Void>() {
- @Override
- public String visitString(String value, Void unused) {
- return value;
- }
- },
- null);
- }
-
- private static boolean isGenerated(AnnotationMirror annotationMirror) {
- Name name = asType(annotationMirror.getAnnotationType().asElement()).getQualifiedName();
- return name.contentEquals("javax.annotation.Generated")
- || name.contentEquals("javax.annotation.processing.Generated");
+ protected BaseProcessingStep processingStep() {
+ return new AggregatedDepsProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
index 257e312..2d1bd92 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -37,7 +37,9 @@
name = "processor_lib",
srcs = [
"AggregatedDepsGenerator.java",
+ "AggregatedDepsProcessingStep.java",
"AggregatedDepsProcessor.java",
+ "KspAggregatedDepsProcessor.java",
"PkgPrivateEntryPointGenerator.java",
"PkgPrivateModuleGenerator.java",
],
@@ -50,11 +52,12 @@
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -64,10 +67,10 @@
deps = [
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/hilt/processor/internal/kotlin",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -87,6 +90,7 @@
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
index ed71c98..14ae03d 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
@@ -19,6 +19,8 @@
import static com.google.common.base.Preconditions.checkState;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
@@ -27,8 +29,6 @@
import dagger.hilt.processor.internal.ComponentDescriptor;
import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
/** Represents information needed to create a component (i.e. modules, entry points, etc) */
@AutoValue
@@ -38,21 +38,21 @@
}
/** Returns the modules for a component, without any filtering. */
- public abstract ImmutableSetMultimap<ClassName, TypeElement> modules();
+ public abstract ImmutableSetMultimap<ClassName, XTypeElement> modules();
/** Returns the entry points associated with the given a component. */
- public abstract ImmutableSetMultimap<ClassName, TypeElement> entryPoints();
+ public abstract ImmutableSetMultimap<ClassName, XTypeElement> entryPoints();
/** Returns the component entry point associated with the given a component. */
- public abstract ImmutableSetMultimap<ClassName, TypeElement> componentEntryPoints();
+ public abstract ImmutableSetMultimap<ClassName, XTypeElement> componentEntryPoints();
@AutoValue.Builder
abstract static class Builder {
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> modulesBuilder();
+ abstract ImmutableSetMultimap.Builder<ClassName, XTypeElement> modulesBuilder();
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> entryPointsBuilder();
+ abstract ImmutableSetMultimap.Builder<ClassName, XTypeElement> entryPointsBuilder();
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> componentEntryPointsBuilder();
+ abstract ImmutableSetMultimap.Builder<ClassName, XTypeElement> componentEntryPointsBuilder();
abstract ComponentDependencies build();
}
@@ -63,16 +63,16 @@
ImmutableSet<AggregatedDepsMetadata> aggregatedDepsMetadata,
ImmutableSet<AggregatedUninstallModulesMetadata> aggregatedUninstallModulesMetadata,
ImmutableSet<AggregatedEarlyEntryPointMetadata> aggregatedEarlyEntryPointMetadata,
- Elements elements) {
- ImmutableSet<TypeElement> uninstalledModules =
- ImmutableSet.<TypeElement>builder()
+ XProcessingEnv env) {
+ ImmutableSet<XTypeElement> uninstalledModules =
+ ImmutableSet.<XTypeElement>builder()
.addAll(
aggregatedUninstallModulesMetadata.stream()
.flatMap(metadata -> metadata.uninstallModuleElements().stream())
// @AggregatedUninstallModules always references the user module, so convert to
// the generated public wrapper if needed.
// TODO(bcorso): Consider converting this to the public module in the processor.
- .map(module -> PkgPrivateMetadata.publicModule(module, elements))
+ .map(module -> PkgPrivateMetadata.publicModule(module))
.collect(toImmutableSet()))
.addAll(
aggregatedDepsMetadata.stream()
@@ -84,8 +84,8 @@
ImmutableSet<ClassName> componentNames =
descriptors.stream().map(ComponentDescriptor::component).collect(toImmutableSet());
for (AggregatedDepsMetadata metadata : aggregatedDepsMetadata) {
- for (TypeElement componentElement : metadata.componentElements()) {
- ClassName componentName = ClassName.get(componentElement);
+ for (XTypeElement componentElement : metadata.componentElements()) {
+ ClassName componentName = componentElement.getClassName();
checkState(
componentNames.contains(componentName), "%s is not a valid Component.", componentName);
switch (metadata.dependencyType()) {
@@ -115,7 +115,7 @@
// @AggregatedEarlyEntryPointMetadata always references the user module, so convert
// to the generated public wrapper if needed.
// TODO(bcorso): Consider converting this to the public module in the processor.
- .map(entryPoint -> PkgPrivateMetadata.publicEarlyEntryPoint(entryPoint, elements))
+ .map(PkgPrivateMetadata::publicEarlyEntryPoint)
.collect(toImmutableSet()));
return componentDependencies.build();
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/KspAggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/KspAggregatedDepsProcessor.java
new file mode 100644
index 0000000..32e450c
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/KspAggregatedDepsProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 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 com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Processor that outputs dummy files to propagate information through multiple javac runs. */
+public final class KspAggregatedDepsProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspAggregatedDepsProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new AggregatedDepsProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspAggregatedDepsProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspAggregatedDepsProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java
index 6dac59f..d02bdfe 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java
@@ -16,12 +16,14 @@
package dagger.hilt.processor.internal.aggregateddeps;
-import com.squareup.javapoet.AnnotationSpec;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XAnnotations;
import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
/**
@@ -29,10 +31,10 @@
* user's entrypoint to use pkg-private visibility to hide from external packages.
*/
final class PkgPrivateEntryPointGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final PkgPrivateMetadata metadata;
- PkgPrivateEntryPointGenerator(ProcessingEnvironment env, PkgPrivateMetadata metadata) {
+ PkgPrivateEntryPointGenerator(XProcessingEnv env, PkgPrivateMetadata metadata) {
this.env = env;
this.metadata = metadata;
}
@@ -55,8 +57,9 @@
void generate() throws IOException {
TypeSpec.Builder entryPointInterfaceBuilder =
- TypeSpec.interfaceBuilder(metadata.generatedClassName().simpleName())
- .addOriginatingElement(metadata.getTypeElement())
+ JavaPoetExtKt.addOriginatingElement(
+ TypeSpec.interfaceBuilder(metadata.generatedClassName().simpleName()),
+ metadata.getTypeElement())
.addAnnotation(Processors.getOriginatingElementAnnotation(metadata.getTypeElement()))
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(metadata.baseClassName())
@@ -64,14 +67,16 @@
Processors.addGeneratedAnnotation(entryPointInterfaceBuilder, env, getClass());
- if (metadata.getOptionalInstallInAnnotationMirror().isPresent()) {
+ if (metadata.getOptionalInstallInAnnotation().isPresent()) {
entryPointInterfaceBuilder.addAnnotation(
- AnnotationSpec.get(metadata.getOptionalInstallInAnnotationMirror().get()));
+ XAnnotations.getAnnotationSpec(metadata.getOptionalInstallInAnnotation().get()));
}
- JavaFile.builder(
- metadata.generatedClassName().packageName(), entryPointInterfaceBuilder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(
+ metadata.generatedClassName().packageName(), entryPointInterfaceBuilder.build())
+ .build(),
+ Mode.Isolating);
}
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
index f88a089..3956853 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
@@ -16,45 +16,41 @@
package dagger.hilt.processor.internal.aggregateddeps;
-import static com.google.auto.common.Visibility.effectiveVisibilityOfElement;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.Visibility;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XTypeElement;
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.Processors;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils;
+import dagger.internal.codegen.xprocessing.XTypeElements;
import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-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);
+ public static XTypeElement publicModule(XTypeElement element) {
+ return publicDep(element, 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);
+ public static XTypeElement publicEntryPoint(XTypeElement element) {
+ return publicDep(element, ClassNames.ENTRY_POINT);
}
/** Returns the public Hilt wrapped type or the type itself if it is already public. */
- public static TypeElement publicEntryPoint(TypeElement element, Elements elements) {
- return publicDep(element, elements, ClassNames.ENTRY_POINT);
+ public static XTypeElement publicEarlyEntryPoint(XTypeElement element) {
+ return publicDep(element, ClassNames.EARLY_ENTRY_POINT);
}
- private static TypeElement publicDep(
- TypeElement element, Elements elements, ClassName annotation) {
- return of(elements, element, annotation)
+ private static XTypeElement publicDep(XTypeElement element, ClassName annotation) {
+ return of(element, annotation)
.map(PkgPrivateMetadata::generatedClassName)
.map(ClassName::canonicalName)
- .map(elements::getTypeElement)
+ .map(getProcessingEnv(element)::requireTypeElement)
.orElse(element);
}
@@ -62,44 +58,42 @@
/** Returns the base class name of the elemenet. */
TypeName baseClassName() {
- return TypeName.get(getTypeElement().asType());
+ return getTypeElement().getClassName();
}
/** Returns TypeElement for the module element the metadata object represents */
- abstract TypeElement getTypeElement();
+ abstract XTypeElement getTypeElement();
/**
* Returns an optional @InstallIn AnnotationMirror for the module element the metadata object
* represents
*/
- abstract Optional<AnnotationMirror> getOptionalInstallInAnnotationMirror();
+ abstract Optional<XAnnotation> getOptionalInstallInAnnotation();
/** Return the Type of this package private element. */
abstract ClassName getAnnotation();
- /** Returns the expected genenerated classname for the element the metadata object represents */
+ /** Returns the expected generated classname for the element the metadata object represents */
final ClassName generatedClassName() {
return Processors.prepend(
- Processors.getEnclosedClassName(ClassName.get(getTypeElement())), PREFIX);
+ Processors.getEnclosedClassName(getTypeElement().getClassName()), PREFIX);
}
/**
* 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(XTypeElement element, ClassName annotation) {
// If this is a public element no wrapping is needed
- if (effectiveVisibilityOfElement(element) == Visibility.PUBLIC
- && !KotlinMetadataUtils.getMetadataUtil().isVisibilityInternal(element)) {
+ if (XTypeElements.isEffectivelyPublic(element) && !element.isInternal()) {
return Optional.empty();
}
- Optional<AnnotationMirror> installIn;
- if (Processors.hasAnnotation(element, ClassNames.INSTALL_IN)) {
- installIn = Optional.of(Processors.getAnnotationMirror(element, ClassNames.INSTALL_IN));
- } else if (Processors.hasAnnotation(element, ClassNames.TEST_INSTALL_IN)) {
- installIn = Optional.of(Processors.getAnnotationMirror(element, ClassNames.TEST_INSTALL_IN));
+ Optional<XAnnotation> installIn;
+ if (element.hasAnnotation(ClassNames.INSTALL_IN)) {
+ installIn = Optional.of(element.getAnnotation(ClassNames.INSTALL_IN));
+ } else if (element.hasAnnotation(ClassNames.TEST_INSTALL_IN)) {
+ installIn = Optional.of(element.getAnnotation(ClassNames.TEST_INSTALL_IN));
} else {
throw new IllegalStateException(
"Expected element to be annotated with @InstallIn: " + element);
@@ -112,11 +106,10 @@
// error more confusing for users since they probably aren't aware of the wrapper. When
// skipped, if the root is in a different package, the error will instead just be on the
// generated Hilt component.
- if (Processors.requiresModuleInstance(elements, MoreElements.asType(element))) {
+ if (Processors.requiresModuleInstance(element)) {
return Optional.empty();
}
}
- return Optional.of(
- new AutoValue_PkgPrivateMetadata(MoreElements.asType(element), installIn, annotation));
+ return Optional.of(new AutoValue_PkgPrivateMetadata(element, installIn, annotation));
}
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java
index 18ff0bd..3225c0b 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java
@@ -16,12 +16,15 @@
package dagger.hilt.processor.internal.aggregateddeps;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XAnnotations;
import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
/**
@@ -30,10 +33,10 @@
* install the module when the component is created in another package.
*/
final class PkgPrivateModuleGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final PkgPrivateMetadata metadata;
- PkgPrivateModuleGenerator(ProcessingEnvironment env, PkgPrivateMetadata metadata) {
+ PkgPrivateModuleGenerator(XProcessingEnv env, PkgPrivateMetadata metadata) {
this.env = env;
this.metadata = metadata;
}
@@ -53,21 +56,22 @@
void generate() throws IOException {
TypeSpec.Builder builder =
TypeSpec.classBuilder(metadata.generatedClassName().simpleName())
- .addOriginatingElement(metadata.getTypeElement())
.addAnnotation(Processors.getOriginatingElementAnnotation(metadata.getTypeElement()))
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
// generated @InstallIn is exactly the same as the module being processed
.addAnnotation(
- AnnotationSpec.get(metadata.getOptionalInstallInAnnotationMirror().get()))
+ XAnnotations.getAnnotationSpec(metadata.getOptionalInstallInAnnotation().get()))
.addAnnotation(
AnnotationSpec.builder(metadata.getAnnotation())
- .addMember("includes", "$T.class", metadata.getTypeElement())
+ .addMember("includes", "$T.class", metadata.getTypeElement().getClassName())
.build());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.getTypeElement());
Processors.addGeneratedAnnotation(builder, env, getClass());
- JavaFile.builder(metadata.generatedClassName().packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(metadata.generatedClassName().packageName(), builder.build()).build(),
+ Mode.Isolating);
}
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessingStep.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessingStep.java
new file mode 100644
index 0000000..ad54223
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessingStep.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.aliasof;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.internal.codegen.extension.DaggerStreams;
+import dagger.internal.codegen.xprocessing.XElements;
+
+/** Processes the annotations annotated with {@link dagger.hilt.migration.AliasOf} */
+public final class AliasOfProcessingStep extends BaseProcessingStep {
+
+ public AliasOfProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.ALIAS_OF);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ ProcessorErrors.checkState(
+ element.hasAnnotation(ClassNames.SCOPE),
+ element,
+ "%s should only be used on scopes." + " However, it was found annotating %s",
+ annotation.simpleName(),
+ XElements.toStableString(element));
+
+ XAnnotation xAnnotation = element.getAnnotation(ClassNames.ALIAS_OF);
+
+ ImmutableList<XTypeElement> defineComponentScopes =
+ xAnnotation.getAsTypeList("value").stream()
+ .map(XType::getTypeElement)
+ .collect(DaggerStreams.toImmutableList());
+
+ ProcessorErrors.checkState(
+ defineComponentScopes.size() >= 1,
+ element,
+ "@AliasOf annotation %s must declare at least one scope to alias.",
+ xAnnotation.getClassName());
+
+ new AliasOfPropagatedDataGenerator(XElements.asTypeElement(element), defineComponentScopes)
+ .generate();
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
index 6c6a734..aeab7a1 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
@@ -16,54 +16,19 @@
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;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-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 dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processes the annotations annotated with {@link dagger.hilt.migration.AliasOf} */
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class AliasOfProcessor extends BaseProcessor {
+public final class AliasOfProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.ALIAS_OF.toString());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.SCOPE),
- element,
- "%s should only be used on scopes." + " However, it was found annotating %s",
- annotation,
- element);
-
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF);
-
- ImmutableList<TypeElement> defineComponentScopes =
- Processors.getAnnotationClassValues(getElementUtils(), annotationMirror, "value");
-
- ProcessorErrors.checkState(
- defineComponentScopes.size() >= 1,
- element,
- "@AliasOf annotation %s must declare at least one scope to alias.",
- annotationMirror);
-
- new AliasOfPropagatedDataGenerator(getProcessingEnv(), asType(element), defineComponentScopes)
- .generate();
+ public AliasOfProcessingStep processingStep() {
+ return new AliasOfProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
index a2441f9..62c69b4 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
@@ -16,45 +16,39 @@
package dagger.hilt.processor.internal.aliasof;
+import androidx.room.compiler.processing.XTypeElement;
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 resource files for {@link dagger.hilt.migration.AliasOf}. */
final class AliasOfPropagatedDataGenerator {
- private final ProcessingEnvironment processingEnv;
- private final TypeElement aliasScope;
- private final ImmutableList<TypeElement> defineComponentScopes;
+ private final XTypeElement aliasScope;
+ private final ImmutableList<XTypeElement> defineComponentScopes;
AliasOfPropagatedDataGenerator(
- ProcessingEnvironment processingEnv,
- TypeElement aliasScope,
- ImmutableList<TypeElement> defineComponentScopes) {
- this.processingEnv = processingEnv;
+ XTypeElement aliasScope,
+ ImmutableList<XTypeElement> defineComponentScopes) {
this.aliasScope = aliasScope;
this.defineComponentScopes = defineComponentScopes;
}
- void generate() throws IOException {
+ void generate() {
Processors.generateAggregatingClass(
ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE,
propagatedDataAnnotation(),
aliasScope,
- getClass(),
- processingEnv);
+ getClass());
}
private AnnotationSpec propagatedDataAnnotation() {
AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassNames.ALIAS_OF_PROPAGATED_DATA);
- for (TypeElement defineComponentScope : defineComponentScopes) {
- builder.addMember("defineComponentScopes", "$T.class", defineComponentScope);
+ for (XTypeElement defineComponentScope : defineComponentScopes) {
+ builder.addMember("defineComponentScopes", "$T.class", defineComponentScope.getClassName());
}
- builder.addMember("alias", "$T.class", aliasScope);
+ builder.addMember("alias", "$T.class", aliasScope.getClassName());
return builder.build();
}
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java
index d0c89db..c1a7bb0 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataMetadata.java
@@ -19,21 +19,20 @@
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XAnnotationValue;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
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 com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.AggregatedElements;
-import dagger.hilt.processor.internal.AnnotationValues;
import dagger.hilt.processor.internal.BadInputException;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.Processors;
import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
+import dagger.internal.codegen.xprocessing.XAnnotations;
/**
* A class that represents the values stored in an {@link
@@ -43,62 +42,58 @@
public abstract class AliasOfPropagatedDataMetadata {
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
- abstract ImmutableList<TypeElement> defineComponentScopeElements();
+ abstract ImmutableList<XTypeElement> defineComponentScopeElements();
- abstract TypeElement aliasElement();
+ abstract XTypeElement aliasElement();
/** Returns metadata for all aggregated elements in the aggregating package. */
- public static ImmutableSet<AliasOfPropagatedDataMetadata> from(Elements elements) {
+ public static ImmutableSet<AliasOfPropagatedDataMetadata> from(XProcessingEnv env) {
return from(
AggregatedElements.from(
- ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE,
- ClassNames.ALIAS_OF_PROPAGATED_DATA,
- elements),
- elements);
+ ClassNames.ALIAS_OF_PROPAGATED_DATA_PACKAGE, ClassNames.ALIAS_OF_PROPAGATED_DATA, env));
}
/** Returns metadata for each aggregated element. */
public static ImmutableSet<AliasOfPropagatedDataMetadata> from(
- ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ ImmutableSet<XTypeElement> aggregatedElements) {
return aggregatedElements.stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ .map(AliasOfPropagatedDataMetadata::create)
.collect(toImmutableSet());
}
public static AliasOfPropagatedDataIr toIr(AliasOfPropagatedDataMetadata metadata) {
return new AliasOfPropagatedDataIr(
- ClassName.get(metadata.aggregatingElement()),
+ metadata.aggregatingElement().getClassName(),
metadata.defineComponentScopeElements().stream()
- .map(ClassName::get)
+ .map(XTypeElement::getClassName)
.collect(toImmutableList()),
- ClassName.get(metadata.aliasElement()));
+ metadata.aliasElement().getClassName());
}
- private static AliasOfPropagatedDataMetadata create(TypeElement element, Elements elements) {
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF_PROPAGATED_DATA);
+ private static AliasOfPropagatedDataMetadata create(XTypeElement element) {
+ XAnnotation annotation = element.getAnnotation(ClassNames.ALIAS_OF_PROPAGATED_DATA);
- ImmutableMap<String, AnnotationValue> values =
- Processors.getAnnotationValues(elements, annotationMirror);
+ // TODO(kuanyingchou) We can remove this once we have
+ // `XAnnotation.hasAnnotationValue(methodName: String)`.
+ ImmutableMap<String, XAnnotationValue> values = Processors.getAnnotationValues(annotation);
- ImmutableList<TypeElement> defineComponentScopes;
+ ImmutableList<XTypeElement> defineComponentScopes;
+
if (values.containsKey("defineComponentScopes")) {
defineComponentScopes =
- ImmutableList.copyOf(
- AnnotationValues.getTypeElements(values.get("defineComponentScopes")));
+ XAnnotations.getAsTypeElementList(annotation, "defineComponentScopes");
} else if (values.containsKey("defineComponentScope")) {
// Older version of AliasOfPropagatedData only passed a single defineComponentScope class
// value. Fall back on reading the single value if we get old propagated data.
- defineComponentScopes =
- ImmutableList.of(AnnotationValues.getTypeElement(values.get("defineComponentScope")));
+ defineComponentScopes = XAnnotations.getAsTypeElementList(annotation, "defineComponentScope");
} else {
throw new BadInputException(
"AliasOfPropagatedData is missing defineComponentScopes", element);
}
return new AutoValue_AliasOfPropagatedDataMetadata(
- element, defineComponentScopes, AnnotationValues.getTypeElement(values.get("alias")));
+ element, defineComponentScopes, annotation.getAsType("alias").getTypeElement());
}
}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
index 1fee2a3..fb45597 100644
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
+++ b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
@@ -40,12 +40,12 @@
ImmutableSetMultimap.Builder<ClassName, ClassName> builder = ImmutableSetMultimap.builder();
metadatas.forEach(
metadata -> {
- ClassName aliasScopeName = ClassName.get(metadata.aliasElement());
+ ClassName aliasScopeName = metadata.aliasElement().getClassName();
metadata
.defineComponentScopeElements()
.forEach(
defineComponentScope -> {
- ClassName defineComponentScopeName = ClassName.get(defineComponentScope);
+ ClassName defineComponentScopeName = defineComponentScope.getClassName();
ProcessorErrors.checkState(
defineComponentScopes.contains(defineComponentScopeName),
metadata.aliasElement(),
diff --git a/java/dagger/hilt/processor/internal/aliasof/BUILD b/java/dagger/hilt/processor/internal/aliasof/BUILD
index d589cb2..3c72e71 100644
--- a/java/dagger/hilt/processor/internal/aliasof/BUILD
+++ b/java/dagger/hilt/processor/internal/aliasof/BUILD
@@ -27,19 +27,23 @@
java_library(
name = "processor_lib",
srcs = [
+ "AliasOfProcessingStep.java",
"AliasOfProcessor.java",
"AliasOfPropagatedDataGenerator.java",
+ "KspAliasOfProcessor.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",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -57,6 +61,7 @@
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
diff --git a/java/dagger/hilt/processor/internal/aliasof/KspAliasOfProcessor.java b/java/dagger/hilt/processor/internal/aliasof/KspAliasOfProcessor.java
new file mode 100644
index 0000000..083783e
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/aliasof/KspAliasOfProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.aliasof;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Processes the annotations annotated with {@link dagger.hilt.migration.AliasOf} */
+public final class KspAliasOfProcessor extends KspBaseProcessingStepProcessor {
+ public KspAliasOfProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new AliasOfProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspAliasOfProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspAliasOfProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/BUILD b/java/dagger/hilt/processor/internal/definecomponent/BUILD
index 9701a06..a259b72 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/BUILD
+++ b/java/dagger/hilt/processor/internal/definecomponent/BUILD
@@ -30,29 +30,50 @@
java_library(
name = "processor_lib",
srcs = [
+ "DefineComponentProcessingStep.java",
"DefineComponentProcessor.java",
+ "KspDefineComponentProcessor.java",
],
deps = [
- ":define_components",
+ ":metadatas",
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
+ ],
+)
+
+java_library(
+ name = "metadatas",
+ srcs = [
+ "DefineComponentBuilderMetadatas.java",
+ "DefineComponentMetadatas.java",
+ ],
+ deps = [
+ "//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/codegen/xprocessing",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/collect",
+ "//third_party/java/javapoet",
],
)
java_library(
name = "define_components",
srcs = [
- "DefineComponentBuilderMetadatas.java",
"DefineComponentClassesMetadata.java",
- "DefineComponentMetadatas.java",
"DefineComponents.java",
],
deps = [
+ ":metadatas",
"//java/dagger/hilt/processor/internal:aggregated_elements",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:component_descriptor",
@@ -60,7 +81,7 @@
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java
index 0f10f39..f4bebf9 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java
@@ -16,29 +16,26 @@
package dagger.hilt.processor.internal.definecomponent;
-import static javax.lang.model.element.Modifier.STATIC;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeName;
+import com.google.common.collect.ImmutableList;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.internal.codegen.xprocessing.XTypes;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
/** Metadata for types annotated with {@link dagger.hilt.DefineComponent.Builder}. */
final class DefineComponentBuilderMetadatas {
@@ -46,115 +43,125 @@
return new DefineComponentBuilderMetadatas(componentMetadatas);
}
- private final Map<Element, DefineComponentBuilderMetadata> builderMetadatas = new HashMap<>();
+ private final Map<XElement, DefineComponentBuilderMetadata> builderMetadatas = new HashMap<>();
private final DefineComponentMetadatas componentMetadatas;
private DefineComponentBuilderMetadatas(DefineComponentMetadatas componentMetadatas) {
this.componentMetadatas = componentMetadatas;
}
- DefineComponentBuilderMetadata get(Element element) {
+ DefineComponentBuilderMetadata get(XElement element) {
if (!builderMetadatas.containsKey(element)) {
builderMetadatas.put(element, getUncached(element));
}
return builderMetadatas.get(element);
}
- private DefineComponentBuilderMetadata getUncached(Element element) {
+ private DefineComponentBuilderMetadata getUncached(XElement element) {
ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.DEFINE_COMPONENT_BUILDER),
+ element.hasAnnotation(ClassNames.DEFINE_COMPONENT_BUILDER),
element,
"%s, expected to be annotated with @DefineComponent.Builder. Found: %s",
- element,
- element.getAnnotationMirrors());
+ XElements.toStableString(element),
+ element.getAllAnnotations().stream()
+ .map(XAnnotations::toStableString)
+ .collect(toImmutableList()));
// TODO(bcorso): Allow abstract classes?
ProcessorErrors.checkState(
- element.getKind().equals(ElementKind.INTERFACE),
+ isTypeElement(element) && asTypeElement(element).isInterface(),
element,
"@DefineComponent.Builder is only allowed on interfaces. Found: %s",
- element);
- TypeElement builder = MoreElements.asType(element);
+ XElements.toStableString(element));
+ XTypeElement builder = asTypeElement(element);
// TODO(bcorso): Allow extending interfaces?
ProcessorErrors.checkState(
- builder.getInterfaces().isEmpty(),
+ builder.getSuperInterfaces().isEmpty(),
builder,
"@DefineComponent.Builder %s, cannot extend a super class or interface. Found: %s",
- builder,
- builder.getInterfaces());
+ XElements.toStableString(builder),
+ builder.getSuperInterfaces().stream()
+ .map(XTypes::toStableString)
+ .collect(toImmutableList()));
// TODO(bcorso): Allow type parameters?
ProcessorErrors.checkState(
builder.getTypeParameters().isEmpty(),
builder,
"@DefineComponent.Builder %s, cannot have type parameters.",
- builder.asType());
+ XTypes.toStableString(builder.getType()));
- List<VariableElement> nonStaticFields =
- ElementFilter.fieldsIn(builder.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
- .collect(Collectors.toList());
+ ImmutableList<XFieldElement> nonStaticFields =
+ builder.getDeclaredFields().stream()
+ .filter(field -> !field.isStatic())
+ .collect(toImmutableList());
+
ProcessorErrors.checkState(
nonStaticFields.isEmpty(),
builder,
"@DefineComponent.Builder %s, cannot have non-static fields. Found: %s",
- builder,
- nonStaticFields);
+ XElements.toStableString(builder),
+ nonStaticFields.stream()
+ .map(XElements::toStableString)
+ .collect(toImmutableList()));
- List<ExecutableElement> buildMethods =
- ElementFilter.methodsIn(builder.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
+ ImmutableList<XMethodElement> buildMethods =
+ builder.getDeclaredMethods().stream()
+ .filter(method -> !method.isStatic())
.filter(method -> method.getParameters().isEmpty())
- .collect(Collectors.toList());
+ .collect(toImmutableList());
ProcessorErrors.checkState(
buildMethods.size() == 1,
builder,
"@DefineComponent.Builder %s, must have exactly 1 build method that takes no parameters. "
+ "Found: %s",
- builder,
- buildMethods);
+ XElements.toStableString(builder),
+ buildMethods.stream()
+ .map(XElements::toStableString)
+ .collect(toImmutableList()));
- ExecutableElement buildMethod = buildMethods.get(0);
- TypeMirror component = buildMethod.getReturnType();
+ XMethodElement buildMethod = buildMethods.get(0);
+ XType componentType = buildMethod.getReturnType();
ProcessorErrors.checkState(
- buildMethod.getReturnType().getKind().equals(TypeKind.DECLARED)
- && Processors.hasAnnotation(
- MoreTypes.asTypeElement(component), ClassNames.DEFINE_COMPONENT),
+ isDeclared(componentType)
+ && componentType.getTypeElement().hasAnnotation(ClassNames.DEFINE_COMPONENT),
builder,
"@DefineComponent.Builder method, %s#%s, must return a @DefineComponent type. Found: %s",
- builder,
- buildMethod,
- component);
+ XElements.toStableString(builder),
+ XElements.toStableString(buildMethod),
+ XTypes.toStableString(componentType));
- List<ExecutableElement> nonStaticNonBuilderMethods =
- ElementFilter.methodsIn(builder.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
+ ImmutableList<XMethodElement> nonStaticNonBuilderMethods =
+ builder.getDeclaredMethods().stream()
+ .filter(method -> !method.isStatic())
.filter(method -> !method.equals(buildMethod))
- .filter(method -> !TypeName.get(method.getReturnType()).equals(ClassName.get(builder)))
- .collect(Collectors.toList());
+ .filter(method -> !method.getReturnType().getTypeName().equals(builder.getClassName()))
+ .collect(toImmutableList());
- ProcessorErrors.checkState(
+ ProcessorErrors.checkStateX(
nonStaticNonBuilderMethods.isEmpty(),
nonStaticNonBuilderMethods,
"@DefineComponent.Builder %s, all non-static methods must return %s or %s. Found: %s",
- builder,
- builder,
- component,
- nonStaticNonBuilderMethods);
+ XElements.toStableString(builder),
+ XElements.toStableString(builder),
+ XTypes.toStableString(componentType),
+ nonStaticNonBuilderMethods.stream()
+ .map(XElements::toStableString)
+ .collect(toImmutableList()));
return new AutoValue_DefineComponentBuilderMetadatas_DefineComponentBuilderMetadata(
builder,
buildMethod,
- componentMetadatas.get(MoreTypes.asTypeElement(component)));
+ componentMetadatas.get(componentType.getTypeElement()));
}
@AutoValue
abstract static class DefineComponentBuilderMetadata {
- abstract TypeElement builder();
+ abstract XTypeElement builder();
- abstract ExecutableElement buildMethod();
+ abstract XMethodElement buildMethod();
abstract DefineComponentMetadata componentMetadata();
}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java
index 280269f..da3277d 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentClassesMetadata.java
@@ -16,22 +16,18 @@
package dagger.hilt.processor.internal.definecomponent;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
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 dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
-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
@@ -41,13 +37,13 @@
public abstract class DefineComponentClassesMetadata {
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
/**
* Returns the element annotated with {@code dagger.hilt.internal.definecomponent.DefineComponent}
* or {@code dagger.hilt.internal.definecomponent.DefineComponent.Builder}.
*/
- public abstract TypeElement element();
+ public abstract XTypeElement element();
/** Returns {@code true} if this element represents a component. */
abstract boolean isComponent();
@@ -58,32 +54,25 @@
}
/** Returns metadata for all aggregated elements in the aggregating package. */
- public static ImmutableSet<DefineComponentClassesMetadata> from(Elements elements) {
+ public static ImmutableSet<DefineComponentClassesMetadata> from(XProcessingEnv env) {
return from(
AggregatedElements.from(
- ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE,
- ClassNames.DEFINE_COMPONENT_CLASSES,
- elements),
- elements);
+ ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE, ClassNames.DEFINE_COMPONENT_CLASSES, env));
}
/** Returns metadata for each aggregated element. */
public static ImmutableSet<DefineComponentClassesMetadata> from(
- ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ ImmutableSet<XTypeElement> aggregatedElements) {
return aggregatedElements.stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ .map(aggregatedElement -> create(aggregatedElement))
.collect(toImmutableSet());
}
- private static DefineComponentClassesMetadata create(TypeElement element, Elements elements) {
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.DEFINE_COMPONENT_CLASSES);
+ private static DefineComponentClassesMetadata create(XTypeElement element) {
+ XAnnotation annotation = element.getAnnotation(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"));
+ String componentName = annotation.getAsString("component");
+ String builderName = annotation.getAsString("builder");
ProcessorErrors.checkState(
!(componentName.isEmpty() && builderName.isEmpty()),
@@ -97,7 +86,8 @@
boolean isComponent = !componentName.isEmpty();
String componentOrBuilderName = isComponent ? componentName : builderName;
- TypeElement componentOrBuilderElement = elements.getTypeElement(componentOrBuilderName);
+ XTypeElement componentOrBuilderElement =
+ getProcessingEnv(element).findTypeElement(componentOrBuilderName);
ProcessorErrors.checkState(
componentOrBuilderElement != null,
componentOrBuilderElement,
@@ -111,7 +101,7 @@
public static DefineComponentClassesIr toIr(DefineComponentClassesMetadata metadata) {
return new DefineComponentClassesIr(
- ClassName.get(metadata.aggregatingElement()),
- ClassName.get(metadata.element()).canonicalName());
+ metadata.aggregatingElement().getClassName(),
+ metadata.element().getClassName().canonicalName());
}
}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java
index 60864c2..0381e6c 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java
@@ -16,34 +16,29 @@
package dagger.hilt.processor.internal.definecomponent;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationElementAndValue;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asTypeElement;
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.STATIC;
-import com.google.auto.common.MoreTypes;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XAnnotationValue;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.ClassName;
-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 dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.internal.codegen.xprocessing.XTypes;
import java.util.HashMap;
import java.util.LinkedHashSet;
-import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
-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.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.ElementFilter;
/** Metadata for types annotated with {@link dagger.hilt.DefineComponent}. */
final class DefineComponentMetadatas {
@@ -51,16 +46,16 @@
return new DefineComponentMetadatas();
}
- private final Map<Element, DefineComponentMetadata> metadatas = new HashMap<>();
+ private final Map<XElement, DefineComponentMetadata> metadatas = new HashMap<>();
private DefineComponentMetadatas() {}
/** Returns the metadata for an element annotated with {@link dagger.hilt.DefineComponent}. */
- DefineComponentMetadata get(Element element) {
+ DefineComponentMetadata get(XElement element) {
return get(element, new LinkedHashSet<>());
}
- private DefineComponentMetadata get(Element element, LinkedHashSet<Element> childPath) {
+ private DefineComponentMetadata get(XElement element, LinkedHashSet<XElement> childPath) {
if (!metadatas.containsKey(element)) {
metadatas.put(element, getUncached(element, childPath));
}
@@ -68,102 +63,106 @@
}
private DefineComponentMetadata getUncached(
- Element element, LinkedHashSet<Element> childPath) {
+ XElement element, LinkedHashSet<XElement> childPath) {
ProcessorErrors.checkState(
childPath.add(element),
element,
"@DefineComponent cycle: %s -> %s",
- childPath.stream().map(Object::toString).collect(joining(" -> ")),
- element);
+ childPath.stream().map(XElements::toStableString).collect(joining(" -> ")),
+ XElements.toStableString(element));
ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.DEFINE_COMPONENT),
+ element.hasAnnotation(ClassNames.DEFINE_COMPONENT),
element,
"%s, expected to be annotated with @DefineComponent. Found: %s",
- element,
- element.getAnnotationMirrors());
+ XElements.toStableString(element),
+ element.getAllAnnotations().stream()
+ .map(XAnnotations::toStableString)
+ .collect(toImmutableList()));
// TODO(bcorso): Allow abstract classes?
ProcessorErrors.checkState(
- element.getKind().equals(ElementKind.INTERFACE),
+ isTypeElement(element) && asTypeElement(element).isInterface(),
element,
"@DefineComponent is only allowed on interfaces. Found: %s",
- element);
- TypeElement component = asType(element);
+ XElements.toStableString(element));
+ XTypeElement component = asTypeElement(element);
// TODO(bcorso): Allow extending interfaces?
ProcessorErrors.checkState(
- component.getInterfaces().isEmpty(),
+ component.getSuperInterfaces().isEmpty(),
component,
"@DefineComponent %s, cannot extend a super class or interface. Found: %s",
- component,
- component.getInterfaces());
+ XElements.toStableString(component),
+ component.getSuperInterfaces().stream()
+ .map(XTypes::toStableString)
+ .collect(toImmutableList()));
// TODO(bcorso): Allow type parameters?
ProcessorErrors.checkState(
component.getTypeParameters().isEmpty(),
component,
"@DefineComponent %s, cannot have type parameters.",
- component.asType());
+ XTypes.toStableString(component.getType()));
// TODO(bcorso): Allow non-static abstract methods (aka EntryPoints)?
- List<ExecutableElement> nonStaticMethods =
- ElementFilter.methodsIn(component.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
- .collect(Collectors.toList());
+ ImmutableList<XExecutableElement> nonStaticMethods =
+ component.getDeclaredMethods().stream()
+ .filter(method -> !method.isStatic())
+ .collect(toImmutableList());
+
ProcessorErrors.checkState(
nonStaticMethods.isEmpty(),
component,
"@DefineComponent %s, cannot have non-static methods. Found: %s",
- component,
- nonStaticMethods);
+ XElements.toStableString(component),
+ nonStaticMethods.stream()
+ .map(XElements::toStableString)
+ .collect(toImmutableList()));
// No need to check non-static fields since interfaces can't have them.
- ImmutableList<TypeElement> scopes =
+ ImmutableList<XTypeElement> scopes =
Processors.getScopeAnnotations(component).stream()
- .map(AnnotationMirror::getAnnotationType)
- .map(MoreTypes::asTypeElement)
+ .map(XAnnotation::getTypeElement)
.collect(toImmutableList());
- ImmutableList<AnnotationMirror> aliasScopes =
- Processors.getAnnotationsAnnotatedWith(component, ClassNames.ALIAS_OF);
+ ImmutableList<XAnnotation> aliasScopes =
+ ImmutableList.copyOf(component.getAnnotationsAnnotatedWith(ClassNames.ALIAS_OF));
ProcessorErrors.checkState(
aliasScopes.isEmpty(),
component,
"@DefineComponent %s, references invalid scope(s) annotated with @AliasOf. "
+ "@DefineComponent scopes cannot be aliases of other scopes: %s",
- component,
- aliasScopes);
+ XElements.toStableString(component),
+ aliasScopes.stream().map(XAnnotations::toStableString).collect(toImmutableList()));
- AnnotationMirror mirror =
- Processors.getAnnotationMirror(component, ClassNames.DEFINE_COMPONENT);
- AnnotationValue parentValue = getAnnotationElementAndValue(mirror, "parent").getValue();
+ XAnnotation annotation = component.getAnnotation(ClassNames.DEFINE_COMPONENT);
+ XAnnotationValue parentValue = annotation.getAnnotationValue("parent");
ProcessorErrors.checkState(
- // TODO(bcorso): Contribute a check to auto/common AnnotationValues.
!"<error>".contentEquals(parentValue.getValue().toString()),
component,
"@DefineComponent %s, references an invalid parent type: %s",
- component,
- mirror);
+ XElements.toStableString(component),
+ XAnnotations.toStableString(annotation));
- TypeElement parent = asTypeElement(AnnotationValues.getTypeMirror(parentValue));
+ XTypeElement parent = parentValue.asType().getTypeElement();
ProcessorErrors.checkState(
- ClassName.get(parent).equals(ClassNames.DEFINE_COMPONENT_NO_PARENT)
- || Processors.hasAnnotation(parent, ClassNames.DEFINE_COMPONENT),
+ parent.getClassName().equals(ClassNames.DEFINE_COMPONENT_NO_PARENT)
+ || parent.hasAnnotation(ClassNames.DEFINE_COMPONENT),
component,
"@DefineComponent %s, references a type not annotated with @DefineComponent: %s",
- component,
- parent);
+ XElements.toStableString(component),
+ XElements.toStableString(parent));
Optional<DefineComponentMetadata> parentComponent =
- ClassName.get(parent).equals(ClassNames.DEFINE_COMPONENT_NO_PARENT)
+ parent.getClassName().equals(ClassNames.DEFINE_COMPONENT_NO_PARENT)
? Optional.empty()
: Optional.of(get(parent, childPath));
- ClassName componentClassName = ClassName.get(component);
+ ClassName componentClassName = component.getClassName();
ProcessorErrors.checkState(
parentComponent.isPresent()
@@ -172,7 +171,7 @@
"@DefineComponent %s is missing a parent declaration.\n"
+ "Please declare the parent, for example: @DefineComponent(parent ="
+ " SingletonComponent.class)",
- component);
+ XElements.toStableString(component));
ProcessorErrors.checkState(
componentClassName.equals(ClassNames.SINGLETON_COMPONENT)
@@ -180,7 +179,7 @@
component,
"Cannot have a component with the same simple name as the reserved %s: %s",
ClassNames.SINGLETON_COMPONENT.simpleName(),
- componentClassName);
+ componentClassName.canonicalName());
return new AutoValue_DefineComponentMetadatas_DefineComponentMetadata(
component, scopes, parentComponent);
@@ -190,10 +189,10 @@
abstract static class DefineComponentMetadata {
/** Returns the component annotated with {@link dagger.hilt.DefineComponent}. */
- abstract TypeElement component();
+ abstract XTypeElement component();
/** Returns the scopes of the component. */
- abstract ImmutableList<TypeElement> scopes();
+ abstract ImmutableList<XTypeElement> scopes();
/** Returns the parent component, if one exists. */
abstract Optional<DefineComponentMetadata> parentMetadata();
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessingStep.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessingStep.java
new file mode 100644
index 0000000..fe21227
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessingStep.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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 androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas.DefineComponentBuilderMetadata;
+import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
+
+/**
+ * A processor for {@link dagger.hilt.DefineComponent} and {@link
+ * dagger.hilt.DefineComponent.Builder}.
+ */
+public final class DefineComponentProcessingStep extends BaseProcessingStep {
+ // Note: these caches should be cleared between rounds.
+ private DefineComponentMetadatas componentMetadatas;
+ private DefineComponentBuilderMetadatas componentBuilderMetadatas;
+
+ public DefineComponentProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ public void preProcess(XProcessingEnv env, XRoundEnv round) {
+ componentMetadatas = DefineComponentMetadatas.create();
+ componentBuilderMetadatas = DefineComponentBuilderMetadatas.create(componentMetadatas);
+ }
+
+ @Override
+ public void postProcess(XProcessingEnv env, XRoundEnv round) {
+ componentMetadatas = null;
+ componentBuilderMetadatas = null;
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.DEFINE_COMPONENT, ClassNames.DEFINE_COMPONENT_BUILDER);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ if (annotation.equals(ClassNames.DEFINE_COMPONENT)) {
+ // TODO(bcorso): For cycles we currently process each element in the cycle. We should skip
+ // processing of subsequent elements in a cycle, but this requires ensuring that the first
+ // element processed is always the same so that our failure tests are stable.
+ DefineComponentMetadata metadata = componentMetadatas.get(element);
+ generateFile("component", metadata.component());
+ } else if (annotation.equals(ClassNames.DEFINE_COMPONENT_BUILDER)) {
+ DefineComponentBuilderMetadata metadata = componentBuilderMetadatas.get(element);
+ generateFile("builder", metadata.builder());
+ } else {
+ throw new AssertionError("Unhandled annotation type: " + annotation.canonicalName());
+ }
+ }
+
+ private void generateFile(String member, XTypeElement typeElement) {
+ Processors.generateAggregatingClass(
+ ClassNames.DEFINE_COMPONENT_CLASSES_PACKAGE,
+ AnnotationSpec.builder(ClassNames.DEFINE_COMPONENT_CLASSES)
+ .addMember(member, "$S", typeElement.getQualifiedName())
+ .build(),
+ typeElement,
+ getClass());
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java
index f7e54a0..81bc43a 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java
@@ -19,19 +19,9 @@
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas.DefineComponentBuilderMetadata;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
-import java.io.IOException;
-import java.util.Set;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/**
@@ -40,41 +30,9 @@
*/
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class DefineComponentProcessor extends BaseProcessor {
- private final DefineComponentMetadatas componentMetadatas = DefineComponentMetadatas.create();
- private final DefineComponentBuilderMetadatas componentBuilderMetadatas =
- DefineComponentBuilderMetadatas.create(componentMetadatas);
-
+public final class DefineComponentProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(
- ClassNames.DEFINE_COMPONENT.toString(), ClassNames.DEFINE_COMPONENT_BUILDER.toString());
- }
-
- @Override
- protected void processEach(TypeElement annotation, Element element) throws Exception {
- if (ClassName.get(annotation).equals(ClassNames.DEFINE_COMPONENT)) {
- // TODO(bcorso): For cycles we currently process each element in the cycle. We should skip
- // processing of subsequent elements in a cycle, but this requires ensuring that the first
- // element processed is always the same so that our failure tests are stable.
- DefineComponentMetadata metadata = componentMetadatas.get(element);
- generateFile("component", metadata.component());
- } else if (ClassName.get(annotation).equals(ClassNames.DEFINE_COMPONENT_BUILDER)) {
- DefineComponentBuilderMetadata metadata = componentBuilderMetadatas.get(element);
- generateFile("builder", metadata.builder());
- } else {
- throw new AssertionError("Unhandled annotation type: " + annotation);
- }
- }
-
- 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());
+ protected BaseProcessingStep processingStep() {
+ return new DefineComponentProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
index e9200d0..b5b41af 100644
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
+++ b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
@@ -19,63 +19,34 @@
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ListMultimap;
-import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ComponentDescriptor;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas.DefineComponentBuilderMetadata;
import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
-import java.util.HashMap;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.LinkedHashMap;
import java.util.Map;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/**
* A utility class for getting {@link DefineComponentMetadata} and {@link
* DefineComponentBuilderMetadata}.
*/
public final class DefineComponents {
-
public static DefineComponents create() {
return new DefineComponents();
}
- private final Map<Element, ComponentDescriptor> componentDescriptors = new HashMap<>();
private final DefineComponentMetadatas componentMetadatas = DefineComponentMetadatas.create();
private final DefineComponentBuilderMetadatas componentBuilderMetadatas =
DefineComponentBuilderMetadatas.create(componentMetadatas);
private DefineComponents() {}
- /** Returns the {@link ComponentDescriptor} for the given component element. */
- // TODO(b/144940889): This descriptor doesn't contain the "creator" or the "installInName".
- public ComponentDescriptor componentDescriptor(Element element) {
- if (!componentDescriptors.containsKey(element)) {
- componentDescriptors.put(element, uncachedComponentDescriptor(element));
- }
- return componentDescriptors.get(element);
- }
-
- private ComponentDescriptor uncachedComponentDescriptor(Element element) {
- DefineComponentMetadata metadata = componentMetadatas.get(element);
- ComponentDescriptor.Builder builder =
- ComponentDescriptor.builder()
- .component(ClassName.get(metadata.component()))
- .scopes(metadata.scopes().stream().map(ClassName::get).collect(toImmutableSet()));
-
-
- metadata.parentMetadata()
- .map(DefineComponentMetadata::component)
- .map(this::componentDescriptor)
- .ifPresent(builder::parent);
-
- return builder.build();
- }
-
/** Returns the set of aggregated {@link ComponentDescriptor}s. */
public ImmutableSet<ComponentDescriptor> getComponentDescriptors(
ImmutableSet<DefineComponentClassesMetadata> aggregatedMetadatas) {
@@ -99,17 +70,17 @@
// Check that there are not multiple builders per component
for (DefineComponentMetadata componentMetadata : builderMultimap.keySet()) {
- TypeElement component = componentMetadata.component();
+ XTypeElement component = componentMetadata.component();
ProcessorErrors.checkState(
builderMultimap.get(componentMetadata).size() <= 1,
component,
"Multiple @%s declarations are not allowed for @%s type, %s. Found: %s",
ClassNames.DEFINE_COMPONENT_BUILDER,
ClassNames.DEFINE_COMPONENT,
- component,
+ XElements.toStableString(component),
builderMultimap.get(componentMetadata).stream()
.map(DefineComponentBuilderMetadata::builder)
- .map(TypeElement::toString)
+ .map(XTypeElement::getQualifiedName)
.sorted()
.collect(toImmutableList()));
}
@@ -128,13 +99,15 @@
Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap) {
ComponentDescriptor.Builder builder =
ComponentDescriptor.builder()
- .component(ClassName.get(componentMetadata.component()))
+ .component(componentMetadata.component().getClassName())
.scopes(
- componentMetadata.scopes().stream().map(ClassName::get).collect(toImmutableSet()));
+ componentMetadata.scopes().stream()
+ .map(XTypeElement::getClassName)
+ .collect(toImmutableSet()));
if (builderMap.containsKey(componentMetadata)) {
- builder.creator(ClassName.get(builderMap.get(componentMetadata).builder()));
+ builder.creator(builderMap.get(componentMetadata).builder().getClassName());
}
componentMetadata
diff --git a/java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentProcessor.java b/java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentProcessor.java
new file mode 100644
index 0000000..497c1aa
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentProcessor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.definecomponent;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/**
+ * A processor for {@link dagger.hilt.DefineComponent} and {@link
+ * dagger.hilt.DefineComponent.Builder}.
+ */
+public final class KspDefineComponentProcessor extends KspBaseProcessingStepProcessor {
+ public KspDefineComponentProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new DefineComponentProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspDefineComponentProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspDefineComponentProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentValidationProcessor.java b/java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentValidationProcessor.java
new file mode 100644
index 0000000..d46921e
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/definecomponent/KspDefineComponentValidationProcessor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.definecomponent;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/**
+ * A processor for {@link dagger.hilt.DefineComponent} and {@link
+ * dagger.hilt.DefineComponent.Builder}.
+ */
+public final class KspDefineComponentValidationProcessor extends KspBaseProcessingStepProcessor {
+ public KspDefineComponentValidationProcessor(
+ SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new DefineComponentValidationProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspDefineComponentValidationProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspDefineComponentValidationProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
index c06f9fe..b9caf58 100644
--- a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
@@ -30,16 +30,20 @@
java_library(
name = "processor_lib",
srcs = [
+ "DisableInstallInCheckProcessingStep.java",
"DisableInstallInCheckProcessor.java",
+ "KspDisableInstallInCheckProcessor.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/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
+ "//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessingStep.java b/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessingStep.java
new file mode 100644
index 0000000..591889c
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessingStep.java
@@ -0,0 +1,48 @@
+/*
+ * 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.disableinstallincheck;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.internal.codegen.xprocessing.XElements;
+
+/** Processes the annotations annotated with {@link dagger.hilt.migration.DisableInstallInCheck} */
+public final class DisableInstallInCheckProcessingStep extends BaseProcessingStep {
+ public DisableInstallInCheckProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.DISABLE_INSTALL_IN_CHECK);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ ProcessorErrors.checkState(
+ element.hasAnnotation(ClassNames.MODULE),
+ element,
+ "@DisableInstallInCheck should only be used on modules. However, it was found annotating"
+ + " %s",
+ XElements.toStableString(element));
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java b/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java
index c51f350..873e049 100644
--- a/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java
+++ b/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java
@@ -19,32 +19,16 @@
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 dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processes the annotations annotated with {@link dagger.hilt.migration.DisableInstallInCheck} */
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class DisableInstallInCheckProcessor extends BaseProcessor {
+public final class DisableInstallInCheckProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public ImmutableSet<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.DISABLE_INSTALL_IN_CHECK.toString());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) {
- ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.MODULE),
- element,
- "@DisableInstallInCheck should only be used on modules. However, it was found annotating"
- + " %s",
- element);
+ public DisableInstallInCheckProcessingStep processingStep() {
+ return new DisableInstallInCheckProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/KspDisableInstallInCheckProcessor.java b/java/dagger/hilt/processor/internal/disableinstallincheck/KspDisableInstallInCheckProcessor.java
new file mode 100644
index 0000000..98ff17a
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/disableinstallincheck/KspDisableInstallInCheckProcessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.disableinstallincheck;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Processes the annotations annotated with {@link dagger.hilt.migration.DisableInstallInCheck} */
+public final class KspDisableInstallInCheckProcessor extends KspBaseProcessingStepProcessor {
+ public KspDisableInstallInCheckProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ public DisableInstallInCheckProcessingStep processingStep() {
+ return new DisableInstallInCheckProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspDisableInstallInCheckProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspDisableInstallInCheckProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java
index ae34118..bfe11a7 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointGenerator.java
@@ -16,35 +16,29 @@
package dagger.hilt.processor.internal.earlyentrypoint;
+import androidx.room.compiler.processing.XTypeElement;
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 XTypeElement earlyEntryPoint;
- private final ProcessingEnvironment env;
- private final TypeElement earlyEntryPoint;
-
- AggregatedEarlyEntryPointGenerator(TypeElement earlyEntryPoint, ProcessingEnvironment env) {
+ AggregatedEarlyEntryPointGenerator(XTypeElement earlyEntryPoint) {
this.earlyEntryPoint = earlyEntryPoint;
- this.env = env;
}
- void generate() throws IOException {
+ void generate() {
Processors.generateAggregatingClass(
ClassNames.AGGREGATED_EARLY_ENTRY_POINT_PACKAGE,
AnnotationSpec.builder(ClassNames.AGGREGATED_EARLY_ENTRY_POINT)
.addMember("earlyEntryPoint", "$S", earlyEntryPoint.getQualifiedName())
.build(),
earlyEntryPoint,
- getClass(),
- env);
+ getClass());
}
}
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java
index cf88757..35d3720 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/AggregatedEarlyEntryPointMetadata.java
@@ -16,21 +16,17 @@
package dagger.hilt.processor.internal.earlyentrypoint;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
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 dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr;
-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
@@ -40,44 +36,39 @@
public abstract class AggregatedEarlyEntryPointMetadata {
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
/** Returns the element annotated with {@link dagger.hilt.android.EarlyEntryPoint}. */
- public abstract TypeElement earlyEntryPoint();
+ public abstract XTypeElement earlyEntryPoint();
/** Returns metadata for all aggregated elements in the aggregating package. */
- public static ImmutableSet<AggregatedEarlyEntryPointMetadata> from(Elements elements) {
+ public static ImmutableSet<AggregatedEarlyEntryPointMetadata> from(XProcessingEnv env) {
return from(
AggregatedElements.from(
ClassNames.AGGREGATED_EARLY_ENTRY_POINT_PACKAGE,
ClassNames.AGGREGATED_EARLY_ENTRY_POINT,
- elements),
- elements);
+ env));
}
/** Returns metadata for each aggregated element. */
public static ImmutableSet<AggregatedEarlyEntryPointMetadata> from(
- ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ ImmutableSet<XTypeElement> aggregatedElements) {
return aggregatedElements.stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ .map(aggregatedElement -> create(aggregatedElement, getProcessingEnv(aggregatedElement)))
.collect(toImmutableSet());
}
public static AggregatedEarlyEntryPointIr toIr(AggregatedEarlyEntryPointMetadata metadata) {
return new AggregatedEarlyEntryPointIr(
- ClassName.get(metadata.aggregatingElement()),
- ClassName.get(metadata.earlyEntryPoint()).canonicalName());
+ metadata.aggregatingElement().getClassName(),
+ metadata.earlyEntryPoint().getClassName().canonicalName());
}
- 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);
+ private static AggregatedEarlyEntryPointMetadata create(
+ XTypeElement element, XProcessingEnv env) {
+ XAnnotation annotation = element.getAnnotation(ClassNames.AGGREGATED_EARLY_ENTRY_POINT);
return new AutoValue_AggregatedEarlyEntryPointMetadata(
- element,
- elements.getTypeElement(AnnotationValues.getString(values.get("earlyEntryPoint"))));
+ element, env.requireTypeElement(annotation.getAsString("earlyEntryPoint")));
}
}
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
index 7bbc90c..81607e9 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/BUILD
@@ -28,17 +28,20 @@
name = "processor_lib",
srcs = [
"AggregatedEarlyEntryPointGenerator.java",
+ "EarlyEntryPointProcessingStep.java",
"EarlyEntryPointProcessor.java",
+ "KspEarlyEntryPointProcessor.java",
],
deps = [
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -53,6 +56,7 @@
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessingStep.java b/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessingStep.java
new file mode 100644
index 0000000..f2fa9a0
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessingStep.java
@@ -0,0 +1,43 @@
+/*
+ * 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.xprocessing.XElements.asTypeElement;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+
+/** Validates {@link dagger.hilt.android.EarlyEntryPoint} usages. */
+public final class EarlyEntryPointProcessingStep extends BaseProcessingStep {
+ public EarlyEntryPointProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ public ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.EARLY_ENTRY_POINT);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ new AggregatedEarlyEntryPointGenerator(asTypeElement(element)).generate();
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java b/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java
index 848fa31..8454f6c 100644
--- a/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/EarlyEntryPointProcessor.java
@@ -16,30 +16,19 @@
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 dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
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 {
-
+public final class EarlyEntryPointProcessor extends JavacBaseProcessingStepProcessor {
@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();
+ public EarlyEntryPointProcessingStep processingStep() {
+ return new EarlyEntryPointProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/earlyentrypoint/KspEarlyEntryPointProcessor.java b/java/dagger/hilt/processor/internal/earlyentrypoint/KspEarlyEntryPointProcessor.java
new file mode 100644
index 0000000..04c93da
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/earlyentrypoint/KspEarlyEntryPointProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Validates {@link dagger.hilt.android.EarlyEntryPoint} usages. */
+public final class KspEarlyEntryPointProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspEarlyEntryPointProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ public EarlyEntryPointProcessingStep processingStep() {
+ return new EarlyEntryPointProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspEarlyEntryPointProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspEarlyEntryPointProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
index 2b56408..afd611f 100644
--- a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
@@ -27,8 +27,10 @@
java_library(
name = "processor_lib",
srcs = [
+ "GeneratesRootInputProcessingStep.java",
"GeneratesRootInputProcessor.java",
"GeneratesRootInputPropagatedDataGenerator.java",
+ "KspGeneratesRootInputProcessor.java",
],
deps = [
":generates_root_inputs",
@@ -36,10 +38,12 @@
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -53,6 +57,7 @@
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessingStep.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessingStep.java
new file mode 100644
index 0000000..f464dc4
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessingStep.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 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.generatesrootinput;
+
+import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.internal.codegen.xprocessing.XElements;
+
+/**
+ * Processes the annotations annotated with {@link dagger.hilt.GeneratesRootInput} which generate
+ * input for components and should be processed before component creation.
+ */
+public final class GeneratesRootInputProcessingStep extends BaseProcessingStep {
+ public GeneratesRootInputProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.GENERATES_ROOT_INPUT);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ ProcessorErrors.checkState(
+ isTypeElement(element) && asTypeElement(element).isAnnotationClass(),
+ element,
+ "%s should only annotate other annotations. However, it was found annotating %s",
+ annotation.simpleName(),
+ XElements.toStableString(element));
+
+ new GeneratesRootInputPropagatedDataGenerator(processingEnv(), asTypeElement(element))
+ .generate();
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java
index 6588e09..afd4cba 100644
--- a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java
@@ -19,15 +19,8 @@
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 dagger.hilt.processor.internal.ProcessorErrors;
-import java.util.Set;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/**
@@ -36,22 +29,9 @@
*/
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class GeneratesRootInputProcessor extends BaseProcessor {
-
+public final class GeneratesRootInputProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.GENERATES_ROOT_INPUT.toString());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- ProcessorErrors.checkState(
- element.getKind().equals(ElementKind.ANNOTATION_TYPE),
- element,
- "%s should only annotate other annotations. However, it was found annotating %s",
- annotation,
- element);
-
- new GeneratesRootInputPropagatedDataGenerator(this.getProcessingEnv(), element).generate();
+ public GeneratesRootInputProcessingStep processingStep() {
+ return new GeneratesRootInputProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java
index 5c53894..f0c08e0 100644
--- a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java
@@ -16,41 +16,40 @@
package dagger.hilt.processor.internal.generatesrootinput;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
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.Element;
/** Generates resource files for {@link GeneratesRootInputs}. */
final class GeneratesRootInputPropagatedDataGenerator {
- private final ProcessingEnvironment processingEnv;
- private final Element element;
+ private final XProcessingEnv processingEnv;
+ private final XTypeElement element;
- GeneratesRootInputPropagatedDataGenerator(ProcessingEnvironment processingEnv, Element element) {
+ GeneratesRootInputPropagatedDataGenerator(XProcessingEnv processingEnv, XTypeElement element) {
this.processingEnv = processingEnv;
this.element = element;
}
- void generate() throws IOException {
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(Processors.getFullEnclosedName(element))
- .addOriginatingElement(element)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA)
- .addMember("value", "$T.class", element)
- .build())
- .addJavadoc(
- "Generated class to"
- + "get the list of annotations that generate input for root.\n");
+ void generate() {
+ TypeSpec.Builder generator = TypeSpec.classBuilder(Processors.getFullEnclosedName(element));
+
+ JavaPoetExtKt.addOriginatingElement(generator, element)
+ .addAnnotation(
+ AnnotationSpec.builder(ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA)
+ .addMember("value", "$T.class", element.getClassName())
+ .build())
+ .addJavadoc(
+ "Generated class to get the list of annotations that generate input for root.\n");
Processors.addGeneratedAnnotation(generator, processingEnv, getClass());
-
- JavaFile.builder(GeneratesRootInputs.AGGREGATING_PACKAGE, generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
+ JavaFile javaFile =
+ JavaFile.builder(GeneratesRootInputs.AGGREGATING_PACKAGE, generator.build()).build();
+ processingEnv.getFiler().write(javaFile, Mode.Isolating);
}
}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java
index 139592e..eb1a8ee 100644
--- a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java
@@ -16,87 +16,79 @@
package dagger.hilt.processor.internal.generatesrootinput;
-import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Suppliers.memoize;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XAnnotations;
import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-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;
/** Extracts the list of annotations annotated with {@link dagger.hilt.GeneratesRootInput}. */
public final class GeneratesRootInputs {
static final String AGGREGATING_PACKAGE =
GeneratesRootInputs.class.getPackage().getName() + ".codegen";
- private final Elements elements;
+ private final XProcessingEnv env;
private final Supplier<ImmutableList<ClassName>> generatesRootInputAnnotations =
memoize(() -> getAnnotationList());
- public GeneratesRootInputs(ProcessingEnvironment processingEnvironment) {
- this.elements = processingEnvironment.getElementUtils();
+ public GeneratesRootInputs(XProcessingEnv processingEnvironment) {
+ this.env = processingEnvironment;
}
- public ImmutableSet<Element> getElementsToWaitFor(RoundEnvironment roundEnv) {
+ public ImmutableSet<XElement> getElementsToWaitFor(XRoundEnv roundEnv) {
// Processing can only take place after all dependent annotations have been processed
// Note: We start with ClassName rather than TypeElement because jdk8 does not treat type
// elements as equal across rounds. Thus, in order for RoundEnvironment#getElementsAnnotatedWith
// to work properly, we get new elements to ensure it works across rounds (See b/148693284).
return generatesRootInputAnnotations.get().stream()
- .map(className -> elements.getTypeElement(className.toString()))
+ .map(className -> env.findTypeElement(className.toString()))
.filter(element -> element != null)
- .flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream())
+ .flatMap(
+ annotation -> roundEnv.getElementsAnnotatedWith(annotation.getQualifiedName()).stream())
.collect(toImmutableSet());
}
private ImmutableList<ClassName> getAnnotationList() {
- PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE);
-
- if (packageElement == null) {
- return ImmutableList.of();
- }
-
- List<? extends Element> annotationElements = packageElement.getEnclosedElements();
- checkState(!annotationElements.isEmpty(), "No elements Found in package %s.", packageElement);
+ List<? extends XTypeElement> annotationElements =
+ env.getTypeElementsFromPackage(AGGREGATING_PACKAGE);
ImmutableList.Builder<ClassName> builder = ImmutableList.builder();
- for (Element element : annotationElements) {
+ for (XTypeElement element : annotationElements) {
ProcessorErrors.checkState(
- element.getKind() == ElementKind.CLASS,
+ element.isClass(),
element,
"Only classes may be in package %s. Did you add custom code in the package?",
- packageElement);
+ AGGREGATING_PACKAGE);
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA);
+ XAnnotation annotation =
+ element.getAnnotation(ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA);
ProcessorErrors.checkState(
- annotationMirror != null,
+ annotation != 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,
+ AGGREGATING_PACKAGE,
ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA,
- element.getSimpleName(),
- element.getAnnotationMirrors());
+ element.getClassName().simpleName(),
+ element.getAllAnnotations().stream()
+ .map(XAnnotations::toStableString)
+ .collect(toImmutableSet()));
- TypeElement annotation =
- Processors.getAnnotationClassValue(elements, annotationMirror, "value");
+ XTypeElement value = annotation.getAsType("value").getTypeElement();
- builder.add(ClassName.get(annotation));
+ builder.add(value.getClassName());
}
// This annotation was on Dagger so it couldn't be annotated with @GeneratesRootInput to be
// cultivated later. We have to manually add it to the list.
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/KspGeneratesRootInputProcessor.java b/java/dagger/hilt/processor/internal/generatesrootinput/KspGeneratesRootInputProcessor.java
new file mode 100644
index 0000000..e9ffee5
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/generatesrootinput/KspGeneratesRootInputProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.generatesrootinput;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/**
+ * Processes the annotations annotated with {@link dagger.hilt.GeneratesRootInput} which generate
+ * input for components and should be processed before component creation.
+ */
+public final class KspGeneratesRootInputProcessor extends KspBaseProcessingStepProcessor {
+ public KspGeneratesRootInputProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected GeneratesRootInputProcessingStep processingStep() {
+ return new GeneratesRootInputProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspGeneratesRootInputProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspGeneratesRootInputProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/kotlin/BUILD b/java/dagger/hilt/processor/internal/kotlin/BUILD
index 5705393..437ea0f 100644
--- a/java/dagger/hilt/processor/internal/kotlin/BUILD
+++ b/java/dagger/hilt/processor/internal/kotlin/BUILD
@@ -25,9 +25,8 @@
deps = [
"//:dagger_with_compiler",
"//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:element_descriptors",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
diff --git a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java
index 4d7c1fc..e98b2b3 100644
--- a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java
+++ b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadata.java
@@ -16,34 +16,27 @@
package dagger.hilt.processor.internal.kotlin;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
-import static com.google.auto.common.AnnotationValues.getAnnotationValues;
-import static com.google.auto.common.MoreElements.getAnnotationMirror;
-import static dagger.hilt.processor.internal.ElementDescriptors.getMethodDescriptor;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static kotlinx.metadata.Flag.ValueParameter.DECLARES_DEFAULT_VALUE;
-import com.google.auto.common.AnnotationValues;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ElementDescriptors;
import dagger.internal.codegen.extension.DaggerCollectors;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nullable;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementFilter;
import kotlin.Metadata;
import kotlinx.metadata.Flag;
import kotlinx.metadata.KmClass;
@@ -65,21 +58,21 @@
private static final String DELEGATED_PROPERTY_NAME_SUFFIX = "$delegate";
// Map that associates field elements with its Kotlin synthetic method for annotations.
- private final Map<VariableElement, Optional<MethodForAnnotations>>
- elementFieldAnnotationMethodMap = new HashMap<>();
-
- // Map that associates field elements with its Kotlin getter method.
- private final Map<VariableElement, Optional<ExecutableElement>> elementFieldGetterMethodMap =
+ private final Map<XFieldElement, Optional<MethodForAnnotations>> elementFieldAnnotationMethodMap =
new HashMap<>();
- abstract TypeElement typeElement();
+ // Map that associates field elements with its Kotlin getter method.
+ private final Map<XFieldElement, Optional<XMethodElement>> elementFieldGetterMethodMap =
+ new HashMap<>();
+
+ abstract XTypeElement typeElement();
abstract ClassMetadata classMetadata();
@Memoized
- ImmutableMap<String, ExecutableElement> methodDescriptors() {
- return ElementFilter.methodsIn(typeElement().getEnclosedElements()).stream()
- .collect(toImmutableMap(ElementDescriptors::getMethodDescriptor, Function.identity()));
+ ImmutableMap<String, XMethodElement> methodDescriptors() {
+ return typeElement().getDeclaredMethods().stream()
+ .collect(toImmutableMap(XMethodElement::getJvmDescriptor, Function.identity()));
}
/** Returns true if any constructor of the defined a default parameter. */
@@ -91,7 +84,7 @@
}
/** Gets the synthetic method for annotations of a given field element. */
- Optional<ExecutableElement> getSyntheticAnnotationMethod(VariableElement fieldElement) {
+ Optional<XMethodElement> getSyntheticAnnotationMethod(XFieldElement fieldElement) {
return getAnnotationMethod(fieldElement)
.map(
methodForAnnotations -> {
@@ -99,29 +92,16 @@
throw new IllegalStateException(
"Method for annotations is missing for " + fieldElement);
}
- return methodForAnnotations.method();
+ return XElements.asMethod(methodForAnnotations.method());
});
}
- /**
- * Returns true if the synthetic method for annotations is missing. This can occur when inspecting
- * the Kotlin metadata of a property from another compilation unit.
- */
- boolean isMissingSyntheticAnnotationMethod(VariableElement fieldElement) {
- return getAnnotationMethod(fieldElement)
- .map(methodForAnnotations -> methodForAnnotations == MethodForAnnotations.MISSING)
- // This can be missing if there was no property annotation at all (e.g. no annotations or
- // the qualifier is already properly attached to the field). For these cases, it isn't
- // considered missing since there was no method to look for in the first place.
- .orElse(false);
- }
-
- private Optional<MethodForAnnotations> getAnnotationMethod(VariableElement fieldElement) {
+ private Optional<MethodForAnnotations> getAnnotationMethod(XFieldElement fieldElement) {
return elementFieldAnnotationMethodMap.computeIfAbsent(
fieldElement, this::getAnnotationMethodUncached);
}
- private Optional<MethodForAnnotations> getAnnotationMethodUncached(VariableElement fieldElement) {
+ private Optional<MethodForAnnotations> getAnnotationMethodUncached(XFieldElement fieldElement) {
return findProperty(fieldElement)
.methodForAnnotationsSignature()
.map(
@@ -134,19 +114,19 @@
}
/** Gets the getter method of a given field element corresponding to a property. */
- Optional<ExecutableElement> getPropertyGetter(VariableElement fieldElement) {
+ Optional<XMethodElement> getPropertyGetter(XFieldElement fieldElement) {
return elementFieldGetterMethodMap.computeIfAbsent(
fieldElement, this::getPropertyGetterUncached);
}
- private Optional<ExecutableElement> getPropertyGetterUncached(VariableElement fieldElement) {
+ private Optional<XMethodElement> getPropertyGetterUncached(XFieldElement fieldElement) {
return findProperty(fieldElement)
.getterSignature()
.flatMap(signature -> Optional.ofNullable(methodDescriptors().get(signature)));
}
- private PropertyMetadata findProperty(VariableElement field) {
- String fieldDescriptor = ElementDescriptors.getFieldDescriptor(field);
+ private PropertyMetadata findProperty(XFieldElement field) {
+ String fieldDescriptor = field.getJvmDescriptor();
if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) {
return classMetadata().propertiesByFieldSignature().get(fieldDescriptor);
} else {
@@ -158,8 +138,8 @@
}
}
- private static String getPropertyNameFromField(VariableElement field) {
- String name = field.getSimpleName().toString();
+ private static String getPropertyNameFromField(XFieldElement field) {
+ String name = XElements.getSimpleName(field);
if (name.endsWith(DELEGATED_PROPERTY_NAME_SUFFIX)) {
return name.substring(0, name.length() - DELEGATED_PROPERTY_NAME_SUFFIX.length());
} else {
@@ -167,27 +147,22 @@
}
}
- FunctionMetadata getFunctionMetadata(ExecutableElement method) {
- return classMetadata().functionsBySignature().get(getMethodDescriptor(method));
- }
-
/** Parse Kotlin class metadata from a given type element. */
- static KotlinMetadata from(TypeElement typeElement) {
+ static KotlinMetadata from(XTypeElement typeElement) {
return new AutoValue_KotlinMetadata(typeElement, ClassMetadata.create(metadataOf(typeElement)));
}
- private static KotlinClassMetadata.Class metadataOf(TypeElement typeElement) {
- AnnotationMirror annotationMirror =
- getAnnotationMirror(typeElement, ClassNames.KOTLIN_METADATA.canonicalName()).get();
+ private static KotlinClassMetadata.Class metadataOf(XTypeElement typeElement) {
+ XAnnotation annotation = typeElement.getAnnotation(ClassNames.KOTLIN_METADATA);
Metadata metadataAnnotation =
JvmMetadataUtil.Metadata(
- getIntValue(annotationMirror, "k"),
- getIntArrayValue(annotationMirror, "mv"),
- getStringArrayValue(annotationMirror, "d1"),
- getStringArrayValue(annotationMirror, "d2"),
- getStringValue(annotationMirror, "xs"),
- getOptionalStringValue(annotationMirror, "pn").orElse(null),
- getOptionalIntValue(annotationMirror, "xi").orElse(null));
+ annotation.getAsInt("k"),
+ annotation.getAsIntList("mv").stream().mapToInt(Integer::intValue).toArray(),
+ annotation.getAsStringList("d1").toArray(new String[0]),
+ annotation.getAsStringList("d2").toArray(new String[0]),
+ annotation.getAsString("xs"),
+ getOptionalStringValue(annotation, "pn").orElse(null),
+ getOptionalIntValue(annotation, "xi").orElse(null));
KotlinClassMetadata metadata = KotlinClassMetadata.read(metadataAnnotation);
if (metadata == null) {
// Can happen if Kotlin < 1.0 or if metadata version is not supported, i.e.
@@ -376,52 +351,30 @@
@AutoValue
abstract static class MethodForAnnotations {
- static MethodForAnnotations create(ExecutableElement method) {
+ static MethodForAnnotations create(XMethodElement method) {
return new AutoValue_KotlinMetadata_MethodForAnnotations(method);
}
static final MethodForAnnotations MISSING = MethodForAnnotations.create(null);
@Nullable
- abstract ExecutableElement method();
+ abstract XMethodElement method();
}
- private static int getIntValue(AnnotationMirror annotation, String valueName) {
- return AnnotationValues.getInt(getAnnotationValue(annotation, valueName));
- }
-
- private static Optional<Integer> getOptionalIntValue(
- AnnotationMirror annotation, String valueName) {
+ private static Optional<Integer> getOptionalIntValue(XAnnotation annotation, String valueName) {
return isValuePresent(annotation, valueName)
- ? Optional.of(getIntValue(annotation, valueName))
+ ? Optional.of(annotation.getAsInt(valueName))
: Optional.empty();
}
- private static int[] getIntArrayValue(AnnotationMirror annotation, String valueName) {
- return getAnnotationValues(getAnnotationValue(annotation, valueName)).stream()
- .mapToInt(AnnotationValues::getInt)
- .toArray();
- }
-
- private static String getStringValue(AnnotationMirror annotation, String valueName) {
- return AnnotationValues.getString(getAnnotationValue(annotation, valueName));
- }
-
- private static Optional<String> getOptionalStringValue(
- AnnotationMirror annotation, String valueName) {
+ private static Optional<String> getOptionalStringValue(XAnnotation annotation, String valueName) {
return isValuePresent(annotation, valueName)
- ? Optional.of(getStringValue(annotation, valueName))
+ ? Optional.of(annotation.getAsString(valueName))
: Optional.empty();
}
- private static String[] getStringArrayValue(AnnotationMirror annotation, String valueName) {
- return getAnnotationValues(getAnnotationValue(annotation, valueName)).stream()
- .map(AnnotationValues::getString)
- .toArray(String[]::new);
- }
-
- private static boolean isValuePresent(AnnotationMirror annotation, String valueName) {
- return getAnnotationValuesWithDefaults(annotation).keySet().stream()
- .anyMatch(member -> member.getSimpleName().contentEquals(valueName));
+ private static boolean isValuePresent(XAnnotation annotation, String valueName) {
+ return annotation.getAnnotationValues().stream()
+ .anyMatch(member -> member.getName().equals(valueName));
}
}
diff --git a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataFactory.java b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataFactory.java
index 9988340..65138fe 100644
--- a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataFactory.java
+++ b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataFactory.java
@@ -16,15 +16,16 @@
package dagger.hilt.processor.internal.kotlin;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XTypeElement;
import dagger.hilt.processor.internal.ClassNames;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
/**
* Factory creating Kotlin metadata data objects.
@@ -34,7 +35,7 @@
*/
@Singleton
public final class KotlinMetadataFactory {
- private final Map<TypeElement, KotlinMetadata> metadataCache = new HashMap<>();
+ private final Map<XTypeElement, KotlinMetadata> metadataCache = new HashMap<>();
@Inject
KotlinMetadataFactory() {}
@@ -44,11 +45,11 @@
*
* @throws IllegalStateException if the element has no metadata or is not enclosed in a type
* element with metadata. To check if an element has metadata use {@link
- * KotlinMetadataUtil#hasMetadata(Element)}
+ * KotlinMetadataUtil#hasMetadata(XElement)}
*/
- public KotlinMetadata create(Element element) {
- TypeElement enclosingElement = KotlinMetadataUtil.closestEnclosingTypeElement(element);
- if (!isAnnotationPresent(enclosingElement, ClassNames.KOTLIN_METADATA.canonicalName())) {
+ public KotlinMetadata create(XElement element) {
+ XTypeElement enclosingElement = XElements.closestEnclosingTypeElement(element);
+ if (!enclosingElement.hasAnnotation(ClassNames.KOTLIN_METADATA)) {
throw new IllegalStateException("Missing @Metadata for: " + enclosingElement);
}
return metadataCache.computeIfAbsent(enclosingElement, KotlinMetadata::from);
diff --git a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataUtil.java b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataUtil.java
index b98ce58..771a4b8 100644
--- a/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataUtil.java
+++ b/java/dagger/hilt/processor/internal/kotlin/KotlinMetadataUtil.java
@@ -16,32 +16,26 @@
package dagger.hilt.processor.internal.kotlin;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreElements.isType;
-import static com.google.common.base.Preconditions.checkState;
+import static androidx.room.compiler.processing.XElementKt.isField;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static kotlinx.metadata.Flag.Class.IS_COMPANION_OBJECT;
-import static kotlinx.metadata.Flag.Class.IS_DATA;
-import static kotlinx.metadata.Flag.Class.IS_OBJECT;
-import static kotlinx.metadata.Flag.IS_PRIVATE;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XElements.asField;
+import static dagger.internal.codegen.xprocessing.XElements.isStatic;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFieldElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.base.Equivalence;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadata.FunctionMetadata;
-import dagger.internal.codegen.extension.DaggerCollectors;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.Optional;
import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementFilter;
-import kotlin.Metadata;
-import kotlinx.metadata.Flag;
/** Utility class for interacting with Kotlin Metadata. */
public final class KotlinMetadataUtil {
@@ -57,8 +51,63 @@
* Returns {@code true} if this element has the Kotlin Metadata annotation or if it is enclosed in
* an element that does.
*/
- public boolean hasMetadata(Element element) {
- return isAnnotationPresent(closestEnclosingTypeElement(element), Metadata.class);
+ public boolean hasMetadata(XElement element) {
+ return XElements.closestEnclosingTypeElement(element).hasAnnotation(ClassNames.KOTLIN_METADATA);
+ }
+
+ // TODO(kuanyingchou): Consider replacing it with `XAnnotated.getAnnotationsAnnotatedWith()`
+ // once b/278077018 is resolved.
+ /**
+ * Returns the annotations on the given {@code element} annotated with {@code annotationName}.
+ *
+ * <p>Note: If the given {@code element} is a non-static field this method will return annotations
+ * on both the backing field and the associated synthetic property (if one exists).
+ */
+ public ImmutableList<XAnnotation> getAnnotationsAnnotatedWith(
+ XElement element, ClassName annotationName) {
+ return getAnnotations(element).stream()
+ .filter(annotation -> annotation.getTypeElement().hasAnnotation(annotationName))
+ .collect(toImmutableList());
+ }
+
+ /**
+ * Returns the annotations on the given {@code element} that match the {@code annotationName}.
+ *
+ * <p>Note: If the given {@code element} is a non-static field this method will return annotations
+ * on both the backing field and the associated synthetic property (if one exists).
+ */
+ private ImmutableList<XAnnotation> getAnnotations(XElement element) {
+ ImmutableList<XAnnotation> annotations = ImmutableList.copyOf(element.getAllAnnotations());
+ ImmutableList<XAnnotation> syntheticAnnotations = getSyntheticPropertyAnnotations(element);
+ if (syntheticAnnotations.isEmpty()) {
+ return annotations;
+ }
+ // Dedupe any annotation that appears on both the field and the property.
+ // Note: we reduce the number of annotations we have to dedupe by only checking equivalence on
+ // annotations that have the same class name as a synthetic annotation. This avoids hitting
+ // TypeNotPresentException on annotation values with error types unless it has the same class
+ // name as a synthetic annotation.
+ ImmutableSet<ClassName> syntheticAnnotationClassNames =
+ syntheticAnnotations.stream()
+ .map(XAnnotations::getClassName)
+ .collect(toImmutableSet());
+ ImmutableSet<Equivalence.Wrapper<XAnnotation>> annotationEquivalenceWrappers =
+ annotations.stream()
+ .filter(annotation -> syntheticAnnotationClassNames.contains(annotation.getClassName()))
+ .map(XAnnotations.equivalence()::wrap)
+ .collect(toImmutableSet());
+ ImmutableList<XAnnotation> uniqueSyntheticAnnotations =
+ syntheticAnnotations.stream()
+ .map(XAnnotations.equivalence()::wrap)
+ .filter(wrapper -> !annotationEquivalenceWrappers.contains(wrapper))
+ .map(Equivalence.Wrapper::get)
+ .collect(toImmutableList());
+ return uniqueSyntheticAnnotations.isEmpty()
+ ? annotations
+ : ImmutableList.<XAnnotation>builder()
+ .addAll(annotations)
+ .addAll(uniqueSyntheticAnnotations)
+ .build();
}
/**
@@ -67,135 +116,29 @@
* <p>Note that this method only looks for additional annotations in the synthetic property
* method, if any, of a Kotlin property and not for annotations in its backing field.
*/
- public ImmutableList<? extends AnnotationMirror> getSyntheticPropertyAnnotations(
- VariableElement fieldElement, ClassName annotationType) {
- return metadataFactory
- .create(fieldElement)
- .getSyntheticAnnotationMethod(fieldElement)
- .map(methodElement -> getAnnotationsAnnotatedWith(methodElement, annotationType))
- .orElse(ImmutableList.of());
+ private ImmutableList<XAnnotation> getSyntheticPropertyAnnotations(XElement element) {
+ // Currently, we avoid trying to get annotations from properties on object class's (i.e.
+ // properties with static jvm backing fields) due to issues explained in CL/336150864.
+ if (!isField(element) || isStatic(element)) {
+ return ImmutableList.of();
+ }
+ XFieldElement field = asField(element);
+ return hasMetadata(field)
+ ? metadataFactory
+ .create(field)
+ .getSyntheticAnnotationMethod(field)
+ .map(XMethodElement::getAllAnnotations)
+ .map(ImmutableList::copyOf)
+ .orElse(ImmutableList.<XAnnotation>of())
+ : ImmutableList.of();
}
- /** Returns annotations of element that are annotated with subAnnotation */
- private static ImmutableList<AnnotationMirror> getAnnotationsAnnotatedWith(
- Element element, ClassName subAnnotation) {
- return element.getAnnotationMirrors().stream()
- .filter(
- annotation ->
- isAnnotationPresent(
- annotation.getAnnotationType().asElement(), subAnnotation.canonicalName()))
- .collect(toImmutableList());
- }
-
- /**
- * Returns {@code true} if the synthetic method for annotations is missing. This can occur when
- * the Kotlin metadata of the property reports that it contains a synthetic method for annotations
- * but such method is not found since it is synthetic and ignored by the processor.
- */
- public boolean isMissingSyntheticPropertyForAnnotations(VariableElement fieldElement) {
- return metadataFactory.create(fieldElement).isMissingSyntheticAnnotationMethod(fieldElement);
- }
-
- /** Returns {@code true} if this type element is a Kotlin Object. */
- public boolean isObjectClass(TypeElement typeElement) {
- return hasMetadata(typeElement)
- && metadataFactory.create(typeElement).classMetadata().flags(IS_OBJECT);
- }
-
- /** Returns {@code true} if this type element is a Kotlin data class. */
- public boolean isDataClass(TypeElement typeElement) {
- return hasMetadata(typeElement)
- && metadataFactory.create(typeElement).classMetadata().flags(IS_DATA);
- }
-
- /* Returns {@code true} if this type element is a Kotlin Companion Object. */
- public boolean isCompanionObjectClass(TypeElement typeElement) {
- return hasMetadata(typeElement)
- && metadataFactory.create(typeElement).classMetadata().flags(IS_COMPANION_OBJECT);
- }
-
- /** Returns {@code true} if this type element is a Kotlin object or companion object. */
- public boolean isObjectOrCompanionObjectClass(TypeElement typeElement) {
- return isObjectClass(typeElement) || isCompanionObjectClass(typeElement);
- }
-
- /* Returns {@code true} if this type element has a Kotlin Companion Object. */
- public boolean hasEnclosedCompanionObject(TypeElement typeElement) {
- return hasMetadata(typeElement)
- && metadataFactory.create(typeElement).classMetadata().companionObjectName().isPresent();
- }
-
- /* Returns the Companion Object element enclosed by the given type element. */
- public TypeElement getEnclosedCompanionObject(TypeElement typeElement) {
- return metadataFactory
- .create(typeElement)
- .classMetadata()
- .companionObjectName()
- .map(
- companionObjectName ->
- ElementFilter.typesIn(typeElement.getEnclosedElements()).stream()
- .filter(
- innerType -> innerType.getSimpleName().contentEquals(companionObjectName))
- .collect(DaggerCollectors.onlyElement()))
- .get();
- }
-
- /**
- * Returns {@code true} if the given type element was declared <code>private</code> in its Kotlin
- * source.
- */
- public boolean isVisibilityPrivate(TypeElement typeElement) {
- return hasMetadata(typeElement)
- && metadataFactory.create(typeElement).classMetadata().flags(IS_PRIVATE);
- }
-
- /**
- * Returns {@code true} if the given type element was declared {@code internal} in its Kotlin
- * source.
- */
- public boolean isVisibilityInternal(TypeElement type) {
- return hasMetadata(type)
- && metadataFactory.create(type).classMetadata().flags(Flag.IS_INTERNAL);
- }
-
- /**
- * Returns {@code true} if the given executable element was declared {@code internal} in its
- * Kotlin source.
- */
- public boolean isVisibilityInternal(ExecutableElement method) {
- return hasMetadata(method)
- && metadataFactory.create(method).getFunctionMetadata(method).flags(Flag.IS_INTERNAL);
- }
-
- public Optional<ExecutableElement> getPropertyGetter(VariableElement fieldElement) {
+ public Optional<XMethodElement> getPropertyGetter(XFieldElement fieldElement) {
return metadataFactory.create(fieldElement).getPropertyGetter(fieldElement);
}
- public boolean containsConstructorWithDefaultParam(TypeElement typeElement) {
+ public boolean containsConstructorWithDefaultParam(XTypeElement typeElement) {
return hasMetadata(typeElement)
&& metadataFactory.create(typeElement).containsConstructorWithDefaultParam();
}
-
- /**
- * Returns a map mapping all method signatures within the given class element, including methods
- * that it inherits from its ancestors, to their method names.
- */
- public ImmutableMap<String, String> getAllMethodNamesBySignature(TypeElement element) {
- checkState(
- hasMetadata(element), "Can not call getAllMethodNamesBySignature for non-Kotlin class");
- return metadataFactory.create(element).classMetadata().functionsBySignature().values().stream()
- .collect(toImmutableMap(FunctionMetadata::signature, FunctionMetadata::name));
- }
-
- /** Returns the argument or the closest enclosing element that is a {@link TypeElement}. */
- static TypeElement closestEnclosingTypeElement(Element element) {
- Element current = element;
- while (current != null) {
- if (isType(current)) {
- return asType(current);
- }
- current = current.getEnclosingElement();
- }
- throw new IllegalStateException("There is no enclosing TypeElement for: " + element);
- }
}
diff --git a/java/dagger/hilt/processor/internal/originatingelement/BUILD b/java/dagger/hilt/processor/internal/originatingelement/BUILD
index 8942535..f4a279a 100644
--- a/java/dagger/hilt/processor/internal/originatingelement/BUILD
+++ b/java/dagger/hilt/processor/internal/originatingelement/BUILD
@@ -27,6 +27,8 @@
java_library(
name = "processor_lib",
srcs = [
+ "KspOriginatingElementProcessor.java",
+ "OriginatingElementProcessingStep.java",
"OriginatingElementProcessor.java",
],
deps = [
@@ -34,10 +36,12 @@
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
+ "//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
diff --git a/java/dagger/hilt/processor/internal/originatingelement/KspOriginatingElementProcessor.java b/java/dagger/hilt/processor/internal/originatingelement/KspOriginatingElementProcessor.java
new file mode 100644
index 0000000..51926e1
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/originatingelement/KspOriginatingElementProcessor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.hilt.processor.internal.originatingelement;
+
+import com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/**
+ * Processes the annotations annotated with {@link dagger.hilt.codegen.OriginatingElement} to check
+ * that they're only used on top-level classes and the value passed is also a top-level class.
+ */
+public final class KspOriginatingElementProcessor extends KspBaseProcessingStepProcessor {
+ private KspOriginatingElementProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new OriginatingElementProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspOriginatingElemenetProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspOriginatingElementProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessingStep.java b/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessingStep.java
new file mode 100644
index 0000000..d0f0ab9
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessingStep.java
@@ -0,0 +1,69 @@
+/*
+ * 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.originatingelement;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XElementKt;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XElements;
+
+/**
+ * Processes the annotations annotated with {@link dagger.hilt.codegen.OriginatingElement} to check
+ * that they're only used on top-level classes and the value passed is also a top-level class.
+ */
+public final class OriginatingElementProcessingStep extends BaseProcessingStep {
+
+ public OriginatingElementProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.ORIGINATING_ELEMENT);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ ProcessorErrors.checkState(
+ XElementKt.isTypeElement(element) && Processors.isTopLevel(element),
+ element,
+ "@%s should only be used to annotate top-level types, but found: %s",
+ annotation.simpleName(),
+ XElements.toStableString(element));
+
+ XTypeElement topLevelClassElement =
+ element
+ .getAnnotation(ClassNames.ORIGINATING_ELEMENT)
+ .getAsType("topLevelClass")
+ .getTypeElement();
+
+ // TODO(bcorso): ProcessorErrors should allow us to point to the annotation too.
+ ProcessorErrors.checkState(
+ Processors.isTopLevel(topLevelClassElement),
+ element,
+ "@%s.topLevelClass value should be a top-level class, but found: %s",
+ annotation.simpleName(),
+ topLevelClassElement.getClassName());
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java b/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java
index 723cf04..23cc2de 100644
--- a/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java
+++ b/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java
@@ -18,16 +18,9 @@
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.ImmutableSet;
-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 dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/**
@@ -36,34 +29,9 @@
*/
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class OriginatingElementProcessor extends BaseProcessor {
-
+public final class OriginatingElementProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public ImmutableSet<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.ORIGINATING_ELEMENT.toString());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- ProcessorErrors.checkState(
- MoreElements.isType(element) && Processors.isTopLevel(element),
- element,
- "@%s should only be used to annotate top-level types, but found: %s",
- annotation.getSimpleName(),
- element);
-
- TypeElement originatingElementValue =
- Processors.getAnnotationClassValue(
- getElementUtils(),
- Processors.getAnnotationMirror(element, ClassNames.ORIGINATING_ELEMENT),
- "topLevelClass");
-
- // TODO(bcorso): ProcessorErrors should allow us to point to the annotation too.
- ProcessorErrors.checkState(
- Processors.isTopLevel(originatingElementValue),
- element,
- "@%s.topLevelClass value should be a top-level class, but found: %s",
- annotation.getSimpleName(),
- originatingElementValue);
+ public OriginatingElementProcessingStep processingStep() {
+ return new OriginatingElementProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java b/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java
index 1abe44b..e4794bc 100644
--- a/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/AggregatedRootGenerator.java
@@ -16,50 +16,46 @@
package dagger.hilt.processor.internal.root;
+import androidx.room.compiler.processing.XTypeElement;
import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
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 originatingRootElement;
- private final TypeElement rootAnnotation;
- private final ProcessingEnvironment processingEnv;
+ private final XTypeElement rootElement;
+ private final XTypeElement originatingRootElement;
+ private final XTypeElement rootAnnotation;
AggregatedRootGenerator(
- TypeElement rootElement,
- TypeElement originatingRootElement,
- TypeElement rootAnnotation,
- ProcessingEnvironment processingEnv) {
+ XTypeElement rootElement, XTypeElement originatingRootElement, XTypeElement rootAnnotation) {
this.rootElement = rootElement;
this.originatingRootElement = originatingRootElement;
this.rootAnnotation = rootAnnotation;
- this.processingEnv = processingEnv;
}
- void generate() throws IOException {
- AnnotationSpec.Builder aggregatedRootAnnotation = AnnotationSpec.builder(
- ClassNames.AGGREGATED_ROOT)
+ void generate() {
+ AnnotationSpec.Builder aggregatedRootAnnotation =
+ AnnotationSpec.builder(ClassNames.AGGREGATED_ROOT)
.addMember("root", "$S", rootElement.getQualifiedName())
- .addMember("rootPackage", "$S", ClassName.get(rootElement).packageName())
+ .addMember("rootPackage", "$S", rootElement.getClassName().packageName())
.addMember("originatingRoot", "$S", originatingRootElement.getQualifiedName())
- .addMember("originatingRootPackage", "$S",
- ClassName.get(originatingRootElement).packageName())
- .addMember("rootAnnotation", "$T.class", rootAnnotation);
- ClassName.get(rootElement).simpleNames().forEach(
- name -> aggregatedRootAnnotation.addMember("rootSimpleNames", "$S", name));
- ClassName.get(originatingRootElement).simpleNames().forEach(
- name -> aggregatedRootAnnotation.addMember("originatingRootSimpleNames", "$S", name));
+ .addMember(
+ "originatingRootPackage", "$S", originatingRootElement.getClassName().packageName())
+ .addMember("rootAnnotation", "$T.class", rootAnnotation.getClassName());
+ rootElement
+ .getClassName()
+ .simpleNames()
+ .forEach(name -> aggregatedRootAnnotation.addMember("rootSimpleNames", "$S", name));
+ originatingRootElement
+ .getClassName()
+ .simpleNames()
+ .forEach(
+ name -> aggregatedRootAnnotation.addMember("originatingRootSimpleNames", "$S", name));
Processors.generateAggregatingClass(
ClassNames.AGGREGATED_ROOT_PACKAGE,
aggregatedRootAnnotation.build(),
rootElement,
- getClass(),
- processingEnv);
+ getClass());
}
}
diff --git a/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java b/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java
index 70ee63f..7788c81 100644
--- a/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/AggregatedRootMetadata.java
@@ -18,20 +18,15 @@
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
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 dagger.hilt.processor.internal.root.ir.AggregatedRootIr;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
/**
* Represents the values stored in an {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot}.
@@ -40,19 +35,19 @@
abstract class AggregatedRootMetadata {
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
/** Returns the element that was annotated with the root annotation. */
- abstract TypeElement rootElement();
+ abstract XTypeElement rootElement();
/**
- * Returns the originating root element. In most cases this will be the same as
- * {@link #rootElement()}.
+ * Returns the originating root element. In most cases this will be the same as {@link
+ * #rootElement()}.
*/
- abstract TypeElement originatingRootElement();
+ abstract XTypeElement originatingRootElement();
/** Returns the root annotation as an element. */
- abstract TypeElement rootAnnotation();
+ abstract XTypeElement rootAnnotation();
/** Returns whether this root can use a shared component. */
abstract boolean allowsSharingComponent();
@@ -62,16 +57,16 @@
return RootType.of(rootElement());
}
- static ImmutableSet<AggregatedRootMetadata> from(ProcessingEnvironment env) {
+ static ImmutableSet<AggregatedRootMetadata> from(XProcessingEnv env) {
return from(
AggregatedElements.from(
- ClassNames.AGGREGATED_ROOT_PACKAGE, ClassNames.AGGREGATED_ROOT, env.getElementUtils()),
+ ClassNames.AGGREGATED_ROOT_PACKAGE, ClassNames.AGGREGATED_ROOT, env),
env);
}
/** Returns metadata for each aggregated element. */
public static ImmutableSet<AggregatedRootMetadata> from(
- ImmutableSet<TypeElement> aggregatedElements, ProcessingEnvironment env) {
+ ImmutableSet<XTypeElement> aggregatedElements, XProcessingEnv env) {
return aggregatedElements.stream()
.map(aggregatedElement -> create(aggregatedElement, env))
.collect(toImmutableSet());
@@ -79,29 +74,23 @@
public static AggregatedRootIr toIr(AggregatedRootMetadata metadata) {
return new AggregatedRootIr(
- ClassName.get(metadata.aggregatingElement()),
- ClassName.get(metadata.rootElement()),
- ClassName.get(metadata.originatingRootElement()),
- ClassName.get(metadata.rootAnnotation()),
+ metadata.aggregatingElement().getClassName(),
+ metadata.rootElement().getClassName(),
+ metadata.originatingRootElement().getClassName(),
+ metadata.rootAnnotation().getClassName(),
metadata.allowsSharingComponent());
}
- private static AggregatedRootMetadata create(TypeElement element, ProcessingEnvironment env) {
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_ROOT);
+ private static AggregatedRootMetadata create(XTypeElement element, XProcessingEnv env) {
+ XAnnotation annotation = element.getAnnotation(ClassNames.AGGREGATED_ROOT);
- ImmutableMap<String, AnnotationValue> values =
- Processors.getAnnotationValues(env.getElementUtils(), annotationMirror);
-
- TypeElement rootElement =
- env.getElementUtils().getTypeElement(AnnotationValues.getString(values.get("root")));
+ XTypeElement rootElement = env.requireTypeElement(annotation.getAsString("root"));
boolean allowSharingComponent = true;
return new AutoValue_AggregatedRootMetadata(
element,
rootElement,
- env.getElementUtils()
- .getTypeElement(AnnotationValues.getString(values.get("originatingRoot"))),
- AnnotationValues.getTypeElement(values.get("rootAnnotation")),
+ env.requireTypeElement(annotation.getAsString("originatingRoot")),
+ annotation.getAsType("rootAnnotation").getTypeElement(),
allowSharingComponent);
}
}
diff --git a/java/dagger/hilt/processor/internal/root/BUILD b/java/dagger/hilt/processor/internal/root/BUILD
index 0402d91..a132b1c 100644
--- a/java/dagger/hilt/processor/internal/root/BUILD
+++ b/java/dagger/hilt/processor/internal/root/BUILD
@@ -30,8 +30,10 @@
name = "component_tree_deps_processor_lib",
srcs = [
"ComponentGenerator.java",
+ "ComponentTreeDepsProcessingStep.java",
"ComponentTreeDepsProcessor.java",
"EarlySingletonComponentCreatorGenerator.java",
+ "KspComponentTreeDepsProcessor.java",
"RootFileFormatter.java",
"RootGenerator.java",
"TestComponentDataGenerator.java",
@@ -53,13 +55,15 @@
"//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",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
+ "//third_party/java/error_prone:annotations",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/guava/graph",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -77,7 +81,9 @@
srcs = [
"AggregatedRootGenerator.java",
"ComponentTreeDepsGenerator.java",
+ "KspRootProcessor.java",
"ProcessedRootSentinelGenerator.java",
+ "RootProcessingStep.java",
"RootProcessor.java",
"TestInjectorGenerator.java",
],
@@ -100,12 +106,13 @@
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/hilt/processor/internal/uninstallmodules:aggregated_uninstall_modules_metadata",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -132,6 +139,7 @@
"//java/dagger/hilt/processor/internal/kotlin",
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:common",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
@@ -147,6 +155,7 @@
deps = [
"//java/dagger/hilt/processor/internal:classnames",
"//java/dagger/hilt/processor/internal:processors",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/javapoet",
],
)
diff --git a/java/dagger/hilt/processor/internal/root/ComponentGenerator.java b/java/dagger/hilt/processor/internal/root/ComponentGenerator.java
index 0e8d0ad..500b93b 100644
--- a/java/dagger/hilt/processor/internal/root/ComponentGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/ComponentGenerator.java
@@ -19,6 +19,8 @@
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static java.util.Comparator.comparing;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
import com.google.common.base.Joiner;
import com.google.common.base.Utf8;
import com.google.common.collect.ImmutableCollection;
@@ -36,7 +38,6 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
/** Generates a Dagger component or subcomponent interface. */
@@ -47,7 +48,7 @@
.thenComparing(ClassName::compareTo);
private static final Comparator<TypeName> TYPE_NAME_SORTER = comparing(TypeName::toString);
- private final ProcessingEnvironment processingEnv;
+ private final XProcessingEnv processingEnv;
private final ClassName name;
private final Optional<ClassName> superclass;
private final ImmutableList<ClassName> modules;
@@ -58,7 +59,7 @@
private final Optional<TypeSpec> componentBuilder;
public ComponentGenerator(
- ProcessingEnvironment processingEnv,
+ XProcessingEnv processingEnv,
ClassName name,
Optional<ClassName> superclass,
Set<? extends ClassName> modules,
@@ -161,7 +162,9 @@
Processors.addGeneratedAnnotation(builder, processingEnv, ClassNames.ROOT_PROCESSOR.toString());
- JavaFile.builder(name.packageName(), builder.build()).build().writeTo(processingEnv.getFiler());
+ processingEnv
+ .getFiler()
+ .write(JavaFile.builder(name.packageName(), builder.build()).build(), Mode.Isolating);
return partitionName;
}
}
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java
index 34c586a..bddc41d 100644
--- a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsGenerator.java
@@ -18,6 +18,9 @@
import static javax.lang.model.element.Modifier.PUBLIC;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
@@ -30,18 +33,18 @@
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
/** Generates an {@link dagger.hilt.internal.componenttreedeps.ComponentTreeDeps}. */
final class ComponentTreeDepsGenerator {
// Keeps track of already generated proxies. For correctness, this same instance of
// ComponentTreeDepsGenerator must be used for a given round.
private final Set<ClassName> generatedProxies = new HashSet<>();
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
+ private final Mode mode;
- ComponentTreeDepsGenerator(ProcessingEnvironment env) {
+ ComponentTreeDepsGenerator(XProcessingEnv env, Mode mode) {
this.env = env;
+ this.mode = mode;
}
void generate(ComponentTreeDepsMetadata metadata) throws IOException {
@@ -53,7 +56,7 @@
Processors.addGeneratedAnnotation(builder, env, ClassNames.ROOT_PROCESSOR.toString());
- JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler());
+ env.getFiler().write(JavaFile.builder(name.packageName(), builder.build()).build(), mode);
}
AnnotationSpec componentTreeDepsAnnotation(ComponentTreeDepsMetadata metadata)
@@ -68,9 +71,9 @@
return builder.build();
}
- private void addDeps(AnnotationSpec.Builder builder, ImmutableSet<TypeElement> deps, String name)
+ private void addDeps(AnnotationSpec.Builder builder, ImmutableSet<XTypeElement> deps, String name)
throws IOException {
- for (TypeElement dep : deps) {
+ for (XTypeElement dep : deps) {
builder.addMember(name, "$T.class", maybeWrapInPublicProxy(dep));
}
}
@@ -85,33 +88,32 @@
* <p>Note: The public proxy is needed because Hilt versions < 2.35 generated package-private
* aggregating elements, which can't be referenced directly in the {@code @ComponentTreeDeps}.
*/
- private ClassName maybeWrapInPublicProxy(TypeElement dep) throws IOException {
+ private ClassName maybeWrapInPublicProxy(XTypeElement dep) {
Optional<ClassName> proxyName = AggregatedElements.aggregatedElementProxyName(dep);
if (proxyName.isPresent()) {
// Check the set of already generated proxies to ensure we don't regenerate the proxy in
// this round. Also check that the element doesn't already exist to ensure we don't regenerate
// a proxy generated in a previous round.
if (generatedProxies.add(proxyName.get())
- && env.getElementUtils().getTypeElement(proxyName.get().canonicalName()) == null) {
+ && env.findTypeElement(proxyName.get().canonicalName()) == null) {
generateProxy(dep, proxyName.get());
}
return proxyName.get();
}
- return ClassName.get(dep);
+ return dep.getClassName();
}
- private void generateProxy(TypeElement dep, ClassName proxyName) throws IOException {
+ private void generateProxy(XTypeElement dep, ClassName proxyName) {
TypeSpec.Builder builder =
TypeSpec.classBuilder(proxyName)
.addModifiers(PUBLIC)
// No originating element since this is generated by the aggregating processor.
.addAnnotation(
AnnotationSpec.builder(ClassNames.AGGREGATED_ELEMENT_PROXY)
- .addMember("value", "$T.class", dep)
+ .addMember("value", "$T.class", dep.getClassName())
.build());
Processors.addGeneratedAnnotation(builder, env, ClassNames.ROOT_PROCESSOR.toString());
-
- JavaFile.builder(proxyName.packageName(), builder.build()).build().writeTo(env.getFiler());
+ env.getFiler().write(JavaFile.builder(proxyName.packageName(), builder.build()).build(), mode);
}
}
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java
index bcd56c4..a84d7da 100644
--- a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsMetadata.java
@@ -18,21 +18,18 @@
import static com.google.common.base.Preconditions.checkArgument;
import static dagger.hilt.processor.internal.AggregatedElements.unwrapProxies;
-import static dagger.hilt.processor.internal.AnnotationValues.getTypeElements;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
+import dagger.internal.codegen.xprocessing.XAnnotations;
/**
* Represents the values stored in an {@link
@@ -50,75 +47,71 @@
abstract ClassName name();
/** Returns the {@link dagger.hilt.internal.aggregatedroot.AggregatedRoot} deps. */
- abstract ImmutableSet<TypeElement> aggregatedRootDeps();
+ abstract ImmutableSet<XTypeElement> aggregatedRootDeps();
/** Returns the {@link dagger.hilt.internal.definecomponent.DefineComponentClasses} deps. */
- abstract ImmutableSet<TypeElement> defineComponentDeps();
+ abstract ImmutableSet<XTypeElement> defineComponentDeps();
/** Returns the {@link dagger.hilt.internal.aliasof.AliasOfPropagatedData} deps. */
- abstract ImmutableSet<TypeElement> aliasOfDeps();
+ abstract ImmutableSet<XTypeElement> aliasOfDeps();
/** Returns the {@link dagger.hilt.internal.aggregateddeps.AggregatedDeps} deps. */
- abstract ImmutableSet<TypeElement> aggregatedDeps();
+ abstract ImmutableSet<XTypeElement> aggregatedDeps();
/** Returns the {@link dagger.hilt.android.uninstallmodules.AggregatedUninstallModules} deps. */
- abstract ImmutableSet<TypeElement> aggregatedUninstallModulesDeps();
+ abstract ImmutableSet<XTypeElement> aggregatedUninstallModulesDeps();
/** Returns the {@link dagger.hilt.android.earlyentrypoint.AggregatedEarlyEntryPoint} deps. */
- abstract ImmutableSet<TypeElement> aggregatedEarlyEntryPointDeps();
+ abstract ImmutableSet<XTypeElement> aggregatedEarlyEntryPointDeps();
- static ComponentTreeDepsMetadata from(TypeElement element, Elements elements) {
- checkArgument(Processors.hasAnnotation(element, ClassNames.COMPONENT_TREE_DEPS));
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.COMPONENT_TREE_DEPS);
-
- ImmutableMap<String, AnnotationValue> values =
- Processors.getAnnotationValues(elements, annotationMirror);
+ static ComponentTreeDepsMetadata from(XTypeElement element, XProcessingEnv env) {
+ checkArgument(element.hasAnnotation(ClassNames.COMPONENT_TREE_DEPS));
+ XAnnotation annotation = element.getAnnotation(ClassNames.COMPONENT_TREE_DEPS);
return create(
- ClassName.get(element),
- unwrapProxies(getTypeElements(values.get("rootDeps")), elements),
- unwrapProxies(getTypeElements(values.get("defineComponentDeps")), elements),
- unwrapProxies(getTypeElements(values.get("aliasOfDeps")), elements),
- unwrapProxies(getTypeElements(values.get("aggregatedDeps")), elements),
- unwrapProxies(getTypeElements(values.get("uninstallModulesDeps")), elements),
- unwrapProxies(getTypeElements(values.get("earlyEntryPointDeps")), elements));
+ element.getClassName(),
+ unwrapProxies(XAnnotations.getAsTypeElementList(annotation, "rootDeps")),
+ unwrapProxies(XAnnotations.getAsTypeElementList(annotation, "defineComponentDeps")),
+ unwrapProxies(XAnnotations.getAsTypeElementList(annotation, "aliasOfDeps")),
+ unwrapProxies(XAnnotations.getAsTypeElementList(annotation, "aggregatedDeps")),
+ unwrapProxies(XAnnotations.getAsTypeElementList(annotation, "uninstallModulesDeps")),
+ unwrapProxies(XAnnotations.getAsTypeElementList(annotation, "earlyEntryPointDeps")));
}
- static ComponentTreeDepsMetadata from(ComponentTreeDepsIr ir, Elements elements) {
+ static ComponentTreeDepsMetadata from(ComponentTreeDepsIr ir, XProcessingEnv env) {
return create(
ir.getName(),
ir.getRootDeps().stream()
- .map(it -> elements.getTypeElement(it.canonicalName()))
+ .map(it -> env.requireTypeElement(it.canonicalName()))
.collect(toImmutableSet()),
ir.getDefineComponentDeps().stream()
- .map(it -> elements.getTypeElement(it.canonicalName()))
+ .map(it -> env.requireTypeElement(it.canonicalName()))
.collect(toImmutableSet()),
ir.getAliasOfDeps().stream()
- .map(it -> elements.getTypeElement(it.canonicalName()))
+ .map(it -> env.requireTypeElement(it.canonicalName()))
.collect(toImmutableSet()),
ir.getAggregatedDeps().stream()
- .map(it -> elements.getTypeElement(it.canonicalName()))
+ .map(it -> env.requireTypeElement(it.canonicalName()))
.collect(toImmutableSet()),
ir.getUninstallModulesDeps().stream()
- .map(it -> elements.getTypeElement(it.canonicalName()))
+ .map(it -> env.requireTypeElement(it.canonicalName()))
.collect(toImmutableSet()),
ir.getEarlyEntryPointDeps().stream()
- .map(it -> elements.getTypeElement(it.canonicalName()))
+ .map(it -> env.requireTypeElement(it.canonicalName()))
.collect(toImmutableSet()));
}
/** Returns all modules included in a component tree deps. */
- public ImmutableSet<TypeElement> modules(Elements elements) {
- return AggregatedDepsMetadata.from(aggregatedDeps(), elements).stream()
+ public ImmutableSet<XTypeElement> modules() {
+ return AggregatedDepsMetadata.from(aggregatedDeps()).stream()
.filter(AggregatedDepsMetadata::isModule)
.map(AggregatedDepsMetadata::dependency)
.collect(toImmutableSet());
}
/** Returns all entry points included in a component tree deps. */
- public ImmutableSet<TypeElement> entrypoints(Elements elements) {
- return AggregatedDepsMetadata.from(aggregatedDeps(), elements).stream()
+ public ImmutableSet<XTypeElement> entrypoints() {
+ return AggregatedDepsMetadata.from(aggregatedDeps()).stream()
.filter(dependency -> !dependency.isModule())
.map(AggregatedDepsMetadata::dependency)
.collect(toImmutableSet());
@@ -126,12 +119,12 @@
static ComponentTreeDepsMetadata create(
ClassName name,
- ImmutableSet<TypeElement> aggregatedRootDeps,
- ImmutableSet<TypeElement> defineComponentDeps,
- ImmutableSet<TypeElement> aliasOfDeps,
- ImmutableSet<TypeElement> aggregatedDeps,
- ImmutableSet<TypeElement> aggregatedUninstallModulesDeps,
- ImmutableSet<TypeElement> aggregatedEarlyEntryPointDeps) {
+ ImmutableSet<XTypeElement> aggregatedRootDeps,
+ ImmutableSet<XTypeElement> defineComponentDeps,
+ ImmutableSet<XTypeElement> aliasOfDeps,
+ ImmutableSet<XTypeElement> aggregatedDeps,
+ ImmutableSet<XTypeElement> aggregatedUninstallModulesDeps,
+ ImmutableSet<XTypeElement> aggregatedEarlyEntryPointDeps) {
return new AutoValue_ComponentTreeDepsMetadata(
name,
aggregatedRootDeps,
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessingStep.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessingStep.java
new file mode 100644
index 0000000..295a779
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessingStep.java
@@ -0,0 +1,193 @@
+/*
+ * 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 com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointMetadata;
+import dagger.hilt.android.processor.internal.androidentrypoint.ApplicationGenerator;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ComponentDescriptor;
+import dagger.hilt.processor.internal.ComponentNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.hilt.processor.internal.Processors;
+import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
+import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
+import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
+import dagger.hilt.processor.internal.aliasof.AliasOfs;
+import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
+import dagger.hilt.processor.internal.definecomponent.DefineComponents;
+import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
+import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Processor that outputs dagger components based on transitive build deps. */
+public final class ComponentTreeDepsProcessingStep extends BaseProcessingStep {
+ private final Set<ClassName> componentTreeDepNames = new HashSet<>();
+ private final Set<ClassName> processed = new HashSet<>();
+
+ public ComponentTreeDepsProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.COMPONENT_TREE_DEPS);
+ }
+
+ @Override
+ protected void processEach(ClassName annotation, XElement element) {
+ componentTreeDepNames.add(XElements.asTypeElement(element).getClassName());
+ }
+
+ @Override
+ public void postProcess(XProcessingEnv env, XRoundEnv roundEnv) throws Exception {
+ ImmutableSet<ComponentTreeDepsMetadata> componentTreeDepsToProcess =
+ componentTreeDepNames.stream()
+ .filter(className -> !processed.contains(className))
+ .map(className -> processingEnv().requireTypeElement(className))
+ .map(element -> ComponentTreeDepsMetadata.from(element, processingEnv()))
+ .collect(toImmutableSet());
+
+ DefineComponents defineComponents = DefineComponents.create();
+ for (ComponentTreeDepsMetadata metadata : componentTreeDepsToProcess) {
+ processComponentTreeDeps(metadata, defineComponents);
+ }
+ }
+
+ private void processComponentTreeDeps(
+ ComponentTreeDepsMetadata metadata, DefineComponents defineComponents) throws IOException {
+ XTypeElement metadataElement = processingEnv().requireTypeElement(metadata.name());
+ try {
+ // We choose a name for the generated components/wrapper based off of the originating element
+ // annotated with @ComponentTreeDeps. This is close to but isn't necessarily a "real" name of
+ // a root, since with shared test components, even for single roots, the component tree deps
+ // will be moved to a shared package with a deduped name.
+ ClassName renamedRoot = Processors.removeNameSuffix(metadataElement, "_ComponentTreeDeps");
+ ComponentNames componentNames = ComponentNames.withRenaming(rootName -> renamedRoot);
+
+ boolean isDefaultRoot = ClassNames.DEFAULT_ROOT.equals(renamedRoot);
+ ImmutableSet<Root> roots =
+ AggregatedRootMetadata.from(metadata.aggregatedRootDeps(), processingEnv()).stream()
+ .map(AggregatedRootMetadata::rootElement)
+ .map(rootElement -> Root.create(rootElement, processingEnv()))
+ .collect(toImmutableSet());
+
+ // TODO(bcorso): For legacy reasons, a lot of the generating code requires a "root" as input
+ // since we used to assume 1 root per component tree. Now that each ComponentTreeDeps may
+ // represent multiple roots, we should refactor this logic.
+ Root root =
+ isDefaultRoot
+ ? Root.createDefaultRoot(processingEnv())
+ // Non-default roots should only ever be associated with one root element
+ : getOnlyElement(roots);
+
+ ImmutableSet<ComponentDescriptor> componentDescriptors =
+ defineComponents.getComponentDescriptors(
+ DefineComponentClassesMetadata.from(metadata.defineComponentDeps()));
+ ComponentTree tree = ComponentTree.from(componentDescriptors);
+ ComponentDependencies deps =
+ ComponentDependencies.from(
+ componentDescriptors,
+ AggregatedDepsMetadata.from(metadata.aggregatedDeps()),
+ AggregatedUninstallModulesMetadata.from(metadata.aggregatedUninstallModulesDeps()),
+ AggregatedEarlyEntryPointMetadata.from(metadata.aggregatedEarlyEntryPointDeps()),
+ processingEnv());
+ AliasOfs aliasOfs =
+ AliasOfs.create(
+ AliasOfPropagatedDataMetadata.from(metadata.aliasOfDeps()), componentDescriptors);
+ RootMetadata rootMetadata = RootMetadata.create(root, tree, deps, aliasOfs, processingEnv());
+
+ generateComponents(metadata, rootMetadata, componentNames);
+
+ // Generate a creator for the early entry point if there is a default component available
+ // and there are early entry points.
+ if (isDefaultRoot && !metadata.aggregatedEarlyEntryPointDeps().isEmpty()) {
+ EarlySingletonComponentCreatorGenerator.generate(processingEnv());
+ }
+
+ if (root.isTestRoot()) {
+ // Generate test related classes for each test root that uses this component.
+ ImmutableList<RootMetadata> rootMetadatas =
+ roots.stream()
+ .map(test -> RootMetadata.create(test, tree, deps, aliasOfs, processingEnv()))
+ .collect(toImmutableList());
+ generateTestComponentData(metadataElement, rootMetadatas, componentNames);
+ } else {
+ generateApplication(root.element());
+ }
+
+ setProcessingState(metadata, root);
+ } catch (Exception e) {
+ processed.add(metadata.name());
+ throw e;
+ }
+ }
+
+ private void setProcessingState(ComponentTreeDepsMetadata metadata, Root root) {
+ processed.add(metadata.name());
+ }
+
+ private void generateComponents(
+ ComponentTreeDepsMetadata metadata, RootMetadata rootMetadata, ComponentNames componentNames)
+ throws IOException {
+ RootGenerator.generate(metadata, rootMetadata, componentNames, processingEnv());
+ }
+
+ private void generateTestComponentData(
+ XTypeElement metadataElement,
+ ImmutableList<RootMetadata> rootMetadatas,
+ ComponentNames componentNames)
+ throws IOException {
+ for (RootMetadata rootMetadata : rootMetadatas) {
+ // TODO(bcorso): Consider moving this check earlier into processEach.
+ XTypeElement testElement = rootMetadata.testRootMetadata().testElement();
+ ProcessorErrors.checkState(
+ testElement.isPublic(),
+ testElement,
+ "Hilt tests must be public, but found: %s",
+ XElements.toStableString(testElement));
+ new TestComponentDataGenerator(processingEnv(), metadataElement, rootMetadata, componentNames)
+ .generate();
+ }
+ }
+
+ private void generateApplication(XTypeElement rootElement) throws IOException {
+ // The generated application references the generated component so they must be generated
+ // in the same build unit. Thus, we only generate the application here if we're using the
+ // Hilt Gradle plugin's aggregating task. If we're using the aggregating processor, we need
+ // to generate the application within AndroidEntryPointProcessor instead.
+ if (!useAggregatingRootProcessor(processingEnv())) {
+ AndroidEntryPointMetadata metadata = AndroidEntryPointMetadata.of(rootElement);
+ new ApplicationGenerator(processingEnv(), metadata).generate();
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java
index 85eb59a..08c0e8b 100644
--- a/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java
+++ b/java/dagger/hilt/processor/internal/root/ComponentTreeDepsProcessor.java
@@ -16,189 +16,20 @@
package dagger.hilt.processor.internal.root;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.lang.model.element.Modifier.PUBLIC;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
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.android.processor.internal.androidentrypoint.AndroidEntryPointMetadata;
-import dagger.hilt.android.processor.internal.androidentrypoint.ApplicationGenerator;
-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.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
-import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
-import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
-import dagger.hilt.processor.internal.aliasof.AliasOfs;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
-import dagger.hilt.processor.internal.definecomponent.DefineComponents;
-import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
-import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processor that outputs dagger components based on transitive build deps. */
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
-public final class ComponentTreeDepsProcessor extends BaseProcessor {
- private final Set<ClassName> componentTreeDepNames = new HashSet<>();
- private final Set<ClassName> processed = new HashSet<>();
- private final DefineComponents defineComponents = DefineComponents.create();
-
+public final class ComponentTreeDepsProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public ImmutableSet<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.COMPONENT_TREE_DEPS.toString());
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) {
- componentTreeDepNames.add(ClassName.get(asType(element)));
- }
-
- @Override
- public void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
- ImmutableSet<ComponentTreeDepsMetadata> componentTreeDepsToProcess =
- componentTreeDepNames.stream()
- .filter(className -> !processed.contains(className))
- .map(className -> getElementUtils().getTypeElement(className.canonicalName()))
- .map(element -> ComponentTreeDepsMetadata.from(element, getElementUtils()))
- .collect(toImmutableSet());
-
- for (ComponentTreeDepsMetadata metadata : componentTreeDepsToProcess) {
- processComponentTreeDeps(metadata);
- }
- }
-
- private void processComponentTreeDeps(ComponentTreeDepsMetadata metadata) throws IOException {
- TypeElement metadataElement = getElementUtils().getTypeElement(metadata.name().canonicalName());
- try {
- // We choose a name for the generated components/wrapper based off of the originating element
- // annotated with @ComponentTreeDeps. This is close to but isn't necessarily a "real" name of
- // a root, since with shared test components, even for single roots, the component tree deps
- // will be moved to a shared package with a deduped name.
- ClassName renamedRoot = Processors.removeNameSuffix(metadataElement, "_ComponentTreeDeps");
- ComponentNames componentNames = ComponentNames.withRenaming(rootName -> renamedRoot);
-
- boolean isDefaultRoot = ClassNames.DEFAULT_ROOT.equals(renamedRoot);
- ImmutableSet<Root> roots =
- AggregatedRootMetadata.from(metadata.aggregatedRootDeps(), processingEnv).stream()
- .map(AggregatedRootMetadata::rootElement)
- .map(rootElement -> Root.create(rootElement, getProcessingEnv()))
- .collect(toImmutableSet());
-
- // TODO(bcorso): For legacy reasons, a lot of the generating code requires a "root" as input
- // since we used to assume 1 root per component tree. Now that each ComponentTreeDeps may
- // represent multiple roots, we should refactor this logic.
- Root root =
- isDefaultRoot
- ? Root.createDefaultRoot(getProcessingEnv())
- // Non-default roots should only ever be associated with one root element
- : getOnlyElement(roots);
-
- ImmutableSet<ComponentDescriptor> componentDescriptors =
- defineComponents.getComponentDescriptors(
- DefineComponentClassesMetadata.from(
- metadata.defineComponentDeps(), getElementUtils()));
- ComponentTree tree = ComponentTree.from(componentDescriptors);
- ComponentDependencies deps =
- ComponentDependencies.from(
- componentDescriptors,
- AggregatedDepsMetadata.from(metadata.aggregatedDeps(), getElementUtils()),
- AggregatedUninstallModulesMetadata.from(
- metadata.aggregatedUninstallModulesDeps(), getElementUtils()),
- AggregatedEarlyEntryPointMetadata.from(
- metadata.aggregatedEarlyEntryPointDeps(), getElementUtils()),
- getElementUtils());
- AliasOfs aliasOfs =
- AliasOfs.create(
- AliasOfPropagatedDataMetadata.from(metadata.aliasOfDeps(), getElementUtils()),
- componentDescriptors);
- RootMetadata rootMetadata =
- RootMetadata.create(root, tree, deps, aliasOfs, getProcessingEnv());
-
- generateComponents(metadata, rootMetadata, componentNames);
-
- // Generate a creator for the early entry point if there is a default component available
- // and there are early entry points.
- if (isDefaultRoot && !metadata.aggregatedEarlyEntryPointDeps().isEmpty()) {
- EarlySingletonComponentCreatorGenerator.generate(getProcessingEnv());
- }
-
- if (root.isTestRoot()) {
- // Generate test related classes for each test root that uses this component.
- ImmutableList<RootMetadata> rootMetadatas =
- roots.stream()
- .map(test -> RootMetadata.create(test, tree, deps, aliasOfs, getProcessingEnv()))
- .collect(toImmutableList());
- generateTestComponentData(metadataElement, rootMetadatas, componentNames);
- } else {
- generateApplication(root.element());
- }
-
- setProcessingState(metadata, root);
- } catch (Exception e) {
- processed.add(metadata.name());
- throw e;
- }
- }
-
- private void setProcessingState(ComponentTreeDepsMetadata metadata, Root root) {
- processed.add(metadata.name());
- }
-
- private void generateComponents(
- ComponentTreeDepsMetadata metadata, RootMetadata rootMetadata, ComponentNames componentNames)
- throws IOException {
- RootGenerator.generate(metadata, rootMetadata, componentNames, getProcessingEnv());
- }
-
- private void generateTestComponentData(
- TypeElement metadataElement,
- 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();
- ProcessorErrors.checkState(
- testElement.getModifiers().contains(PUBLIC),
- testElement,
- "Hilt tests must be public, but found: %s",
- testElement);
- new TestComponentDataGenerator(
- getProcessingEnv(), metadataElement, rootMetadata, componentNames)
- .generate();
- }
- }
-
- private void generateApplication(TypeElement rootElement) throws IOException {
- // The generated application references the generated component so they must be generated
- // in the same build unit. Thus, we only generate the application here if we're using the
- // Hilt Gradle plugin's aggregating task. If we're using the aggregating processor, we need
- // to generate the application within AndroidEntryPointProcessor instead.
- if (!useAggregatingRootProcessor(getProcessingEnv())) {
- AndroidEntryPointMetadata metadata =
- AndroidEntryPointMetadata.of(getProcessingEnv(), rootElement);
- new ApplicationGenerator(
- getProcessingEnv(),
- metadata)
- .generate();
- }
+ protected BaseProcessingStep processingStep() {
+ return new ComponentTreeDepsProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java b/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java
index f0066e1..a0fc70b 100644
--- a/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/EarlySingletonComponentCreatorGenerator.java
@@ -16,14 +16,14 @@
package dagger.hilt.processor.internal.root;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
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 {
@@ -36,7 +36,7 @@
ClassName.get(
"dagger.hilt.android.internal.testing.root", "DaggerDefault_HiltComponents_SingletonC");
- static void generate(ProcessingEnvironment env) throws IOException {
+ static void generate(XProcessingEnv env) {
TypeSpec.Builder builder =
TypeSpec.classBuilder(EARLY_SINGLETON_COMPONENT_CREATOR_IMPL)
.superclass(EARLY_SINGLETON_COMPONENT_CREATOR)
@@ -54,9 +54,11 @@
Processors.addGeneratedAnnotation(builder, env, ClassNames.ROOT_PROCESSOR.toString());
- JavaFile.builder(EARLY_SINGLETON_COMPONENT_CREATOR_IMPL.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(EARLY_SINGLETON_COMPONENT_CREATOR_IMPL.packageName(), builder.build())
+ .build(),
+ Mode.Isolating);
}
private EarlySingletonComponentCreatorGenerator() {}
diff --git a/java/dagger/hilt/processor/internal/root/KspComponentTreeDepsProcessor.java b/java/dagger/hilt/processor/internal/root/KspComponentTreeDepsProcessor.java
new file mode 100644
index 0000000..5b51abd
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/KspComponentTreeDepsProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Processor that outputs dagger components based on transitive build deps. */
+public final class KspComponentTreeDepsProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspComponentTreeDepsProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new ComponentTreeDepsProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspComponentTreeDepsProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspComponentTreeDepsProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/KspRootProcessor.java b/java/dagger/hilt/processor/internal/root/KspRootProcessor.java
new file mode 100644
index 0000000..ef823ce
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/KspRootProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 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.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Processor that outputs dagger components based on transitive build deps. */
+public final class KspRootProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspRootProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new RootProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspRootProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspRootProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java
index 87efa20..d2e3a93 100644
--- a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelGenerator.java
@@ -16,21 +16,21 @@
package dagger.hilt.processor.internal.root;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XTypeElement;
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;
+ private final XTypeElement processedRoot;
+ private final Mode mode;
- ProcessedRootSentinelGenerator(TypeElement processedRoot, ProcessingEnvironment processingEnv) {
+ ProcessedRootSentinelGenerator(XTypeElement processedRoot, Mode mode) {
this.processedRoot = processedRoot;
- this.processingEnv = processingEnv;
+ this.mode = mode;
}
void generate() throws IOException {
@@ -41,6 +41,6 @@
.build(),
processedRoot,
getClass(),
- processingEnv);
+ mode);
}
}
diff --git a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java
index ffc67f4..ba0be42 100644
--- a/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/ProcessedRootSentinelMetadata.java
@@ -18,20 +18,16 @@
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
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 dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr;
import java.util.stream.Collectors;
-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
@@ -41,42 +37,35 @@
abstract class ProcessedRootSentinelMetadata {
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
/** Returns the processed root elements. */
- abstract ImmutableSet<TypeElement> rootElements();
+ abstract ImmutableSet<XTypeElement> rootElements();
- static ImmutableSet<ProcessedRootSentinelMetadata> from(Elements elements) {
+ static ImmutableSet<ProcessedRootSentinelMetadata> from(XProcessingEnv env) {
return AggregatedElements.from(
- ClassNames.PROCESSED_ROOT_SENTINEL_PACKAGE,
- ClassNames.PROCESSED_ROOT_SENTINEL,
- elements)
+ ClassNames.PROCESSED_ROOT_SENTINEL_PACKAGE, ClassNames.PROCESSED_ROOT_SENTINEL, env)
.stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ .map(aggregatedElement -> create(aggregatedElement, env))
.collect(toImmutableSet());
}
static ProcessedRootSentinelIr toIr(ProcessedRootSentinelMetadata metadata) {
return new ProcessedRootSentinelIr(
- ClassName.get(metadata.aggregatingElement()),
+ metadata.aggregatingElement().getClassName(),
metadata.rootElements().stream()
- .map(ClassName::get)
+ .map(XTypeElement::getClassName)
.map(ClassName::canonicalName)
- .collect(Collectors.toList())
- );
+ .collect(Collectors.toList()));
}
- 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);
+ private static ProcessedRootSentinelMetadata create(XTypeElement element, XProcessingEnv env) {
+ XAnnotation annotationMirror = element.getAnnotation(ClassNames.PROCESSED_ROOT_SENTINEL);
return new AutoValue_ProcessedRootSentinelMetadata(
element,
- AnnotationValues.getStrings(values.get("roots")).stream()
- .map(elements::getTypeElement)
+ annotationMirror.getAsStringList("roots").stream()
+ .map(env::requireTypeElement)
.collect(toImmutableSet()));
}
}
diff --git a/java/dagger/hilt/processor/internal/root/Root.java b/java/dagger/hilt/processor/internal/root/Root.java
index 00e17ca..86b8159 100644
--- a/java/dagger/hilt/processor/internal/root/Root.java
+++ b/java/dagger/hilt/processor/internal/root/Root.java
@@ -16,13 +16,13 @@
package dagger.hilt.processor.internal.root;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
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;
+import dagger.internal.codegen.xprocessing.XElements;
/** Metadata for a root element that can trigger the {@link RootProcessor}. */
@AutoValue
@@ -40,41 +40,40 @@
* <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());
+ static Root createDefaultRoot(XProcessingEnv env) {
+ XTypeElement rootElement = env.requireTypeElement(ClassNames.DEFAULT_ROOT.canonicalName());
return new AutoValue_Root(rootElement, 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);
- if (ClassNames.DEFAULT_ROOT.equals(ClassName.get(rootElement))) {
+ static Root create(XElement element, XProcessingEnv env) {
+ XTypeElement rootElement = XElements.asTypeElement(element);
+ if (ClassNames.DEFAULT_ROOT.equals(rootElement.getClassName())) {
return createDefaultRoot(env);
}
return new AutoValue_Root(rootElement, rootElement, RootType.of(rootElement).isTestRoot());
}
/** Returns the root element that should be used with processing. */
- abstract TypeElement element();
+ abstract XTypeElement element();
/**
* Returns the originating root element. In most cases this will be the same as {@link
* #element()}.
*/
- abstract TypeElement originatingRootElement();
+ abstract XTypeElement originatingRootElement();
/** 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());
+ return element().getClassName();
}
/** Returns the class name of the originating root element. */
ClassName originatingRootClassname() {
- return ClassName.get(originatingRootElement());
+ return originatingRootElement().getClassName();
}
@Override
diff --git a/java/dagger/hilt/processor/internal/root/RootFileFormatter.java b/java/dagger/hilt/processor/internal/root/RootFileFormatter.java
index 45cdd22..0f22604 100644
--- a/java/dagger/hilt/processor/internal/root/RootFileFormatter.java
+++ b/java/dagger/hilt/processor/internal/root/RootFileFormatter.java
@@ -16,15 +16,23 @@
package dagger.hilt.processor.internal.root;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.compat.XConverters;
+import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.JavaFile;
+import java.io.BufferedWriter;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.annotation.processing.Filer;
-import javax.lang.model.element.Element;
-import javax.tools.JavaFileObject;
/**
* Typically we would just use {@code JavaFile#writeTo()} to write files. However, this formatter
@@ -38,28 +46,25 @@
private static final Pattern CLASS_PATERN = Pattern.compile("(\\h*)(.*class.*implements)(.*\\{)");
/** Formats the {@link JavaFile} java source file. */
- static void write(JavaFile javaFile, Filer filer) throws IOException {
- String fileName =
- javaFile.packageName.isEmpty()
- ? javaFile.typeSpec.name
- : javaFile.packageName + "." + javaFile.typeSpec.name;
-
- Element[] originatingElements = javaFile.typeSpec.originatingElements.toArray(new Element[0]);
+ static void write(JavaFile javaFile, XProcessingEnv env) throws IOException {
+ ImmutableList<XElement> originatingElements =
+ javaFile.typeSpec.originatingElements.stream()
+ .map(element -> XConverters.toXProcessing(element, env))
+ .collect(toImmutableList());
StringBuilder sb = new StringBuilder("");
javaFile.writeTo(sb);
String fileContent = formatInterfaces(sb.toString(), CLASS_PATERN);
- JavaFileObject filerSourceFile = filer.createSourceFile(fileName, originatingElements);
- try (Writer writer = filerSourceFile.openWriter()) {
+ try (OutputStream outputStream = env.getFiler()
+ .writeSource(
+ javaFile.packageName,
+ javaFile.typeSpec.name,
+ "java",
+ originatingElements,
+ Mode.Isolating);
+ Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, UTF_8))) {
writer.write(fileContent);
- } catch (Exception e) {
- try {
- filerSourceFile.delete();
- } catch (Exception ignored) {
- // Nothing to do.
- }
- throw e;
}
}
diff --git a/java/dagger/hilt/processor/internal/root/RootGenerator.java b/java/dagger/hilt/processor/internal/root/RootGenerator.java
index 732c6ea..2868f7c 100644
--- a/java/dagger/hilt/processor/internal/root/RootGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/RootGenerator.java
@@ -16,14 +16,17 @@
package dagger.hilt.processor.internal.root;
-import static com.google.common.base.Preconditions.checkNotNull;
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;
import static javax.lang.model.element.Modifier.PUBLIC;
import static javax.lang.model.element.Modifier.STATIC;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XProcessingEnv.Backend;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -43,9 +46,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
/** Generates components and any other classes needed for a root. */
final class RootGenerator {
@@ -54,7 +55,7 @@
ComponentTreeDepsMetadata componentTreeDepsMetadata,
RootMetadata metadata,
ComponentNames componentNames,
- ProcessingEnvironment env)
+ XProcessingEnv env)
throws IOException {
new RootGenerator(
componentTreeDepsMetadata,
@@ -64,9 +65,9 @@
.generateComponents();
}
- private final TypeElement originatingElement;
+ private final XTypeElement originatingElement;
private final RootMetadata metadata;
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final Root root;
private final Map<String, Integer> simpleComponentNamesToDedupeSuffix = new HashMap<>();
private final Map<ComponentDescriptor, ClassName> componentNameMap = new HashMap<>();
@@ -76,10 +77,8 @@
ComponentTreeDepsMetadata componentTreeDepsMetadata,
RootMetadata metadata,
ComponentNames componentNames,
- ProcessingEnvironment env) {
- this.originatingElement =
- checkNotNull(
- env.getElementUtils().getTypeElement(componentTreeDepsMetadata.name().toString()));
+ XProcessingEnv env) {
+ this.originatingElement = env.requireTypeElement(componentTreeDepsMetadata.name().toString());
this.metadata = metadata;
this.componentNames = componentNames;
this.env = env;
@@ -104,7 +103,10 @@
for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) {
ImmutableSet<ClassName> modules =
ImmutableSet.<ClassName>builder()
- .addAll(toClassNames(metadata.modules(componentDescriptor.component())))
+ .addAll(
+ metadata.modules(componentDescriptor.component()).stream()
+ .map(XTypeElement::getClassName)
+ .collect(toImmutableSet()))
.addAll(
componentTree.childrenOf(componentDescriptor).stream()
.map(subcomponentBuilderModules::get)
@@ -127,10 +129,15 @@
.build());
}
- RootFileFormatter.write(
+ JavaFile componentsWrapperJavaFile =
JavaFile.builder(componentsWrapperClassName.packageName(), componentsWrapper.build())
- .build(),
- env.getFiler());
+ .build();
+ // TODO(danysantiago): Support formatting in KSP: b/288572563
+ if (env.getBackend() == Backend.KSP) {
+ env.getFiler().write(componentsWrapperJavaFile, Mode.Isolating);
+ } else {
+ RootFileFormatter.write(componentsWrapperJavaFile, env);
+ }
}
private static ComponentTree filterDescriptors(ComponentTree componentTree) {
@@ -178,7 +185,6 @@
ClassName componentName, ClassName builderName, ClassName moduleName) {
TypeSpec.Builder subcomponentBuilderModule =
TypeSpec.interfaceBuilder(moduleName)
- .addOriginatingElement(originatingElement)
.addModifiers(ABSTRACT)
.addAnnotation(
AnnotationSpec.builder(ClassNames.MODULE)
@@ -192,7 +198,7 @@
.returns(builderName)
.addParameter(componentName.nestedClass("Builder"), "builder")
.build());
-
+ JavaPoetExtKt.addOriginatingElement(subcomponentBuilderModule, originatingElement);
Processors.addGeneratedAnnotation(
subcomponentBuilderModule, env, ClassNames.ROOT_PROCESSOR.toString());
@@ -203,13 +209,15 @@
return descriptor
.creator()
.map(
- creator ->
- TypeSpec.interfaceBuilder("Builder")
- .addOriginatingElement(originatingElement)
- .addModifiers(STATIC, ABSTRACT)
- .addSuperinterface(creator)
- .addAnnotation(componentBuilderAnnotation(descriptor))
- .build());
+ creator -> {
+ TypeSpec.Builder builder =
+ TypeSpec.interfaceBuilder("Builder")
+ .addModifiers(STATIC, ABSTRACT)
+ .addSuperinterface(creator)
+ .addAnnotation(componentBuilderAnnotation(descriptor));
+ JavaPoetExtKt.addOriginatingElement(builder, originatingElement);
+ return builder.build();
+ });
}
private ClassName componentAnnotation(ComponentDescriptor componentDescriptor) {
diff --git a/java/dagger/hilt/processor/internal/root/RootMetadata.java b/java/dagger/hilt/processor/internal/root/RootMetadata.java
index 05fd078..8166d66 100644
--- a/java/dagger/hilt/processor/internal/root/RootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/RootMetadata.java
@@ -19,10 +19,11 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Suppliers.memoize;
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 androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
@@ -33,14 +34,8 @@
import dagger.hilt.processor.internal.Processors;
import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
import dagger.hilt.processor.internal.aliasof.AliasOfs;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtil;
-import dagger.hilt.processor.internal.kotlin.KotlinMetadataUtils;
import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
/** Contains metadata about the given hilt root. */
@@ -53,7 +48,7 @@
ComponentTree componentTree,
ComponentDependencies deps,
AliasOfs aliasOfs,
- ProcessingEnvironment env) {
+ XProcessingEnv env) {
return createInternal(root, componentTree, deps, aliasOfs, env);
}
@@ -66,15 +61,14 @@
ComponentTree componentTree,
ComponentDependencies deps,
AliasOfs aliasOfs,
- ProcessingEnvironment env) {
+ XProcessingEnv env) {
RootMetadata metadata = new RootMetadata(root, componentTree, deps, aliasOfs, env);
metadata.validate();
return metadata;
}
private final Root root;
- private final ProcessingEnvironment env;
- private final Elements elements;
+ private final XProcessingEnv env;
private final ComponentTree componentTree;
private final ComponentDependencies deps;
private final AliasOfs aliasOfs;
@@ -88,10 +82,9 @@
ComponentTree componentTree,
ComponentDependencies deps,
AliasOfs aliasOfs,
- ProcessingEnvironment env) {
+ XProcessingEnv env) {
this.root = root;
this.env = env;
- this.elements = env.getElementUtils();
this.componentTree = componentTree;
this.deps = deps;
this.aliasOfs = aliasOfs;
@@ -109,15 +102,15 @@
return deps;
}
- public ImmutableSet<TypeElement> modules(ClassName componentName) {
- return deps.modules().get(componentName);
+ public ImmutableSet<XTypeElement> modules(ClassName componentName) {
+ return deps.modules().get(componentName).stream().collect(toImmutableSet());
}
public ImmutableSet<TypeName> entryPoints(ClassName componentName) {
return ImmutableSet.<TypeName>builder()
.addAll(
deps.entryPoints().get(componentName).stream()
- .map(ClassName::get)
+ .map(XTypeElement::getClassName)
.collect(toImmutableSet()))
.add(
root.isTestRoot() && componentName.equals(ClassNames.SINGLETON_COMPONENT)
@@ -138,10 +131,10 @@
* filters out framework modules directly referenced by the codegen, since those are already known
* about and are specifically handled in the codegen.
*/
- public ImmutableSet<TypeElement> modulesThatDaggerCannotConstruct(ClassName componentName) {
+ public ImmutableSet<XTypeElement> modulesThatDaggerCannotConstruct(ClassName componentName) {
return modules(componentName).stream()
.filter(module -> !daggerCanConstruct(module))
- .filter(module -> !APPLICATION_CONTEXT_MODULE.equals(ClassName.get(module)))
+ .filter(module -> !APPLICATION_CONTEXT_MODULE.equals(module.getClassName()))
.collect(toImmutableSet());
}
@@ -167,7 +160,7 @@
// Only test modules in the application component can be missing default constructor
for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) {
ClassName componentName = componentDescriptor.component();
- for (TypeElement extraModule : modulesThatDaggerCannotConstruct(componentName)) {
+ for (XTypeElement extraModule : modulesThatDaggerCannotConstruct(componentName)) {
if (root.isTestRoot() && !componentName.equals(ClassNames.SINGLETON_COMPONENT)) {
env.getMessager()
.printMessage(
@@ -201,11 +194,8 @@
return builder.build();
}
- private static boolean daggerCanConstruct(TypeElement type) {
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- boolean isKotlinObject =
- metadataUtil.isObjectClass(type) || metadataUtil.isCompanionObjectClass(type);
- if (isKotlinObject) {
+ private static boolean daggerCanConstruct(XTypeElement type) {
+ if (type.isKotlinObject()) {
// Treat Kotlin object modules as if Dagger can construct them (it technically can't, but it
// doesn't need to as it can use them since all their provision methods are static).
return true;
@@ -216,29 +206,29 @@
&& (hasOnlyStaticProvides(type) || hasVisibleEmptyConstructor(type));
}
- private static boolean isInnerClass(TypeElement type) {
- return type.getNestingKind().isNested() && !type.getModifiers().contains(STATIC);
+ private static boolean isInnerClass(XTypeElement type) {
+ return type.isNested() && !type.isStatic();
}
- private static boolean hasNonDaggerAbstractMethod(TypeElement type) {
+ private static boolean hasNonDaggerAbstractMethod(XTypeElement type) {
// TODO(erichang): Actually this isn't really supported b/28989613
- return ElementFilter.methodsIn(type.getEnclosedElements()).stream()
- .filter(method -> method.getModifiers().contains(ABSTRACT))
+ return type.getDeclaredMethods().stream()
+ .filter(XMethodElement::isAbstract)
.anyMatch(method -> !Processors.hasDaggerAbstractMethodAnnotation(method));
}
- private static boolean hasOnlyStaticProvides(TypeElement type) {
+ private static boolean hasOnlyStaticProvides(XTypeElement type) {
// TODO(erichang): Check for @Produces too when we have a producers story
- return ElementFilter.methodsIn(type.getEnclosedElements()).stream()
- .filter(method -> Processors.hasAnnotation(method, ClassNames.PROVIDES))
- .allMatch(method -> method.getModifiers().contains(STATIC));
+ return type.getDeclaredMethods().stream()
+ .filter(method -> method.hasAnnotation(ClassNames.PROVIDES))
+ .allMatch(XMethodElement::isStatic);
}
- private static boolean hasVisibleEmptyConstructor(TypeElement type) {
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
+ private static boolean hasVisibleEmptyConstructor(XTypeElement type) {
+ List<XConstructorElement> constructors = type.getConstructors();
return constructors.isEmpty()
|| constructors.stream()
.filter(constructor -> constructor.getParameters().isEmpty())
- .anyMatch(constructor -> !constructor.getModifiers().contains(PRIVATE));
+ .anyMatch(constructor -> !constructor.isPrivate());
}
}
diff --git a/java/dagger/hilt/processor/internal/root/RootProcessingStep.java b/java/dagger/hilt/processor/internal/root/RootProcessingStep.java
new file mode 100644
index 0000000..f281995
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/root/RootProcessingStep.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2019 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 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.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static java.util.Arrays.stream;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BadInputException;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
+import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
+import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
+import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
+import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs;
+import dagger.hilt.processor.internal.root.ir.AggregatedDepsIr;
+import dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr;
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIr;
+import dagger.hilt.processor.internal.root.ir.AggregatedRootIrValidator;
+import dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr;
+import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr;
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr;
+import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIrCreator;
+import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
+import dagger.hilt.processor.internal.root.ir.InvalidRootsException;
+import dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr;
+import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.util.Set;
+
+/** Processor that outputs dagger components based on transitive build deps. */
+public final class RootProcessingStep extends BaseProcessingStep {
+
+ private boolean processed;
+ private GeneratesRootInputs generatesRootInputs;
+
+ public RootProcessingStep(XProcessingEnv env) {
+ super(env);
+ generatesRootInputs = new GeneratesRootInputs(processingEnv());
+ }
+
+ private Mode getMode() {
+ return useAggregatingRootProcessor(processingEnv()) ? Mode.Aggregating : Mode.Isolating;
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return stream(RootType.values()).map(RootType::className).collect(toImmutableSet());
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) throws Exception {
+ XTypeElement rootElement = XElements.asTypeElement(element);
+ // TODO(bcorso): Move this logic into a separate isolating processor to avoid regenerating it
+ // for unrelated changes in Gradle.
+ RootType rootType = RootType.of(rootElement);
+ if (rootType.isTestRoot()) {
+ new TestInjectorGenerator(processingEnv(), TestRootMetadata.of(processingEnv(), rootElement))
+ .generate();
+ }
+
+ XTypeElement originatingRootElement =
+ Root.create(rootElement, processingEnv()).originatingRootElement();
+ new AggregatedRootGenerator(
+ rootElement, originatingRootElement, processingEnv().requireTypeElement(annotation))
+ .generate();
+ }
+
+ @Override
+ protected void postProcess(XProcessingEnv env, XRoundEnv roundEnv) throws Exception {
+ if (!useAggregatingRootProcessor(processingEnv())) {
+ return;
+ }
+ ImmutableSet<XElement> newElements =
+ generatesRootInputs.getElementsToWaitFor(roundEnv).stream().collect(toImmutableSet());
+ if (processed) {
+ checkState(
+ newElements.isEmpty(),
+ "Found extra modules after compilation: %s\n"
+ + "(If you are adding an annotation processor that generates root input for hilt, "
+ + "the annotation must be annotated with @dagger.hilt.GeneratesRootInput.\n)",
+ newElements.stream().map(XElements::toStableString).collect(toImmutableList()));
+ } else if (newElements.isEmpty()) {
+ processed = true;
+
+ ImmutableSet<AggregatedRootIr> rootsToProcess = rootsToProcess();
+ if (rootsToProcess.isEmpty()) {
+ return;
+ }
+ // Generate an @ComponentTreeDeps for each unique component tree.
+ ComponentTreeDepsGenerator componentTreeDepsGenerator =
+ new ComponentTreeDepsGenerator(processingEnv(), getMode());
+ for (ComponentTreeDepsMetadata metadata : componentTreeDepsMetadatas(rootsToProcess)) {
+ componentTreeDepsGenerator.generate(metadata);
+ }
+
+ // Generate a sentinel for all processed roots.
+ for (AggregatedRootIr ir : rootsToProcess) {
+ XTypeElement rootElement = processingEnv().requireTypeElement(ir.getRoot().canonicalName());
+ new ProcessedRootSentinelGenerator(rootElement, getMode()).generate();
+ }
+ }
+ }
+
+ private ImmutableSet<AggregatedRootIr> rootsToProcess() {
+ ImmutableSet<ProcessedRootSentinelIr> processedRoots =
+ ProcessedRootSentinelMetadata.from(processingEnv()).stream()
+ .map(ProcessedRootSentinelMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedRootIr> aggregatedRoots =
+ AggregatedRootMetadata.from(processingEnv()).stream()
+ .map(AggregatedRootMetadata::toIr)
+ .collect(toImmutableSet());
+
+ boolean isCrossCompilationRootValidationDisabled =
+ isCrossCompilationRootValidationDisabled(
+ aggregatedRoots.stream()
+ .map(ir -> processingEnv().requireTypeElement(ir.getRoot().canonicalName()))
+ .collect(toImmutableSet()),
+ processingEnv());
+ try {
+ return ImmutableSet.copyOf(
+ AggregatedRootIrValidator.rootsToProcess(
+ isCrossCompilationRootValidationDisabled, processedRoots, aggregatedRoots));
+ } catch (InvalidRootsException ex) {
+ throw new BadInputException(ex.getMessage());
+ }
+ }
+
+ private ImmutableSet<ComponentTreeDepsMetadata> componentTreeDepsMetadatas(
+ ImmutableSet<AggregatedRootIr> aggregatedRoots) {
+ ImmutableSet<DefineComponentClassesIr> defineComponentDeps =
+ DefineComponentClassesMetadata.from(processingEnv()).stream()
+ .map(DefineComponentClassesMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AliasOfPropagatedDataIr> aliasOfDeps =
+ AliasOfPropagatedDataMetadata.from(processingEnv()).stream()
+ .map(AliasOfPropagatedDataMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedDepsIr> aggregatedDeps =
+ AggregatedDepsMetadata.from(processingEnv()).stream()
+ .map(AggregatedDepsMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedUninstallModulesIr> aggregatedUninstallModulesDeps =
+ AggregatedUninstallModulesMetadata.from(processingEnv()).stream()
+ .map(AggregatedUninstallModulesMetadata::toIr)
+ .collect(toImmutableSet());
+ ImmutableSet<AggregatedEarlyEntryPointIr> aggregatedEarlyEntryPointDeps =
+ AggregatedEarlyEntryPointMetadata.from(processingEnv()).stream()
+ .map(AggregatedEarlyEntryPointMetadata::toIr)
+ .collect(toImmutableSet());
+
+ // We should be guaranteed that there are no mixed roots, so check if this is prod or test.
+ boolean isTest = aggregatedRoots.stream().anyMatch(AggregatedRootIr::isTestRoot);
+ Set<ComponentTreeDepsIr> componentTreeDeps =
+ ComponentTreeDepsIrCreator.components(
+ isTest,
+ isSharedTestComponentsEnabled(processingEnv()),
+ aggregatedRoots,
+ defineComponentDeps,
+ aliasOfDeps,
+ aggregatedDeps,
+ aggregatedUninstallModulesDeps,
+ aggregatedEarlyEntryPointDeps);
+ return componentTreeDeps.stream()
+ .map(it -> ComponentTreeDepsMetadata.from(it, processingEnv()))
+ .collect(toImmutableSet());
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/root/RootProcessor.java b/java/dagger/hilt/processor/internal/root/RootProcessor.java
index 93ab9d9..cc2e224 100644
--- a/java/dagger/hilt/processor/internal/root/RootProcessor.java
+++ b/java/dagger/hilt/processor/internal/root/RootProcessor.java
@@ -16,192 +16,31 @@
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.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.DYNAMIC;
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.ImmutableSet;
-import dagger.hilt.processor.internal.BadInputException;
-import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
-import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
-import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
-import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs;
-import dagger.hilt.processor.internal.root.ir.AggregatedDepsIr;
-import dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr;
-import dagger.hilt.processor.internal.root.ir.AggregatedRootIr;
-import dagger.hilt.processor.internal.root.ir.AggregatedRootIrValidator;
-import dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr;
-import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr;
-import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr;
-import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIrCreator;
-import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
-import dagger.hilt.processor.internal.root.ir.InvalidRootsException;
-import dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr;
-import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
-import java.util.Arrays;
-import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/** Processor that outputs dagger components based on transitive build deps. */
@IncrementalAnnotationProcessor(DYNAMIC)
@AutoService(Processor.class)
-public final class RootProcessor extends BaseProcessor {
-
- private boolean processed;
- private GeneratesRootInputs generatesRootInputs;
-
+public final class RootProcessor extends JavacBaseProcessingStepProcessor {
@Override
- public synchronized void init(ProcessingEnvironment processingEnvironment) {
- super.init(processingEnvironment);
- generatesRootInputs = new GeneratesRootInputs(processingEnvironment);
+ protected BaseProcessingStep processingStep() {
+ return new RootProcessingStep(getXProcessingEnv());
}
@Override
public ImmutableSet<String> additionalProcessingOptions() {
- return useAggregatingRootProcessor(getProcessingEnv())
+ return useAggregatingRootProcessor(getXProcessingEnv())
? ImmutableSet.of(AGGREGATING.getProcessorOption())
: ImmutableSet.of(ISOLATING.getProcessorOption());
}
-
- @Override
- public ImmutableSet<String> getSupportedAnnotationTypes() {
- return ImmutableSet.<String>builder()
- .addAll(
- Arrays.stream(RootType.values())
- .map(rootType -> rootType.className().toString())
- .collect(toImmutableSet()))
- .build();
- }
-
- @Override
- public void processEach(TypeElement annotation, Element element) throws Exception {
- TypeElement rootElement = MoreElements.asType(element);
- // TODO(bcorso): Move this logic into a separate isolating processor to avoid regenerating it
- // for unrelated changes in Gradle.
- RootType rootType = RootType.of(rootElement);
- if (rootType.isTestRoot()) {
- new TestInjectorGenerator(
- getProcessingEnv(), TestRootMetadata.of(getProcessingEnv(), rootElement))
- .generate();
- }
-
- TypeElement originatingRootElement =
- Root.create(rootElement, getProcessingEnv()).originatingRootElement();
- new AggregatedRootGenerator(rootElement, originatingRootElement, annotation, getProcessingEnv())
- .generate();
- }
-
- @Override
- public void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
- if (!useAggregatingRootProcessor(getProcessingEnv())) {
- return;
- }
- ImmutableSet<Element> newElements = generatesRootInputs.getElementsToWaitFor(roundEnv);
- if (processed) {
- checkState(
- newElements.isEmpty(),
- "Found extra modules after compilation: %s\n"
- + "(If you are adding an annotation processor that generates root input for hilt, "
- + "the annotation must be annotated with @dagger.hilt.GeneratesRootInput.\n)",
- newElements);
- } else if (newElements.isEmpty()) {
- processed = true;
-
- ImmutableSet<AggregatedRootIr> rootsToProcess = rootsToProcess();
- if (rootsToProcess.isEmpty()) {
- return;
- }
- // Generate an @ComponentTreeDeps for each unique component tree.
- ComponentTreeDepsGenerator componentTreeDepsGenerator =
- new ComponentTreeDepsGenerator(getProcessingEnv());
- for (ComponentTreeDepsMetadata metadata : componentTreeDepsMetadatas(rootsToProcess)) {
- componentTreeDepsGenerator.generate(metadata);
- }
-
- // Generate a sentinel for all processed roots.
- for (AggregatedRootIr ir : rootsToProcess) {
- TypeElement rootElement = getElementUtils().getTypeElement(ir.getRoot().canonicalName());
- new ProcessedRootSentinelGenerator(rootElement, getProcessingEnv()).generate();
- }
- }
- }
-
- private ImmutableSet<AggregatedRootIr> rootsToProcess() {
- ImmutableSet<ProcessedRootSentinelIr> processedRoots =
- ProcessedRootSentinelMetadata.from(getElementUtils()).stream()
- .map(ProcessedRootSentinelMetadata::toIr)
- .collect(toImmutableSet());
- ImmutableSet<AggregatedRootIr> aggregatedRoots =
- AggregatedRootMetadata.from(processingEnv).stream()
- .map(AggregatedRootMetadata::toIr)
- .collect(toImmutableSet());
-
- boolean isCrossCompilationRootValidationDisabled =
- isCrossCompilationRootValidationDisabled(
- aggregatedRoots.stream()
- .map(ir -> getElementUtils().getTypeElement(ir.getRoot().canonicalName()))
- .collect(toImmutableSet()),
- processingEnv);
- try {
- return ImmutableSet.copyOf(
- AggregatedRootIrValidator.rootsToProcess(
- isCrossCompilationRootValidationDisabled, processedRoots, aggregatedRoots));
- } catch (InvalidRootsException ex) {
- throw new BadInputException(ex.getMessage());
- }
- }
-
- private ImmutableSet<ComponentTreeDepsMetadata> componentTreeDepsMetadatas(
- ImmutableSet<AggregatedRootIr> aggregatedRoots) {
- ImmutableSet<DefineComponentClassesIr> defineComponentDeps =
- DefineComponentClassesMetadata.from(getElementUtils()).stream()
- .map(DefineComponentClassesMetadata::toIr)
- .collect(toImmutableSet());
- ImmutableSet<AliasOfPropagatedDataIr> aliasOfDeps =
- AliasOfPropagatedDataMetadata.from(getElementUtils()).stream()
- .map(AliasOfPropagatedDataMetadata::toIr)
- .collect(toImmutableSet());
- ImmutableSet<AggregatedDepsIr> aggregatedDeps =
- AggregatedDepsMetadata.from(getElementUtils()).stream()
- .map(AggregatedDepsMetadata::toIr)
- .collect(toImmutableSet());
- ImmutableSet<AggregatedUninstallModulesIr> aggregatedUninstallModulesDeps =
- AggregatedUninstallModulesMetadata.from(getElementUtils()).stream()
- .map(AggregatedUninstallModulesMetadata::toIr)
- .collect(toImmutableSet());
- ImmutableSet<AggregatedEarlyEntryPointIr> aggregatedEarlyEntryPointDeps =
- AggregatedEarlyEntryPointMetadata.from(getElementUtils()).stream()
- .map(AggregatedEarlyEntryPointMetadata::toIr)
- .collect(toImmutableSet());
-
- // We should be guaranteed that there are no mixed roots, so check if this is prod or test.
- boolean isTest = aggregatedRoots.stream().anyMatch(AggregatedRootIr::isTestRoot);
- Set<ComponentTreeDepsIr> componentTreeDeps =
- ComponentTreeDepsIrCreator.components(
- isTest,
- isSharedTestComponentsEnabled(processingEnv),
- aggregatedRoots,
- defineComponentDeps,
- aliasOfDeps,
- aggregatedDeps,
- aggregatedUninstallModulesDeps,
- aggregatedEarlyEntryPointDeps);
- return componentTreeDeps.stream()
- .map(it -> ComponentTreeDepsMetadata.from(it, getElementUtils()))
- .collect(toImmutableSet());
- }
}
diff --git a/java/dagger/hilt/processor/internal/root/RootType.java b/java/dagger/hilt/processor/internal/root/RootType.java
index a6efc84..28bc12f 100644
--- a/java/dagger/hilt/processor/internal/root/RootType.java
+++ b/java/dagger/hilt/processor/internal/root/RootType.java
@@ -16,10 +16,9 @@
package dagger.hilt.processor.internal.root;
+import androidx.room.compiler.processing.XTypeElement;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-import javax.lang.model.element.TypeElement;
/** The valid root types for Hilt applications. */
// TODO(erichang): Fix this class so we don't have to have placeholders
@@ -46,12 +45,12 @@
return annotation;
}
- public static RootType of(TypeElement element) {
- if (Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_APP)) {
+ public static RootType of(XTypeElement element) {
+ if (element.hasAnnotation(ClassNames.HILT_ANDROID_APP)) {
return ROOT;
- } else if (Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_TEST)) {
+ } else if (element.hasAnnotation(ClassNames.HILT_ANDROID_TEST)) {
return TEST_ROOT;
- } else if (Processors.hasAnnotation(element, ClassNames.INTERNAL_TEST_ROOT)) {
+ } else if (element.hasAnnotation(ClassNames.INTERNAL_TEST_ROOT)) {
return TEST_ROOT;
}
throw new IllegalStateException("Unknown root type: " + element);
diff --git a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java b/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
index 19145f4..689dae7 100644
--- a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
@@ -23,8 +23,12 @@
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;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XConstructorElement;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
@@ -37,21 +41,18 @@
import dagger.hilt.processor.internal.Processors;
import java.io.IOException;
import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
/** Generates an implementation of {@link dagger.hilt.android.internal.TestComponentData}. */
public final class TestComponentDataGenerator {
- private final ProcessingEnvironment processingEnv;
- private final TypeElement originatingElement;
+ private final XProcessingEnv processingEnv;
+ private final XTypeElement originatingElement;
private final RootMetadata rootMetadata;
private final ClassName name;
private final ComponentNames componentNames;
public TestComponentDataGenerator(
- ProcessingEnvironment processingEnv,
- TypeElement originatingElement,
+ XProcessingEnv processingEnv,
+ XTypeElement originatingElement,
RootMetadata rootMetadata,
ComponentNames componentNames) {
this.processingEnv = processingEnv;
@@ -92,28 +93,29 @@
public void generate() throws IOException {
TypeSpec.Builder generator =
TypeSpec.classBuilder(name)
- .addOriginatingElement(originatingElement)
.superclass(ClassNames.TEST_COMPONENT_DATA_SUPPLIER)
.addModifiers(PUBLIC, FINAL)
.addMethod(getMethod())
.addMethod(getTestInjectInternalMethod());
+ JavaPoetExtKt.addOriginatingElement(generator, originatingElement);
+
Processors.addGeneratedAnnotation(
generator, processingEnv, ClassNames.ROOT_PROCESSOR.toString());
- JavaFile.builder(name.packageName(), generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
+ processingEnv
+ .getFiler()
+ .write(JavaFile.builder(name.packageName(), generator.build()).build(), Mode.Isolating);
}
private MethodSpec getMethod() {
- TypeElement testElement = rootMetadata.testRootMetadata().testElement();
+ XTypeElement testElement = rootMetadata.testRootMetadata().testElement();
ClassName component =
componentNames.generatedComponent(
- ClassName.get(testElement), ClassNames.SINGLETON_COMPONENT);
- ImmutableSet<TypeElement> daggerRequiredModules =
+ testElement.getClassName(), ClassNames.SINGLETON_COMPONENT);
+ ImmutableSet<XTypeElement> daggerRequiredModules =
rootMetadata.modulesThatDaggerCannotConstruct(ClassNames.SINGLETON_COMPONENT);
- ImmutableSet<TypeElement> hiltRequiredModules =
+ ImmutableSet<XTypeElement> hiltRequiredModules =
daggerRequiredModules.stream()
.filter(module -> !canBeConstructedByHilt(module, testElement))
.collect(toImmutableSet());
@@ -125,7 +127,8 @@
"return new $T($L, $L, $L, $L, $L)",
ClassNames.TEST_COMPONENT_DATA,
rootMetadata.waitForBindValue(),
- CodeBlock.of("testInstance -> injectInternal(($1T) testInstance)", testElement),
+ CodeBlock.of(
+ "testInstance -> injectInternal(($1T) testInstance)", testElement.getClassName()),
getElementsListed(daggerRequiredModules),
getElementsListed(hiltRequiredModules),
CodeBlock.of(
@@ -157,8 +160,8 @@
* : (FooTest.TestModule) modules.get(FooTest.TestModule.class))
* </code></pre>
*/
- private static String getAddModuleStatement(TypeElement module, TypeElement testElement) {
- ClassName className = ClassName.get(module);
+ private static String getAddModuleStatement(XTypeElement module, XTypeElement testElement) {
+ ClassName className = module.getClassName();
return canBeConstructedByHilt(module, testElement)
? CodeBlock.of(
".$1L(autoAddModuleEnabled\n"
@@ -178,21 +181,21 @@
.toString();
}
- private static boolean canBeConstructedByHilt(TypeElement module, TypeElement testElement) {
+ private static boolean canBeConstructedByHilt(XTypeElement module, XTypeElement testElement) {
return hasOnlyAccessibleNoArgConstructor(module)
&& module.getEnclosingElement().equals(testElement);
}
- private static boolean hasOnlyAccessibleNoArgConstructor(TypeElement module) {
- List<ExecutableElement> declaredConstructors = constructorsIn(module.getEnclosedElements());
+ private static boolean hasOnlyAccessibleNoArgConstructor(XTypeElement module) {
+ List<XConstructorElement> declaredConstructors = module.getConstructors();
return declaredConstructors.isEmpty()
|| (declaredConstructors.size() == 1
- && !declaredConstructors.get(0).getModifiers().contains(PRIVATE)
+ && !declaredConstructors.get(0).isPrivate()
&& declaredConstructors.get(0).getParameters().isEmpty());
}
/* Arrays.asList(FooTest.TestModule.class, ...) */
- private static CodeBlock getElementsListed(ImmutableSet<TypeElement> modules) {
+ private static CodeBlock getElementsListed(ImmutableSet<XTypeElement> modules) {
return modules.isEmpty()
? CodeBlock.of("$T.emptySet()", ClassNames.COLLECTIONS)
: CodeBlock.of(
@@ -200,13 +203,13 @@
ClassNames.HASH_SET,
ClassNames.ARRAYS,
modules.stream()
- .map(module -> CodeBlock.of("$T.class", module).toString())
+ .map(module -> CodeBlock.of("$T.class", module.getClassName()).toString())
.collect(joining(",")));
}
private MethodSpec getTestInjectInternalMethod() {
- TypeElement testElement = rootMetadata.testRootMetadata().testElement();
- ClassName testName = ClassName.get(testElement);
+ XTypeElement testElement = rootMetadata.testRootMetadata().testElement();
+ ClassName testName = testElement.getClassName();
return MethodSpec.methodBuilder("injectInternal")
.addModifiers(PRIVATE, STATIC)
.addParameter(testName, "testInstance")
@@ -218,9 +221,10 @@
.build();
}
- private CodeBlock callInjectTest(TypeElement testElement) {
+ private CodeBlock callInjectTest(XTypeElement testElement) {
return CodeBlock.of(
- "(($T) (($T) $T.getApplication($T.getApplicationContext())).generatedComponent()).injectTest(testInstance)",
+ "(($T) (($T) $T.getApplication($T.getApplicationContext()))"
+ + ".generatedComponent()).injectTest(testInstance)",
rootMetadata.testRootMetadata().testInjectorName(),
ClassNames.GENERATED_COMPONENT_MANAGER,
ClassNames.CONTEXTS,
diff --git a/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java b/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java
index b7200e7..1c6ddba 100644
--- a/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java
+++ b/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java
@@ -16,6 +16,10 @@
package dagger.hilt.processor.internal.root;
+import androidx.room.compiler.processing.JavaPoetExtKt;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
@@ -24,16 +28,14 @@
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.Modifier;
-import javax.lang.model.element.TypeElement;
/** Generates an entry point for a test. */
public final class TestInjectorGenerator {
- private final ProcessingEnvironment env;
+ private final XProcessingEnv env;
private final TestRootMetadata metadata;
- TestInjectorGenerator(ProcessingEnvironment env, TestRootMetadata metadata) {
+ TestInjectorGenerator(XProcessingEnv env, TestRootMetadata metadata) {
this.env = env;
this.metadata = metadata;
}
@@ -46,7 +48,6 @@
public void generate() throws IOException {
TypeSpec.Builder builder =
TypeSpec.interfaceBuilder(metadata.testInjectorName())
- .addOriginatingElement(metadata.testElement())
.addAnnotation(Processors.getOriginatingElementAnnotation(metadata.testElement()))
.addAnnotation(ClassNames.GENERATED_ENTRY_POINT)
.addAnnotation(
@@ -61,15 +62,17 @@
metadata.testName(),
Processors.upperToLowerCamel(metadata.testName().simpleName()))
.build());
+ JavaPoetExtKt.addOriginatingElement(builder, metadata.testElement());
Processors.addGeneratedAnnotation(builder, env, getClass());
- JavaFile.builder(metadata.testInjectorName().packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
+ env.getFiler()
+ .write(
+ JavaFile.builder(metadata.testInjectorName().packageName(), builder.build()).build(),
+ Mode.Isolating);
}
- private static ClassName installInComponent(TypeElement testElement) {
+ private static ClassName installInComponent(XTypeElement testElement) {
return ClassNames.SINGLETON_COMPONENT;
}
}
diff --git a/java/dagger/hilt/processor/internal/root/TestRootMetadata.java b/java/dagger/hilt/processor/internal/root/TestRootMetadata.java
index 561beb7..5dc6fee 100644
--- a/java/dagger/hilt/processor/internal/root/TestRootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/TestRootMetadata.java
@@ -16,14 +16,15 @@
package dagger.hilt.processor.internal.root;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.ClassNames;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.Processors;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
+import dagger.internal.codegen.xprocessing.XElements;
import javax.lang.model.element.TypeElement;
/** Metadata class for {@code InternalTestRoot} annotated classes. */
@@ -31,19 +32,19 @@
abstract class TestRootMetadata {
/** Returns the {@link TypeElement} for the test class. */
- abstract TypeElement testElement();
+ abstract XTypeElement testElement();
/** Returns the {@link TypeElement} for the base application. */
- abstract TypeElement baseElement();
+ abstract XTypeElement baseElement();
/** Returns the {@link ClassName} for the test class. */
ClassName testName() {
- return ClassName.get(testElement());
+ return testElement().getClassName();
}
/** Returns the {@link ClassName} for the base application. */
ClassName baseAppName() {
- return ClassName.get(baseElement());
+ return baseElement().getClassName();
}
/** The name of the generated Hilt test application class for the given test name. */
@@ -56,19 +57,18 @@
return Processors.append(Processors.getEnclosedClassName(testName()), "_GeneratedInjector");
}
- static TestRootMetadata of(ProcessingEnvironment env, Element element) {
+ static TestRootMetadata of(XProcessingEnv env, XElement element) {
- TypeElement testElement = MoreElements.asType(element);
+ XTypeElement testElement = XElements.asTypeElement(element);
+ XTypeElement baseElement = env.requireTypeElement(ClassNames.MULTI_DEX_APPLICATION);
- TypeElement baseElement =
- env.getElementUtils().getTypeElement(ClassNames.MULTI_DEX_APPLICATION.toString());
ProcessorErrors.checkState(
- !Processors.hasAnnotation(element, ClassNames.ANDROID_ENTRY_POINT),
+ !element.hasAnnotation(ClassNames.ANDROID_ENTRY_POINT),
element,
"Tests cannot be annotated with @AndroidEntryPoint. Please use @HiltAndroidTest");
ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_TEST),
+ element.hasAnnotation(ClassNames.HILT_ANDROID_TEST),
element,
"Tests must be annotated with @HiltAndroidTest");
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java
index 654a690..5902da0 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesGenerator.java
@@ -16,13 +16,11 @@
package dagger.hilt.processor.internal.uninstallmodules;
+import androidx.room.compiler.processing.XTypeElement;
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}
@@ -30,26 +28,22 @@
*/
final class AggregatedUninstallModulesGenerator {
- private final ProcessingEnvironment env;
- private final TypeElement testElement;
- private final ImmutableList<TypeElement> uninstallModuleElements;
+ private final XTypeElement testElement;
+ private final ImmutableList<XTypeElement> uninstallModuleElements;
AggregatedUninstallModulesGenerator(
- TypeElement testElement,
- ImmutableList<TypeElement> uninstallModuleElements,
- ProcessingEnvironment env) {
+ XTypeElement testElement,
+ ImmutableList<XTypeElement> uninstallModuleElements) {
this.testElement = testElement;
this.uninstallModuleElements = uninstallModuleElements;
- this.env = env;
}
- void generate() throws IOException {
+ void generate() {
Processors.generateAggregatingClass(
ClassNames.AGGREGATED_UNINSTALL_MODULES_PACKAGE,
aggregatedUninstallModulesAnnotation(),
testElement,
- getClass(),
- env);
+ getClass());
}
private AnnotationSpec aggregatedUninstallModulesAnnotation() {
@@ -57,7 +51,7 @@
AnnotationSpec.builder(ClassNames.AGGREGATED_UNINSTALL_MODULES);
builder.addMember("test", "$S", testElement.getQualifiedName());
uninstallModuleElements.stream()
- .map(TypeElement::getQualifiedName)
+ .map(XTypeElement::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
index c41dcf0..6f71552 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/AggregatedUninstallModulesMetadata.java
@@ -16,24 +16,21 @@
package dagger.hilt.processor.internal.uninstallmodules;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
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 com.squareup.javapoet.ClassName;
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 dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr;
import java.util.stream.Collectors;
-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
@@ -43,57 +40,52 @@
public abstract class AggregatedUninstallModulesMetadata {
/** Returns the aggregating element */
- public abstract TypeElement aggregatingElement();
+ public abstract XTypeElement aggregatingElement();
/** Returns the test annotated with {@link dagger.hilt.android.testing.UninstallModules}. */
- public abstract TypeElement testElement();
+ public abstract XTypeElement testElement();
/**
* Returns the list of uninstall modules in {@link dagger.hilt.android.testing.UninstallModules}.
*/
- public abstract ImmutableList<TypeElement> uninstallModuleElements();
+ public abstract ImmutableList<XTypeElement> uninstallModuleElements();
/** Returns metadata for all aggregated elements in the aggregating package. */
- public static ImmutableSet<AggregatedUninstallModulesMetadata> from(Elements elements) {
+ public static ImmutableSet<AggregatedUninstallModulesMetadata> from(XProcessingEnv env) {
return from(
AggregatedElements.from(
ClassNames.AGGREGATED_UNINSTALL_MODULES_PACKAGE,
ClassNames.AGGREGATED_UNINSTALL_MODULES,
- elements),
- elements);
+ env));
}
/** Returns metadata for each aggregated element. */
public static ImmutableSet<AggregatedUninstallModulesMetadata> from(
- ImmutableSet<TypeElement> aggregatedElements, Elements elements) {
+ ImmutableSet<XTypeElement> aggregatedElements) {
return aggregatedElements.stream()
- .map(aggregatedElement -> create(aggregatedElement, elements))
+ .map(aggregatedElement -> create(aggregatedElement, getProcessingEnv(aggregatedElement)))
.collect(toImmutableSet());
}
public static AggregatedUninstallModulesIr toIr(AggregatedUninstallModulesMetadata metadata) {
return new AggregatedUninstallModulesIr(
- ClassName.get(metadata.aggregatingElement()),
- ClassName.get(metadata.testElement()).canonicalName(),
+ metadata.aggregatingElement().getClassName(),
+ metadata.testElement().getClassName().canonicalName(),
metadata.uninstallModuleElements().stream()
- .map(ClassName::get)
+ .map(XTypeElement::getClassName)
.map(ClassName::canonicalName)
.collect(Collectors.toList()));
}
- 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);
+ private static AggregatedUninstallModulesMetadata create(
+ XTypeElement element, XProcessingEnv env) {
+ XAnnotation annotationMirror = element.getAnnotation(ClassNames.AGGREGATED_UNINSTALL_MODULES);
return new AutoValue_AggregatedUninstallModulesMetadata(
element,
- elements.getTypeElement(AnnotationValues.getString(values.get("test"))),
- AnnotationValues.getAnnotationValues(values.get("uninstallModules")).stream()
- .map(AnnotationValues::getString)
- .map(elements::getTypeElement)
+ env.requireTypeElement(annotationMirror.getAsString("test")),
+ annotationMirror.getAsStringList("uninstallModules").stream()
+ .map(env::requireTypeElement)
.collect(toImmutableList()));
}
}
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
index 876c473..818abbc 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/BUILD
@@ -28,6 +28,8 @@
name = "processor_lib",
srcs = [
"AggregatedUninstallModulesGenerator.java",
+ "KspUninstallModulesProcessor.java",
+ "UninstallModulesProcessingStep.java",
"UninstallModulesProcessor.java",
],
deps = [
@@ -36,11 +38,12 @@
"//java/dagger/hilt/processor/internal:processor_errors",
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/internal/codegen/extension",
- "//third_party/java/auto:common",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:service",
"//third_party/java/guava/collect",
"//third_party/java/incap",
"//third_party/java/javapoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
@@ -55,6 +58,7 @@
"//java/dagger/hilt/processor/internal:processors",
"//java/dagger/hilt/processor/internal/root/ir",
"//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
"//third_party/java/auto:value",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/KspUninstallModulesProcessor.java b/java/dagger/hilt/processor/internal/uninstallmodules/KspUninstallModulesProcessor.java
new file mode 100644
index 0000000..ab7d6f4
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/KspUninstallModulesProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.google.auto.service.AutoService;
+import com.google.devtools.ksp.processing.SymbolProcessor;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import com.google.devtools.ksp.processing.SymbolProcessorProvider;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.KspBaseProcessingStepProcessor;
+
+/** Validates {@link dagger.hilt.android.testing.UninstallModules} usages. */
+public final class KspUninstallModulesProcessor extends KspBaseProcessingStepProcessor {
+
+ public KspUninstallModulesProcessor(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ super(symbolProcessorEnvironment);
+ }
+
+ @Override
+ protected BaseProcessingStep processingStep() {
+ return new UninstallModulesProcessingStep(getXProcessingEnv());
+ }
+
+ /** Provides the {@link KspUninstallModulesProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
+ public static final class Provider implements SymbolProcessorProvider {
+ @Override
+ public SymbolProcessor create(SymbolProcessorEnvironment symbolProcessorEnvironment) {
+ return new KspUninstallModulesProcessor(symbolProcessorEnvironment);
+ }
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessingStep.java b/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessingStep.java
new file mode 100644
index 0000000..6a20244
--- /dev/null
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessingStep.java
@@ -0,0 +1,104 @@
+/*
+ * 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 androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.ClassNames;
+import dagger.hilt.processor.internal.ProcessorErrors;
+import dagger.hilt.processor.internal.Processors;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
+
+/** Validates {@link dagger.hilt.android.testing.UninstallModules} usages. */
+public final class UninstallModulesProcessingStep extends BaseProcessingStep {
+
+ public UninstallModulesProcessingStep(XProcessingEnv env) {
+ super(env);
+ }
+
+ @Override
+ protected ImmutableSet<ClassName> annotationClassNames() {
+ return ImmutableSet.of(ClassNames.UNINSTALL_MODULES);
+ }
+
+ @Override
+ public void processEach(ClassName annotation, XElement element) {
+ // TODO(bcorso): Consider using RootType to check this?
+ // TODO(bcorso): Loosen this restriction to allow defining sets of ignored modules in libraries.
+ ProcessorErrors.checkState(
+ isTypeElement(element) && element.hasAnnotation(ClassNames.HILT_ANDROID_TEST),
+ element,
+ "@%s should only be used on test classes annotated with @%s, but found: %s",
+ annotation.simpleName(),
+ ClassNames.HILT_ANDROID_TEST.simpleName(),
+ XElements.toStableString(element));
+
+ XTypeElement testElement = XElements.asTypeElement(element);
+ ImmutableList<XTypeElement> uninstallModules =
+ XAnnotations.getAsTypeElementList(
+ testElement.getAnnotation(ClassNames.UNINSTALL_MODULES), "value");
+
+ checkModulesHaveInstallIn(testElement, uninstallModules);
+ checkModulesDontOriginateFromTest(testElement, uninstallModules);
+
+ new AggregatedUninstallModulesGenerator(testElement, uninstallModules).generate();
+ }
+
+ private void checkModulesHaveInstallIn(
+ XTypeElement testElement, ImmutableList<XTypeElement> uninstallModules) {
+ ImmutableList<XTypeElement> invalidModules =
+ uninstallModules.stream()
+ .filter(
+ module ->
+ !(module.hasAnnotation(ClassNames.MODULE)
+ && module.hasAnnotation(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.stream().map(XElements::toStableString).collect(toImmutableList()));
+ }
+
+ private void checkModulesDontOriginateFromTest(
+ XTypeElement testElement, ImmutableList<XTypeElement> uninstallModules) {
+ ImmutableList<ClassName> invalidModules =
+ uninstallModules.stream()
+ .filter(module -> Processors.getOriginatingTestElement(module).isPresent())
+ .map(XTypeElement::getClassName)
+ .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);
+ }
+}
diff --git a/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java b/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java
index c7e528d..c13ac4a 100644
--- a/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java
+++ b/java/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessor.java
@@ -16,95 +16,20 @@
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 dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.hilt.processor.internal.JavacBaseProcessingStepProcessor;
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 {
-
+public final class UninstallModulesProcessor extends JavacBaseProcessingStepProcessor {
@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);
+ protected BaseProcessingStep processingStep() {
+ return new UninstallModulesProcessingStep(getXProcessingEnv());
}
}
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index 1df0313..a3868b5 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -43,6 +43,7 @@
"//java/dagger/internal/codegen/compileroption",
"//java/dagger/internal/codegen/componentgenerator",
"//java/dagger/internal/codegen/kotlin",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/processingstep",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
@@ -80,12 +81,13 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/processingstep",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
+ "//java/dagger/internal/codegen/xprocessing",
],
artifact_target_maven_deps = [
- "com.google.auto:auto-common",
"com.google.code.findbugs:jsr305",
"com.google.dagger:dagger-producers",
"com.google.dagger:dagger-spi",
@@ -100,7 +102,6 @@
"net.ltgt.gradle.incap:incap",
"org.checkerframework:checker-compat-qual",
"org.jetbrains.kotlin:kotlin-stdlib",
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
],
javadoc_root_packages = ["dagger.internal.codegen"],
# The javadocs should only include ComponentProcessor.java, since that is the only class used
diff --git a/java/dagger/internal/codegen/KspComponentProcessor.java b/java/dagger/internal/codegen/KspComponentProcessor.java
index 2b6d0f7..8b07f93 100644
--- a/java/dagger/internal/codegen/KspComponentProcessor.java
+++ b/java/dagger/internal/codegen/KspComponentProcessor.java
@@ -20,6 +20,7 @@
import androidx.room.compiler.processing.XProcessingStep;
import androidx.room.compiler.processing.XRoundEnv;
import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor;
+import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.ksp.processing.SymbolProcessor;
@@ -63,6 +64,7 @@
}
/** Provides the {@link KspComponentProcessor}. */
+ @AutoService(SymbolProcessorProvider.class)
public static final class Provider implements SymbolProcessorProvider {
/**
* Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
diff --git a/java/dagger/internal/codegen/base/BUILD b/java/dagger/internal/codegen/base/BUILD
index 56bf7f3..8d5fd5e 100644
--- a/java/dagger/internal/codegen/base/BUILD
+++ b/java/dagger/internal/codegen/base/BUILD
@@ -38,8 +38,8 @@
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/xprocessing",
- "//java/dagger/spi",
"//third_party/java/auto:value",
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
diff --git a/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java b/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java
index fc54c96..208da2b 100644
--- a/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java
+++ b/java/dagger/internal/codegen/base/DaggerSuperficialValidation.java
@@ -56,10 +56,10 @@
import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList;
-import com.google.devtools.ksp.symbol.ClassKind;
import com.squareup.javapoet.ClassName;
import dagger.Reusable;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.xprocessing.XAnnotationValues;
import dagger.internal.codegen.xprocessing.XAnnotations;
import dagger.internal.codegen.xprocessing.XElements;
@@ -127,14 +127,7 @@
// In XProcessing, there is no generic way to get an element "asType" so we break this down
// differently for different element kinds.
if (isTypeElement(element)) {
- XTypeElement typeElement = asTypeElement(element);
- // TODO(b/247828057): Due to a bug in XProcessing, enum entry types are sometimes
- // represented by XTypeElement rather than XEnumEntry in KSP which leads to failures later
- // on. Thus, skip validation in these cases until this bug is fixed.
- if (!(processingEnv.getBackend() == Backend.KSP
- && XConverters.toKS(typeElement).getClassKind() == ClassKind.ENUM_ENTRY)) {
- validateType(Ascii.toLowerCase(getKindName(element)), typeElement.getType());
- }
+ validateType(Ascii.toLowerCase(getKindName(element)), asTypeElement(element).getType());
} else if (isVariableElement(element)) {
validateType(
Ascii.toLowerCase(getKindName(element)) + " type", asVariable(element).getType());
@@ -279,7 +272,18 @@
if (typeElement.getSuperType() != null) {
validateType("superclass", typeElement.getSuperType());
}
- validateElements(typeElement.getEnclosedElements());
+ // TODO (b/286313067) move the logic to ComponentValidator once the validation logic is
+ // split into individual validators to satisfy different needs.
+ // Dagger doesn't use components' static method, therefore, they shouldn't be validated to
+ // be able to stop component generation.
+ if (typeElement.hasAnnotation(TypeNames.COMPONENT)) {
+ validateElements(
+ typeElement.getEnclosedElements().stream()
+ .filter(member -> !XElements.isStatic(member))
+ .collect(toImmutableList()));
+ } else {
+ validateElements(typeElement.getEnclosedElements());
+ }
} else if (isExecutable(element)) {
if (isMethod(element)) {
validateType("return type", asMethod(element).getReturnType());
@@ -400,10 +404,22 @@
private void validateAnnotation(XAnnotation annotation) {
try {
validateType("annotation type", annotation.getType());
- validateAnnotationValues(getDefaultValues(annotation));
- validateAnnotationValues(annotation.getAnnotationValues());
+ try {
+ // Note: We separate this into its own try-catch since there's a bug where we could get an
+ // error when getting the annotation values due to b/264089557. This way we will at least
+ // report the name of the annotation in the error message.
+ validateAnnotationValues(getDefaultValues(annotation));
+ validateAnnotationValues(annotation.getAnnotationValues());
+ } catch (RuntimeException exception) {
+ throw ValidationException.from(exception).append(annotation);
+ }
} catch (RuntimeException exception) {
- throw ValidationException.from(exception).append(annotation);
+ throw ValidationException.from(exception)
+ .append(
+ "annotation type: "
+ + (annotation.getType().isError()
+ ? annotation.getName() // SUPPRESS_GET_NAME_CHECK
+ : annotation.getClassName().canonicalName()));
}
}
diff --git a/java/dagger/internal/codegen/base/Keys.java b/java/dagger/internal/codegen/base/Keys.java
index dc061fe..0a29875 100644
--- a/java/dagger/internal/codegen/base/Keys.java
+++ b/java/dagger/internal/codegen/base/Keys.java
@@ -24,8 +24,8 @@
import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.Key;
import java.util.Optional;
/** Utility methods related to {@link Key}s. */
diff --git a/java/dagger/internal/codegen/base/MapType.java b/java/dagger/internal/codegen/base/MapType.java
index 00bea13..00401ed 100644
--- a/java/dagger/internal/codegen/base/MapType.java
+++ b/java/dagger/internal/codegen/base/MapType.java
@@ -26,8 +26,8 @@
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.Key;
/** Information about a {@link java.util.Map} type. */
@AutoValue
diff --git a/java/dagger/internal/codegen/base/OptionalType.java b/java/dagger/internal/codegen/base/OptionalType.java
index feef652..79b638d 100644
--- a/java/dagger/internal/codegen/base/OptionalType.java
+++ b/java/dagger/internal/codegen/base/OptionalType.java
@@ -30,7 +30,7 @@
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.Key;
/**
* Information about an {@code Optional} type.
diff --git a/java/dagger/internal/codegen/base/RequestKinds.java b/java/dagger/internal/codegen/base/RequestKinds.java
index d66cd71..a9c7e83 100644
--- a/java/dagger/internal/codegen/base/RequestKinds.java
+++ b/java/dagger/internal/codegen/base/RequestKinds.java
@@ -23,15 +23,15 @@
import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
import static dagger.internal.codegen.javapoet.TypeNames.producerOf;
import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static dagger.internal.codegen.model.RequestKind.LAZY;
+import static dagger.internal.codegen.model.RequestKind.PRODUCED;
+import static dagger.internal.codegen.model.RequestKind.PRODUCER;
+import static dagger.internal.codegen.model.RequestKind.PROVIDER;
import static dagger.internal.codegen.xprocessing.XProcessingEnvs.wrapType;
import static dagger.internal.codegen.xprocessing.XTypes.checkTypePresent;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
import static dagger.internal.codegen.xprocessing.XTypes.unwrapType;
-import static dagger.spi.model.RequestKind.LAZY;
-import static dagger.spi.model.RequestKind.PRODUCED;
-import static dagger.spi.model.RequestKind.PRODUCER;
-import static dagger.spi.model.RequestKind.PROVIDER;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
@@ -39,7 +39,7 @@
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.RequestKind;
/** Utility methods for {@link RequestKind}s. */
public final class RequestKinds {
@@ -142,7 +142,7 @@
/**
* A dagger- or {@code javax.inject}-defined class for {@code requestKind} that that can wrap
- * another type but share the same {@link dagger.spi.model.Key}.
+ * another type but share the same {@link dagger.internal.codegen.model.Key}.
*
* <p>For example, {@code Provider<String>} and {@code Lazy<String>} can both be requested if a
* key exists for {@code String}; they all share the same key.
diff --git a/java/dagger/internal/codegen/base/Scopes.java b/java/dagger/internal/codegen/base/Scopes.java
index b4cc323..935fe97 100644
--- a/java/dagger/internal/codegen/base/Scopes.java
+++ b/java/dagger/internal/codegen/base/Scopes.java
@@ -19,8 +19,8 @@
import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
import androidx.room.compiler.processing.XProcessingEnv;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.Scope;
/** Common names and convenience methods for {@link Scope}s. */
public final class Scopes {
diff --git a/java/dagger/internal/codegen/base/SetType.java b/java/dagger/internal/codegen/base/SetType.java
index 875eb4f..ab2ea91 100644
--- a/java/dagger/internal/codegen/base/SetType.java
+++ b/java/dagger/internal/codegen/base/SetType.java
@@ -25,8 +25,8 @@
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.Key;
/** Information about a {@link java.util.Set} type. */
@AutoValue
diff --git a/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java b/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
index 54ca6ce..a8bca09 100644
--- a/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
+++ b/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
@@ -43,9 +43,9 @@
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingKind;
import dagger.internal.codegen.xprocessing.XTypeElements;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.BindingKind;
import java.util.List;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/binding/BUILD b/java/dagger/internal/codegen/binding/BUILD
index b65233d..e606eb4 100644
--- a/java/dagger/internal/codegen/binding/BUILD
+++ b/java/dagger/internal/codegen/binding/BUILD
@@ -32,9 +32,9 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/xprocessing",
"//java/dagger/producers",
- "//java/dagger/spi",
"//third_party/java/auto:common",
"//third_party/java/auto:value",
"//third_party/java/error_prone:annotations",
diff --git a/java/dagger/internal/codegen/binding/Binding.java b/java/dagger/internal/codegen/binding/Binding.java
index c66bdaf..250e608 100644
--- a/java/dagger/internal/codegen/binding/Binding.java
+++ b/java/dagger/internal/codegen/binding/Binding.java
@@ -23,9 +23,9 @@
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Scope;
import java.util.Optional;
/**
diff --git a/java/dagger/internal/codegen/binding/BindingDeclaration.java b/java/dagger/internal/codegen/binding/BindingDeclaration.java
index 9647134..dd24c98 100644
--- a/java/dagger/internal/codegen/binding/BindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/BindingDeclaration.java
@@ -23,9 +23,9 @@
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XTypeElement;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XElements;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.Key;
import java.util.Comparator;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/binding/BindingFactory.java b/java/dagger/internal/codegen/binding/BindingFactory.java
index 6593e23..11fa591 100644
--- a/java/dagger/internal/codegen/binding/BindingFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingFactory.java
@@ -24,28 +24,27 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentProductionMethod;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
import static dagger.internal.codegen.binding.MapKeys.getMapKey;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.model.BindingKind.ASSISTED_FACTORY;
+import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.internal.codegen.model.BindingKind.BOUND_INSTANCE;
+import static dagger.internal.codegen.model.BindingKind.COMPONENT;
+import static dagger.internal.codegen.model.BindingKind.COMPONENT_DEPENDENCY;
+import static dagger.internal.codegen.model.BindingKind.COMPONENT_PRODUCTION;
+import static dagger.internal.codegen.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.MEMBERS_INJECTOR;
+import static dagger.internal.codegen.model.BindingKind.OPTIONAL;
+import static dagger.internal.codegen.model.BindingKind.PRODUCTION;
+import static dagger.internal.codegen.model.BindingKind.PROVISION;
+import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static dagger.internal.codegen.xprocessing.XElements.asVariable;
import static dagger.internal.codegen.xprocessing.XTypes.erasedTypeName;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import static dagger.spi.model.BindingKind.ASSISTED_FACTORY;
-import static dagger.spi.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.spi.model.BindingKind.BOUND_INSTANCE;
-import static dagger.spi.model.BindingKind.COMPONENT;
-import static dagger.spi.model.BindingKind.COMPONENT_DEPENDENCY;
-import static dagger.spi.model.BindingKind.COMPONENT_PRODUCTION;
-import static dagger.spi.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.spi.model.BindingKind.DELEGATE;
-import static dagger.spi.model.BindingKind.INJECTION;
-import static dagger.spi.model.BindingKind.MEMBERS_INJECTOR;
-import static dagger.spi.model.BindingKind.OPTIONAL;
-import static dagger.spi.model.BindingKind.PRODUCTION;
-import static dagger.spi.model.BindingKind.PROVISION;
-import static dagger.spi.model.BindingKind.SUBCOMPONENT_CREATOR;
import androidx.room.compiler.processing.XConstructorElement;
import androidx.room.compiler.processing.XConstructorType;
@@ -53,7 +52,6 @@
import androidx.room.compiler.processing.XExecutableParameterElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XMethodType;
-import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import androidx.room.compiler.processing.XVariableElement;
@@ -69,12 +67,11 @@
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.ProductionBinding.ProductionKind;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DaggerType;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import java.util.Optional;
import java.util.function.BiFunction;
import javax.inject.Inject;
@@ -88,7 +85,6 @@
@Inject
BindingFactory(
- XProcessingEnv processingEnv,
KeyFactory keyFactory,
DependencyRequestFactory dependencyRequestFactory,
InjectionSiteFactory injectionSiteFactory,
@@ -100,7 +96,7 @@
}
/**
- * Returns an {@link dagger.spi.model.BindingKind#INJECTION} binding.
+ * Returns an {@link dagger.internal.codegen.model.BindingKind#INJECTION} binding.
*
* @param constructorElement the {@code @Inject}-annotated constructor
* @param resolvedType the parameterized type if the constructor is for a generic class and the
@@ -165,12 +161,12 @@
XMethodType factoryMethodType = factoryMethod.asMemberOf(factoryType);
return ProvisionBinding.builder()
.contributionType(ContributionType.UNIQUE)
- .key(Key.builder(DaggerType.from(factoryType)).build())
+ .key(keyFactory.forType(factoryType))
.bindingElement(factory)
.provisionDependencies(
ImmutableSet.of(
DependencyRequest.builder()
- .key(Key.builder(DaggerType.from(factoryMethodType.getReturnType())).build())
+ .key(keyFactory.forType(factoryMethodType.getReturnType()))
.kind(RequestKind.PROVIDER)
.build()))
.kind(ASSISTED_FACTORY)
@@ -178,7 +174,7 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#PROVISION} binding for a
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#PROVISION} binding for a
* {@code @Provides}-annotated method.
*
* @param contributedBy the installed module that declares or inherits the method
@@ -193,12 +189,12 @@
this::providesMethodBinding)
.kind(PROVISION)
.scope(injectionAnnotations.getScope(providesMethod))
- .nullableType(getNullableType(providesMethod))
+ .nullability(Nullability.of(providesMethod))
.build();
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#PRODUCTION} binding for a
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#PRODUCTION} binding for a
* {@code @Produces}-annotated method.
*
* @param contributedBy the installed module that declares or inherits the method
@@ -245,9 +241,9 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#MULTIBOUND_MAP} or {@link
- * dagger.spi.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding contribution
- * bindings.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#MULTIBOUND_MAP} or {@link
+ * dagger.internal.codegen.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding
+ * contribution bindings.
*
* @param key a key that may be satisfied by a multibinding
*/
@@ -291,7 +287,10 @@
multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION));
}
- /** Returns a {@link dagger.spi.model.BindingKind#COMPONENT} binding for the component. */
+ /**
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#COMPONENT} binding for the
+ * component.
+ */
public ProvisionBinding componentBinding(XTypeElement componentDefinitionType) {
checkNotNull(componentDefinitionType);
return ProvisionBinding.builder()
@@ -303,8 +302,8 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#COMPONENT_DEPENDENCY} binding for a component's
- * dependency.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#COMPONENT_DEPENDENCY} binding for a
+ * component's dependency.
*/
public ProvisionBinding componentDependencyBinding(ComponentRequirement dependency) {
checkNotNull(dependency);
@@ -317,9 +316,9 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#COMPONENT_PROVISION} or {@link
- * dagger.spi.model.BindingKind#COMPONENT_PRODUCTION} binding for a method on a component's
- * dependency.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#COMPONENT_PROVISION} or {@link
+ * dagger.internal.codegen.model.BindingKind#COMPONENT_PRODUCTION} binding for a method on a
+ * component's dependency.
*
* @param componentDescriptor the component with the dependency, not the dependency that has the
* method
@@ -338,7 +337,7 @@
builder =
ProvisionBinding.builder()
.key(keyFactory.forComponentMethod(dependencyMethod))
- .nullableType(getNullableType(dependencyMethod))
+ .nullability(Nullability.of(dependencyMethod))
.kind(COMPONENT_PROVISION)
.scope(injectionAnnotations.getScope(dependencyMethod));
}
@@ -349,7 +348,7 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#BOUND_INSTANCE} binding for a
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#BOUND_INSTANCE} binding for a
* {@code @BindsInstance}-annotated builder setter method or factory method parameter.
*/
ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, XElement element) {
@@ -362,14 +361,14 @@
.contributionType(ContributionType.UNIQUE)
.bindingElement(element)
.key(requirement.key().get())
- .nullableType(getNullableType(parameterElement))
+ .nullability(Nullability.of(parameterElement))
.kind(BOUND_INSTANCE)
.build();
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared by a
- * component method that returns a subcomponent builder. Use {{@link
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#SUBCOMPONENT_CREATOR} binding
+ * declared by a component method that returns a subcomponent builder. Use {{@link
* #subcomponentCreatorBinding(ImmutableSet)}} for bindings declared using {@link
* Module#subcomponents()}.
*
@@ -389,8 +388,8 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared using
- * {@link Module#subcomponents()}.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#SUBCOMPONENT_CREATOR} binding
+ * declared using {@link Module#subcomponents()}.
*/
ProvisionBinding subcomponentCreatorBinding(
ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
@@ -403,7 +402,7 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#DELEGATE} binding.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#DELEGATE} binding.
*
* @param delegateDeclaration the {@code @Binds}-annotated declaration
* @param actualBinding the binding that satisfies the {@code @Binds} declaration
@@ -413,7 +412,7 @@
switch (actualBinding.bindingType()) {
case PRODUCTION:
return buildDelegateBinding(
- ProductionBinding.builder().nullableType(actualBinding.nullableType()),
+ ProductionBinding.builder().nullability(actualBinding.nullability()),
delegateDeclaration,
TypeNames.PRODUCER);
@@ -421,7 +420,7 @@
return buildDelegateBinding(
ProvisionBinding.builder()
.scope(injectionAnnotations.getScope(delegateDeclaration.bindingElement().get()))
- .nullableType(actualBinding.nullableType()),
+ .nullability(actualBinding.nullability()),
delegateDeclaration,
TypeNames.PROVIDER);
@@ -431,8 +430,8 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#DELEGATE} binding used when there is no binding
- * that satisfies the {@code @Binds} declaration.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#DELEGATE} binding used when there is
+ * no binding that satisfies the {@code @Binds} declaration.
*/
public ContributionBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) {
return buildDelegateBinding(
@@ -458,7 +457,7 @@
}
/**
- * Returns an {@link dagger.spi.model.BindingKind#OPTIONAL} binding for {@code key}.
+ * Returns an {@link dagger.internal.codegen.model.BindingKind#OPTIONAL} binding for {@code key}.
*
* @param requestKind the kind of request for the optional binding
* @param underlyingKeyBindings the possibly empty set of bindings that exist in the component for
@@ -490,7 +489,7 @@
.build();
}
- /** Returns a {@link dagger.spi.model.BindingKind#MEMBERS_INJECTOR} binding. */
+ /** Returns a {@link dagger.internal.codegen.model.BindingKind#MEMBERS_INJECTOR} binding. */
public ProvisionBinding membersInjectorBinding(
Key key, MembersInjectionBinding membersInjectionBinding) {
return ProvisionBinding.builder()
@@ -504,7 +503,7 @@
}
/**
- * Returns a {@link dagger.spi.model.BindingKind#MEMBERS_INJECTION} binding.
+ * Returns a {@link dagger.internal.codegen.model.BindingKind#MEMBERS_INJECTION} binding.
*
* @param resolvedType if {@code declaredType} is a generic class and {@code resolvedType} is a
* parameterization of that type, the returned binding will be for the resolved type
diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java
index 460c483..8dfe74f 100644
--- a/java/dagger/internal/codegen/binding/BindingGraph.java
+++ b/java/dagger/internal/codegen/binding/BindingGraph.java
@@ -42,15 +42,15 @@
import com.google.common.graph.ImmutableNetwork;
import com.google.common.graph.Traverser;
import dagger.internal.codegen.base.TarjanSCCs;
-import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Edge;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DaggerTypeElement;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -71,7 +71,8 @@
* their bindings.
*/
@AutoValue
- public abstract static class TopLevelBindingGraph extends dagger.spi.model.BindingGraph {
+ public abstract static class TopLevelBindingGraph
+ extends dagger.internal.codegen.model.BindingGraph {
static TopLevelBindingGraph create(
ImmutableNetwork<Node, Edge> network, boolean isFullBindingGraph) {
TopLevelBindingGraph topLevelBindingGraph =
@@ -106,7 +107,8 @@
TopLevelBindingGraph() {}
- // This overrides dagger.spi.model.BindingGraph with a more efficient implementation.
+ // This overrides dagger.internal.codegen.model.BindingGraph with a more efficient
+ // implementation.
@Override
public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
return componentNodes.containsKey(componentPath)
@@ -162,9 +164,10 @@
}
private static ImmutableSet<Binding> frameworkRequestBindingSet(
- ImmutableNetwork<Node, Edge> network, ImmutableSet<dagger.spi.model.Binding> bindings) {
+ ImmutableNetwork<Node, Edge> network,
+ ImmutableSet<dagger.internal.codegen.model.Binding> bindings) {
Set<Binding> frameworkRequestBindings = new HashSet<>();
- for (dagger.spi.model.Binding binding : bindings) {
+ for (dagger.internal.codegen.model.Binding binding : bindings) {
ImmutableList<DependencyEdge> edges =
network.inEdges(binding).stream()
.flatMap(instancesOf(DependencyEdge.class))
diff --git a/java/dagger/internal/codegen/binding/BindingGraphConverter.java b/java/dagger/internal/codegen/binding/BindingGraphConverter.java
index 717e429..5928b8f 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphConverter.java
+++ b/java/dagger/internal/codegen/binding/BindingGraphConverter.java
@@ -20,7 +20,7 @@
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.extension.DaggerGraphs.unreachableNodes;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.spi.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XType;
@@ -37,16 +37,16 @@
import com.google.common.graph.NetworkBuilder;
import dagger.internal.codegen.binding.BindingGraph.TopLevelBindingGraph;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Edge;
-import dagger.spi.model.BindingGraph.MissingBinding;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DaggerExecutableElement;
-import dagger.spi.model.DaggerTypeElement;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.MissingBinding;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerExecutableElement;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
@@ -55,7 +55,7 @@
import java.util.Set;
import javax.inject.Inject;
-/** Converts {@link BindingGraph}s to {@link dagger.spi.model.BindingGraph}s. */
+/** Converts {@link BindingGraph}s to {@link dagger.internal.codegen.model.BindingGraph}s. */
final class BindingGraphConverter {
private final BindingDeclarationFormatter bindingDeclarationFormatter;
@@ -65,8 +65,8 @@
}
/**
- * Creates the external {@link dagger.spi.model.BindingGraph} representing the given internal
- * {@link BindingGraph}.
+ * Creates the external {@link dagger.internal.codegen.model.BindingGraph} representing the given
+ * internal {@link BindingGraph}.
*/
BindingGraph convert(LegacyBindingGraph legacyBindingGraph, boolean isFullBindingGraph) {
MutableNetwork<Node, Edge> network = asNetwork(legacyBindingGraph);
@@ -276,8 +276,8 @@
}
/**
- * Adds a {@link dagger.spi.model.BindingGraph.DependencyEdge} from a node to the binding(s)
- * that satisfy a dependency request.
+ * Adds a {@link dagger.internal.codegen.model.BindingGraph.DependencyEdge} from a node to the
+ * binding(s) that satisfy a dependency request.
*/
private void addDependencyEdges(Node source, DependencyRequest dependencyRequest) {
ResolvedBindings dependencies = resolvedDependencies(source, dependencyRequest);
diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
index fe01431..ba1157d 100644
--- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java
+++ b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
@@ -22,15 +22,15 @@
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName;
+import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.OPTIONAL;
+import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
-import static dagger.spi.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.spi.model.BindingKind.DELEGATE;
-import static dagger.spi.model.BindingKind.INJECTION;
-import static dagger.spi.model.BindingKind.OPTIONAL;
-import static dagger.spi.model.BindingKind.SUBCOMPONENT_CREATOR;
-import static dagger.spi.model.RequestKind.MEMBERS_INJECTION;
import static java.util.function.Predicate.isEqual;
import androidx.room.compiler.processing.XProcessingEnv;
@@ -51,11 +51,11 @@
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XTypeElements;
import dagger.producers.internal.ProductionExecutorModule;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.Scope;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
diff --git a/java/dagger/internal/codegen/binding/BindingNode.java b/java/dagger/internal/codegen/binding/BindingNode.java
index aa0f6cb..7856420 100644
--- a/java/dagger/internal/codegen/binding/BindingNode.java
+++ b/java/dagger/internal/codegen/binding/BindingNode.java
@@ -24,25 +24,25 @@
import com.google.common.collect.Iterables;
import dagger.BindsOptionalOf;
import dagger.Module;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerElement;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
import dagger.multibindings.Multibinds;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DaggerElement;
-import dagger.spi.model.DaggerTypeElement;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.Scope;
import java.util.Optional;
/**
- * An implementation of {@link dagger.spi.model.Binding} that also exposes {@link
+ * An implementation of {@link dagger.internal.codegen.model.Binding} that also exposes {@link
* BindingDeclaration}s associated with the binding.
*/
-// TODO(dpb): Consider a supertype of dagger.spi.model.Binding that
+// TODO(dpb): Consider a supertype of dagger.internal.codegen.model.Binding that
// dagger.internal.codegen.binding.Binding
// could also implement.
@AutoValue
-public abstract class BindingNode implements dagger.spi.model.Binding {
+public abstract class BindingNode implements dagger.internal.codegen.model.Binding {
public static BindingNode create(
ComponentPath component,
Binding delegate,
diff --git a/java/dagger/internal/codegen/binding/BindingRequest.java b/java/dagger/internal/codegen/binding/BindingRequest.java
index 58e72bc..b560aa0 100644
--- a/java/dagger/internal/codegen/binding/BindingRequest.java
+++ b/java/dagger/internal/codegen/binding/BindingRequest.java
@@ -21,9 +21,9 @@
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import java.util.Optional;
/**
diff --git a/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java b/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
index 30f3588..077f454 100644
--- a/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
+++ b/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
@@ -18,8 +18,8 @@
import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.spi.model.DaggerExecutableElement;
+import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.internal.codegen.model.DaggerExecutableElement;
/** An implementation of {@link ChildFactoryMethodEdge}. */
public final class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
index a89de70..0bc2209 100644
--- a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
@@ -40,7 +40,7 @@
import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import dagger.internal.codegen.base.ComponentCreatorKind;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.List;
/**
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
index 096554f..a105608 100644
--- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
@@ -46,9 +46,9 @@
import dagger.Subcomponent;
import dagger.internal.codegen.base.ComponentAnnotation;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XAnnotations;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Scope;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java b/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
index 77e9dbf..1d09450 100644
--- a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
+++ b/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
@@ -43,8 +43,8 @@
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XTypeElements;
-import dagger.spi.model.Scope;
import java.util.Optional;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/binding/ComponentNodeImpl.java b/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
index 5dbf633..984b7ed 100644
--- a/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
+++ b/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
@@ -20,10 +20,10 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableSet;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Scope;
/** An implementation of {@link ComponentNode} that also exposes the {@link ComponentDescriptor}. */
@AutoValue
diff --git a/java/dagger/internal/codegen/binding/ComponentRequirement.java b/java/dagger/internal/codegen/binding/ComponentRequirement.java
index 4b985fe..df10577 100644
--- a/java/dagger/internal/codegen/binding/ComponentRequirement.java
+++ b/java/dagger/internal/codegen/binding/ComponentRequirement.java
@@ -32,9 +32,9 @@
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XTypeElements;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.Key;
import java.util.Optional;
/** A type that a component needs an instance of. */
@@ -191,8 +191,7 @@
public static ComponentRequirement forBoundInstance(ContributionBinding binding) {
checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE));
- return forBoundInstance(
- binding.key(), binding.nullableType().isPresent(), binding.bindingElement().get());
+ return forBoundInstance(binding.key(), binding.isNullable(), binding.bindingElement().get());
}
static ComponentRequirement forBoundInstance(
diff --git a/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java b/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
index 57da79a..a56a549 100644
--- a/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
+++ b/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
@@ -20,12 +20,9 @@
import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations;
import static dagger.internal.codegen.base.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
import static dagger.internal.codegen.xprocessing.XElements.hasAnyAnnotation;
-import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XElement;
-import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
@@ -51,17 +48,6 @@
return hasAnyAnnotation(element, subcomponentCreatorAnnotations());
}
- /** Returns the first type that specifies this' nullability, or empty if none. */
- public static Optional<XAnnotation> getNullableAnnotation(XElement element) {
- return element.getAllAnnotations().stream()
- .filter(annotation -> getClassName(annotation).simpleName().contentEquals("Nullable"))
- .findFirst();
- }
-
- public static Optional<XType> getNullableType(XElement element) {
- return getNullableAnnotation(element).map(XAnnotation::getType);
- }
-
/** Returns the enclosed types annotated with the given annotation. */
public static ImmutableSet<XTypeElement> enclosedAnnotatedTypes(
XTypeElement typeElement, ImmutableSet<ClassName> annotations) {
diff --git a/java/dagger/internal/codegen/binding/ContributionBinding.java b/java/dagger/internal/codegen/binding/ContributionBinding.java
index 796e073..f8950a3 100644
--- a/java/dagger/internal/codegen/binding/ContributionBinding.java
+++ b/java/dagger/internal/codegen/binding/ContributionBinding.java
@@ -29,11 +29,11 @@
import dagger.internal.codegen.base.ContributionType.HasContributionType;
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
import java.util.Optional;
/**
@@ -43,8 +43,8 @@
@CheckReturnValue
public abstract class ContributionBinding extends Binding implements HasContributionType {
- /** Returns the type that specifies this' nullability, absent if not nullable. */
- public abstract Optional<XType> nullableType();
+ /** Returns the nullability of this binding. */
+ public abstract Nullability nullability();
// Note: We're using DaggerAnnotation instead of XAnnotation for its equals/hashcode
public abstract Optional<DaggerAnnotation> mapKey();
@@ -64,7 +64,7 @@
@Override
public final boolean isNullable() {
- return nullableType().isPresent();
+ return nullability().isNullable();
}
/**
@@ -134,7 +134,7 @@
public abstract B key(Key key);
@CanIgnoreReturnValue
- public abstract B nullableType(Optional<XType> nullableType);
+ public abstract B nullability(Nullability nullability);
@CanIgnoreReturnValue
abstract B mapKey(Optional<DaggerAnnotation> mapKey);
diff --git a/java/dagger/internal/codegen/binding/DelegateDeclaration.java b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
index 835fff4..76d4287 100644
--- a/java/dagger/internal/codegen/binding/DelegateDeclaration.java
+++ b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
@@ -30,8 +30,8 @@
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.ContributionType.HasContributionType;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.Optional;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java b/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
index d3bde9d..098049c 100644
--- a/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
+++ b/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
@@ -17,9 +17,9 @@
package dagger.internal.codegen.binding;
import dagger.internal.codegen.base.ElementFormatter;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.DaggerElement;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.DaggerElement;
+import dagger.internal.codegen.model.DependencyRequest;
/** An implementation of {@link DependencyEdge}. */
final class DependencyEdgeImpl implements DependencyEdge {
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
index 154cb13..a96eeda 100644
--- a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
+++ b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
@@ -24,14 +24,13 @@
import static dagger.internal.codegen.base.RequestKinds.frameworkClassName;
import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
+import static dagger.internal.codegen.model.RequestKind.FUTURE;
+import static dagger.internal.codegen.model.RequestKind.INSTANCE;
+import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
+import static dagger.internal.codegen.model.RequestKind.PRODUCER;
+import static dagger.internal.codegen.model.RequestKind.PROVIDER;
import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
import static dagger.internal.codegen.xprocessing.XTypes.unwrapType;
-import static dagger.spi.model.RequestKind.FUTURE;
-import static dagger.spi.model.RequestKind.INSTANCE;
-import static dagger.spi.model.RequestKind.MEMBERS_INJECTION;
-import static dagger.spi.model.RequestKind.PRODUCER;
-import static dagger.spi.model.RequestKind.PROVIDER;
import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XElement;
@@ -44,10 +43,10 @@
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DaggerElement;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.DaggerElement;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
@@ -214,7 +213,8 @@
.kind(kind)
.key(key.get())
.isNullable(
- allowsNull(getRequestKind(OptionalType.from(requestKey).valueType()), Optional.empty()))
+ requestKindImplicitlyAllowsNull(
+ getRequestKind(OptionalType.from(requestKey).valueType())))
.build();
}
@@ -225,17 +225,21 @@
.kind(requestKind)
.key(keyFactory.forQualifiedType(qualifier, extractKeyType(type)))
.requestElement(DaggerElement.from(requestElement))
- .isNullable(allowsNull(requestKind, getNullableType(requestElement)))
+ .isNullable(allowsNull(requestKind, Nullability.of(requestElement)))
.build();
}
/**
* Returns {@code true} if a given request element allows null values. {@link
- * RequestKind#INSTANCE} requests must be annotated with {@code @Nullable} in order to allow null
- * values. All other request kinds implicitly allow null values because they are are wrapped
- * inside {@link Provider}, {@link Lazy}, etc.
+ * RequestKind#INSTANCE} requests must be nullable in order to allow null values. All other
+ * request kinds implicitly allow null values because they are are wrapped inside {@link
+ * Provider}, {@link Lazy}, etc.
*/
- private boolean allowsNull(RequestKind kind, Optional<XType> nullableType) {
- return nullableType.isPresent() || !kind.equals(INSTANCE);
+ private boolean allowsNull(RequestKind kind, Nullability nullability) {
+ return nullability.isNullable() || requestKindImplicitlyAllowsNull(kind);
+ }
+
+ private boolean requestKindImplicitlyAllowsNull(RequestKind kind) {
+ return !kind.equals(INSTANCE);
}
}
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
index ae04838..80591b1 100644
--- a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
+++ b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
@@ -27,10 +27,10 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import dagger.Provides;
import dagger.internal.codegen.base.Formatter;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.xprocessing.XTypes;
import dagger.producers.Produces;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DependencyRequest;
import java.util.Optional;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/binding/DependencyVariableNamer.java b/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
index f75c97c..6fa3f39 100644
--- a/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
+++ b/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
@@ -21,7 +21,7 @@
import com.google.common.base.Ascii;
import com.google.common.base.CaseFormat;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/java/dagger/internal/codegen/binding/FrameworkField.java b/java/dagger/internal/codegen/binding/FrameworkField.java
index e1ea064..b1d1cf9 100644
--- a/java/dagger/internal/codegen/binding/FrameworkField.java
+++ b/java/dagger/internal/codegen/binding/FrameworkField.java
@@ -20,8 +20,8 @@
import static androidx.room.compiler.processing.XElementKt.isMethod;
import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
import static androidx.room.compiler.processing.XElementKt.isTypeElement;
+import static dagger.internal.codegen.model.BindingKind.MEMBERS_INJECTOR;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static dagger.spi.model.BindingKind.MEMBERS_INJECTOR;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XType;
diff --git a/java/dagger/internal/codegen/binding/FrameworkType.java b/java/dagger/internal/codegen/binding/FrameworkType.java
index afe6389..ce3b149 100644
--- a/java/dagger/internal/codegen/binding/FrameworkType.java
+++ b/java/dagger/internal/codegen/binding/FrameworkType.java
@@ -27,8 +27,8 @@
import dagger.internal.codegen.base.RequestKinds;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.RequestKind;
import java.util.Optional;
/** One of the core types initialized as fields in a generated component. */
diff --git a/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java b/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
index 776fac6..0e17d96 100644
--- a/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
+++ b/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
@@ -18,8 +18,8 @@
import static dagger.internal.codegen.binding.BindingType.PRODUCTION;
+import dagger.internal.codegen.model.RequestKind;
import dagger.producers.Producer;
-import dagger.spi.model.RequestKind;
import javax.inject.Provider;
/**
diff --git a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
index ceb5024..45fea0a 100644
--- a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
+++ b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
@@ -24,7 +24,7 @@
import dagger.Provides;
import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.Key;
import java.util.Optional;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/binding/InjectionAnnotations.java b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
index eacdd9a..a8adb15 100644
--- a/java/dagger/internal/codegen/binding/InjectionAnnotations.java
+++ b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
@@ -48,8 +48,8 @@
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.Scope;
import java.util.Optional;
import java.util.stream.Stream;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/binding/KeyFactory.java b/java/dagger/internal/codegen/binding/KeyFactory.java
index e7daf60..d7f78c1 100644
--- a/java/dagger/internal/codegen/binding/KeyFactory.java
+++ b/java/dagger/internal/codegen/binding/KeyFactory.java
@@ -48,14 +48,14 @@
import dagger.internal.codegen.base.RequestKinds;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DaggerExecutableElement;
+import dagger.internal.codegen.model.DaggerType;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.xprocessing.XAnnotations;
import dagger.multibindings.Multibinds;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DaggerExecutableElement;
-import dagger.spi.model.DaggerType;
-import dagger.spi.model.DaggerTypeElement;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
@@ -105,11 +105,11 @@
XMethodElement subcomponentCreatorMethod, XType declaredContainer) {
checkArgument(isDeclared(declaredContainer));
XMethodType resolvedMethod = subcomponentCreatorMethod.asMemberOf(declaredContainer);
- return Key.builder(DaggerType.from(resolvedMethod.getReturnType())).build();
+ return forType(resolvedMethod.getReturnType());
}
public Key forSubcomponentCreator(XType creatorType) {
- return Key.builder(DaggerType.from(creatorType)).build();
+ return forType(creatorType);
}
public Key forProvidesMethod(XMethodElement method, XTypeElement contributingModule) {
@@ -234,16 +234,15 @@
}
public Key forInjectConstructorWithResolvedType(XType type) {
- return Key.builder(DaggerType.from(type)).build();
+ return forType(type);
}
- // TODO(ronshapiro): Remove these conveniences which are simple wrappers around Key.Builder
Key forType(XType type) {
return Key.builder(DaggerType.from(type)).build();
}
public Key forMembersInjectedType(XType type) {
- return Key.builder(DaggerType.from(type)).build();
+ return forType(type);
}
Key forQualifiedType(Optional<XAnnotation> qualifier, XType type) {
@@ -265,9 +264,7 @@
}
public Key forProductionComponentMonitor() {
- return Key.builder(
- DaggerType.from(processingEnv.requireType(TypeNames.PRODUCTION_COMPONENT_MONITOR)))
- .build();
+ return forType(processingEnv.requireType(TypeNames.PRODUCTION_COMPONENT_MONITOR));
}
/**
diff --git a/java/dagger/internal/codegen/binding/KeyVariableNamer.java b/java/dagger/internal/codegen/binding/KeyVariableNamer.java
index cb6a910..c9a1a4b 100644
--- a/java/dagger/internal/codegen/binding/KeyVariableNamer.java
+++ b/java/dagger/internal/codegen/binding/KeyVariableNamer.java
@@ -28,8 +28,8 @@
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import java.util.Iterator;
/**
@@ -50,7 +50,8 @@
public static String name(Key key) {
if (key.multibindingContributionIdentifier().isPresent()) {
- return key.multibindingContributionIdentifier().get().bindingMethod();
+ return getSimpleName(
+ key.multibindingContributionIdentifier().get().bindingMethod().xprocessing());
}
StringBuilder builder = new StringBuilder();
diff --git a/java/dagger/internal/codegen/binding/LegacyBindingGraph.java b/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
index 2f8d39a..b38697e 100644
--- a/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
+++ b/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
@@ -22,8 +22,8 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import java.util.Collection;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/binding/MapKeys.java b/java/dagger/internal/codegen/binding/MapKeys.java
index 8f8da18..c156dbb 100644
--- a/java/dagger/internal/codegen/binding/MapKeys.java
+++ b/java/dagger/internal/codegen/binding/MapKeys.java
@@ -46,8 +46,8 @@
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.MapKeyAccessibility;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DaggerAnnotation;
import dagger.internal.codegen.xprocessing.XElements;
-import dagger.spi.model.DaggerAnnotation;
import java.util.NoSuchElementException;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
index 302d6e2..b546f6a 100644
--- a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
+++ b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
@@ -30,9 +30,9 @@
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import java.util.Optional;
/** Represents the full members injection of a particular type. */
diff --git a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
index 962618b..e98abcc 100644
--- a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
+++ b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
@@ -22,6 +22,7 @@
import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
+import static java.util.stream.Collectors.joining;
import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XExecutableElement;
@@ -32,6 +33,7 @@
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import androidx.room.compiler.processing.XVariableElement;
+import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.Formatter;
import dagger.internal.codegen.xprocessing.XAnnotations;
import dagger.internal.codegen.xprocessing.XTypes;
@@ -42,6 +44,9 @@
/** Formats the signature of an {@link XExecutableElement} suitable for use in error messages. */
public final class MethodSignatureFormatter extends Formatter<XExecutableElement> {
+ private static final ClassName JET_BRAINS_NOT_NULL =
+ ClassName.get("org.jetbrains.annotations", "NotNull");
+
private final InjectionAnnotations injectionAnnotations;
@Inject
@@ -103,14 +108,13 @@
StringBuilder builder = new StringBuilder();
List<XAnnotation> annotations = method.getAllAnnotations();
if (!annotations.isEmpty()) {
- Iterator<XAnnotation> annotationIterator = annotations.iterator();
- for (int i = 0; annotationIterator.hasNext(); i++) {
- if (i > 0) {
- builder.append(' ');
- }
- builder.append(formatAnnotation(annotationIterator.next()));
- }
- builder.append(' ');
+ builder.append(
+ annotations.stream()
+ // Filter out @NotNull annotations added by KAPT to make error messages consistent
+ .filter(annotation -> !annotation.getClassName().equals(JET_BRAINS_NOT_NULL))
+ .map(MethodSignatureFormatter::formatAnnotation)
+ .collect(joining(" ")))
+ .append(" ");
}
if (getSimpleName(method).contentEquals("<init>")) {
builder.append(container.getQualifiedName());
diff --git a/java/dagger/internal/codegen/binding/ModuleDescriptor.java b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
index 6543639..62cfa7f 100644
--- a/java/dagger/internal/codegen/binding/ModuleDescriptor.java
+++ b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
@@ -26,7 +26,6 @@
import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.xprocessing.XElements.asMethod;
-import static dagger.internal.codegen.xprocessing.XElements.getMethodDescriptor;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
@@ -47,8 +46,8 @@
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleKind;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XTypeElements;
-import dagger.spi.model.Key;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
@@ -182,7 +181,7 @@
XTypeElement companionModule, ImmutableSet.Builder<ContributionBinding> bindings) {
ImmutableSet<String> bindingElementDescriptors =
bindings.build().stream()
- .map(binding -> getMethodDescriptor(asMethod(binding.bindingElement().get())))
+ .map(binding -> asMethod(binding.bindingElement().get()).getJvmDescriptor())
.collect(toImmutableSet());
XTypeElements.getAllMethods(companionModule).stream()
@@ -193,7 +192,7 @@
// @JvmStatic by comparing descriptors. Contributing bindings are the only valid bindings
// a companion module can declare. See: https://youtrack.jetbrains.com/issue/KT-35104
// TODO(danysantiago): Checks qualifiers too.
- .filter(method -> !bindingElementDescriptors.contains(getMethodDescriptor(method)))
+ .filter(method -> !bindingElementDescriptors.contains(method.getJvmDescriptor()))
.forEach(
method -> {
if (method.hasAnnotation(TypeNames.PROVIDES)) {
diff --git a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
index 746feaf..54672fc 100644
--- a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
@@ -29,8 +29,8 @@
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Key;
import dagger.multibindings.Multibinds;
-import dagger.spi.model.Key;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
diff --git a/java/dagger/internal/codegen/binding/Nullability.java b/java/dagger/internal/codegen/binding/Nullability.java
new file mode 100644
index 0000000..190227b
--- /dev/null
+++ b/java/dagger/internal/codegen/binding/Nullability.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.binding;
+
+import static androidx.room.compiler.processing.XElementKt.isMethod;
+import static androidx.room.compiler.processing.XElementKt.isVariableElement;
+import static dagger.internal.codegen.xprocessing.XAnnotations.getClassName;
+import static dagger.internal.codegen.xprocessing.XElements.asMethod;
+import static dagger.internal.codegen.xprocessing.XElements.asVariable;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XNullability;
+import androidx.room.compiler.processing.XType;
+import com.google.auto.value.AutoValue;
+import java.util.Optional;
+
+/**
+ * Contains information about the nullability of an element.
+ *
+ * <p>Note that an element can be nullable if either:
+ *
+ * <ul>
+ * <li>The element is annotated with {@code Nullable} or
+ * <li>the associated kotlin type is nullable (i.e. {@code T?} types in Kotlin source).
+ * </ul>
+ */
+@AutoValue
+public abstract class Nullability {
+ /** A constant that can represent any non-null element. */
+ public static final Nullability NOT_NULLABLE = new AutoValue_Nullability(false, Optional.empty());
+
+ public static Nullability of(XElement element) {
+ Optional<XAnnotation> nullableAnnotation = getNullableAnnotation(element);
+ boolean isNullable = isKotlinTypeNullable(element) || nullableAnnotation.isPresent();
+ return isNullable ? new AutoValue_Nullability(isNullable, nullableAnnotation) : NOT_NULLABLE;
+ }
+
+ private static boolean isKotlinTypeNullable(XElement element) {
+ if (isMethod(element)) {
+ return isKotlinTypeNullable(asMethod(element).getReturnType());
+ } else if (isVariableElement(element)) {
+ return isKotlinTypeNullable(asVariable(element).getType());
+ } else {
+ return false;
+ }
+ }
+
+ private static boolean isKotlinTypeNullable(XType type) {
+ return type.getNullability() == XNullability.NULLABLE;
+ }
+
+ /** Returns the first type that specifies this' nullability, or empty if none. */
+ private static Optional<XAnnotation> getNullableAnnotation(XElement element) {
+ return element.getAllAnnotations().stream()
+ .filter(annotation -> getClassName(annotation).simpleName().contentEquals("Nullable"))
+ .findFirst();
+ }
+
+ public abstract boolean isNullable();
+
+ public abstract Optional<XAnnotation> nullableAnnotation();
+
+ Nullability() {}
+}
diff --git a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
index d708c0a..60d56bb 100644
--- a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
+++ b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
@@ -24,7 +24,7 @@
import com.google.auto.value.extension.memoized.Memoized;
import dagger.BindsOptionalOf;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.Key;
import java.util.Optional;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/binding/ProductionBinding.java b/java/dagger/internal/codegen/binding/ProductionBinding.java
index 8f49abc..0bcf8e7 100644
--- a/java/dagger/internal/codegen/binding/ProductionBinding.java
+++ b/java/dagger/internal/codegen/binding/ProductionBinding.java
@@ -29,8 +29,8 @@
import com.google.errorprone.annotations.CheckReturnValue;
import dagger.internal.codegen.base.ContributionType;
import dagger.internal.codegen.base.SetType;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import java.util.Optional;
import java.util.stream.Stream;
@@ -111,6 +111,7 @@
public static Builder builder() {
return new AutoValue_ProductionBinding.Builder()
+ .nullability(Nullability.NOT_NULLABLE)
.explicitDependencies(ImmutableList.<DependencyRequest>of())
.thrownTypes(ImmutableList.<XType>of());
}
diff --git a/java/dagger/internal/codegen/binding/ProvisionBinding.java b/java/dagger/internal/codegen/binding/ProvisionBinding.java
index ad61677..caf5904 100644
--- a/java/dagger/internal/codegen/binding/ProvisionBinding.java
+++ b/java/dagger/internal/codegen/binding/ProvisionBinding.java
@@ -17,8 +17,8 @@
package dagger.internal.codegen.binding;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.spi.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.spi.model.BindingKind.PROVISION;
+import static dagger.internal.codegen.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.internal.codegen.model.BindingKind.PROVISION;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
@@ -28,10 +28,10 @@
import com.google.errorprone.annotations.CheckReturnValue;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
import java.util.Optional;
/** A value object representing the mechanism by which a {@link Key} can be provided. */
@@ -82,6 +82,7 @@
public static Builder builder() {
return new AutoValue_ProvisionBinding.Builder()
+ .nullability(Nullability.NOT_NULLABLE)
.provisionDependencies(ImmutableSet.of())
.injectionSites(ImmutableSortedSet.of());
}
@@ -95,7 +96,7 @@
public boolean shouldCheckForNull(CompilerOptions compilerOptions) {
return KINDS_TO_CHECK_FOR_NULL.contains(kind())
&& !contributedPrimitiveType().isPresent()
- && !nullableType().isPresent()
+ && !isNullable()
&& compilerOptions.doCheckForNulls();
}
diff --git a/java/dagger/internal/codegen/binding/ResolvedBindings.java b/java/dagger/internal/codegen/binding/ResolvedBindings.java
index 2e7eb68..8a35442 100644
--- a/java/dagger/internal/codegen/binding/ResolvedBindings.java
+++ b/java/dagger/internal/codegen/binding/ResolvedBindings.java
@@ -27,7 +27,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.Key;
/**
* The collection of bindings that have been resolved for a key. For valid graphs, contains exactly
diff --git a/java/dagger/internal/codegen/binding/SourceFiles.java b/java/dagger/internal/codegen/binding/SourceFiles.java
index d108e75..19d316f 100644
--- a/java/dagger/internal/codegen/binding/SourceFiles.java
+++ b/java/dagger/internal/codegen/binding/SourceFiles.java
@@ -34,14 +34,14 @@
import static dagger.internal.codegen.javapoet.TypeNames.SET_FACTORY;
import static dagger.internal.codegen.javapoet.TypeNames.SET_OF_PRODUCED_PRODUCER;
import static dagger.internal.codegen.javapoet.TypeNames.SET_PRODUCER;
+import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_SET;
import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
import static dagger.internal.codegen.xprocessing.XElements.asTypeElement;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import static dagger.internal.codegen.xprocessing.XTypeElements.typeVariableNames;
-import static dagger.spi.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.spi.model.BindingKind.INJECTION;
-import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
import static javax.lang.model.SourceVersion.isName;
import androidx.room.compiler.processing.XExecutableElement;
@@ -62,8 +62,8 @@
import dagger.internal.codegen.base.MapType;
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.RequestKind;
import javax.inject.Inject;
import javax.lang.model.SourceVersion;
diff --git a/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java b/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
index 5998b98..6790717 100644
--- a/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
+++ b/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
@@ -23,8 +23,8 @@
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
-import dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge;
-import dagger.spi.model.DaggerTypeElement;
+import dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge;
+import dagger.internal.codegen.model.DaggerTypeElement;
/** An implementation of {@link SubcomponentCreatorBindingEdge}. */
public final class SubcomponentCreatorBindingEdgeImpl implements SubcomponentCreatorBindingEdge {
diff --git a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
index dfc2905..5df2dd9 100644
--- a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
+++ b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
@@ -27,7 +27,7 @@
import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.base.DaggerSuperficialValidation;
import dagger.internal.codegen.base.ModuleAnnotation;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.Key;
import java.util.Optional;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BUILD b/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
index 85c6451..e8a005e 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
@@ -33,9 +33,9 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/xprocessing",
- "//java/dagger/spi",
"//third_party/java/auto:common",
"//third_party/java/auto:value",
"//third_party/java/error_prone:annotations",
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
index 7e32bec..c826c3d 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
@@ -20,9 +20,9 @@
import dagger.Module;
import dagger.Provides;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.model.BindingGraphPlugin;
import dagger.internal.codegen.validation.Validation;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.BindingGraphPlugin;
/** Binds the set of {@link BindingGraphPlugin}s used to implement Dagger validation. */
@Module
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/CompositeBindingGraphPlugin.java b/java/dagger/internal/codegen/bindinggraphvalidation/CompositeBindingGraphPlugin.java
index a723800..9d958d7 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/CompositeBindingGraphPlugin.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/CompositeBindingGraphPlugin.java
@@ -27,16 +27,16 @@
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
+import dagger.internal.codegen.model.BindingGraphPlugin;
+import dagger.internal.codegen.model.DaggerProcessingEnv;
+import dagger.internal.codegen.model.DiagnosticReporter;
import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.MaybeBinding;
-import dagger.spi.model.BindingGraphPlugin;
-import dagger.spi.model.DaggerProcessingEnv;
-import dagger.spi.model.DiagnosticReporter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
index f42f7ad..a2c53c4 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
@@ -44,16 +44,16 @@
import dagger.internal.codegen.base.OptionalType;
import dagger.internal.codegen.binding.DependencyRequestFormatter;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.DiagnosticReporter;
-import dagger.spi.model.RequestKind;
import java.util.List;
import java.util.Optional;
import java.util.Set;
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
index 4bdff69..ea4d738 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
@@ -21,12 +21,12 @@
import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.MaybeBinding;
-import dagger.spi.model.DiagnosticReporter;
-import dagger.spi.model.Key;
import javax.inject.Inject;
/**
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
index 2b11f17..5f4dcfc 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
@@ -16,19 +16,19 @@
package dagger.internal.codegen.bindinggraphvalidation;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
-import static dagger.spi.model.BindingKind.INJECTION;
-import static dagger.spi.model.BindingKind.MEMBERS_INJECTION;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.MEMBERS_INJECTION;
import static java.util.Comparator.comparing;
import static javax.tools.Diagnostic.Kind.ERROR;
import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
@@ -37,30 +37,32 @@
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
-import com.google.common.collect.Sets;
import dagger.internal.codegen.base.Formatter;
import dagger.internal.codegen.binding.BindingDeclaration;
import dagger.internal.codegen.binding.BindingDeclarationFormatter;
import dagger.internal.codegen.binding.BindingNode;
import dagger.internal.codegen.binding.MultibindingDeclaration;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DaggerElement;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Key.MultibindingContributionIdentifier;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DaggerElement;
-import dagger.spi.model.DaggerTypeElement;
-import dagger.spi.model.DiagnosticReporter;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.xprocessing.XTypes;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import javax.inject.Inject;
-import javax.tools.Diagnostic.Kind;
+import javax.tools.Diagnostic;
/** Reports errors for conflicting bindings with the same key. */
final class DuplicateBindingsValidator extends ValidationBindingGraphPlugin {
@@ -89,13 +91,13 @@
// same two modules, then fixing the error in one subcomponent will uncover the second
// subcomponent to fix.
// TODO(ronshapiro): Explore ways to address such underreporting without overreporting.
- Set<ImmutableSet<BindingElement>> reportedDuplicateBindingSets = new HashSet<>();
+ Set<ImmutableSet<BindingWithoutComponent>> reportedDuplicateBindingSets = new HashSet<>();
duplicateBindingSets(bindingGraph)
.forEach(
duplicateBindings -> {
// Only report each set of duplicate bindings once, ignoring the installed component.
if (reportedDuplicateBindingSets.add(duplicateBindings.keySet())) {
- reportDuplicateBindings(duplicateBindings, bindingGraph, diagnosticReporter);
+ reportErrors(duplicateBindings, bindingGraph, diagnosticReporter);
}
});
}
@@ -107,20 +109,31 @@
* descendant component because it depends on local multibindings or optional bindings. Hence each
* "set" is represented as a multimap from binding element (ignoring component path) to binding.
*/
- private ImmutableSet<ImmutableSetMultimap<BindingElement, Binding>> duplicateBindingSets(
+ private ImmutableSet<ImmutableSetMultimap<BindingWithoutComponent, Binding>> duplicateBindingSets(
BindingGraph bindingGraph) {
return groupBindingsByKey(bindingGraph).stream()
.flatMap(bindings -> mutuallyVisibleSubsets(bindings).stream())
- .map(BindingElement::index)
+ .map(BindingWithoutComponent::index)
.filter(duplicates -> duplicates.keySet().size() > 1)
.collect(toImmutableSet());
}
- private static ImmutableSet<ImmutableSet<Binding>> groupBindingsByKey(BindingGraph bindingGraph) {
+ private ImmutableSet<ImmutableSet<Binding>> groupBindingsByKey(BindingGraph bindingGraph) {
return valueSetsForEachKey(
bindingGraph.bindings().stream()
.filter(binding -> !binding.kind().equals(MEMBERS_INJECTION))
- .collect(toImmutableSetMultimap(Binding::key, binding -> binding)));
+ .collect(
+ toImmutableSetMultimap(
+ binding ->
+ // If the "ignoreProvisionKeyWildcards" flag is enabled then ignore the
+ // variance in the key types here so that Foo<Bar> and Foo<? extends Bar>
+ // get grouped into the same set (i.e. as duplicates).
+ KeyWithTypeEquivalence.forKey(
+ binding.key(),
+ compilerOptions.ignoreProvisionKeyWildcards()
+ ? XTypes.equivalenceIgnoringVariance()
+ : XTypes.equivalence()),
+ binding -> binding)));
}
/**
@@ -147,8 +160,8 @@
return valueSetsForEachKey(mutuallyVisibleBindings.build());
}
- private void reportDuplicateBindings(
- ImmutableSetMultimap<BindingElement, Binding> duplicateBindings,
+ private void reportErrors(
+ ImmutableSetMultimap<BindingWithoutComponent, Binding> duplicateBindings,
BindingGraph bindingGraph,
DiagnosticReporter diagnosticReporter) {
if (explicitBindingConfictsWithInject(duplicateBindings.keySet())) {
@@ -158,49 +171,33 @@
.ifPresent(
diagnosticKind ->
reportExplicitBindingConflictsWithInject(
- duplicateBindings,
+ duplicateBindings.values(),
diagnosticReporter,
diagnosticKind,
bindingGraph.rootComponentNode()));
return;
}
- ImmutableSet<Binding> bindings = ImmutableSet.copyOf(duplicateBindings.values());
- Binding oneBinding = bindings.asList().get(0);
- String message = bindings.stream().anyMatch(binding -> binding.kind().isMultibinding())
- ? incompatibleBindingsMessage(oneBinding, bindings, bindingGraph)
- : duplicateBindingMessage(oneBinding, bindings, bindingGraph);
- if (compilerOptions.experimentalDaggerErrorMessages()) {
- diagnosticReporter.reportComponent(
- ERROR,
- bindingGraph.rootComponentNode(),
- message);
- } else {
- diagnosticReporter.reportBinding(
- ERROR,
- oneBinding,
- message);
- }
+
+ reportDuplicateBindings(duplicateBindings.values(), bindingGraph, diagnosticReporter);
}
/**
* Returns {@code true} if the bindings contain one {@code @Inject} binding and one that isn't.
*/
private static boolean explicitBindingConfictsWithInject(
- ImmutableSet<BindingElement> duplicateBindings) {
+ ImmutableSet<BindingWithoutComponent> duplicateBindings) {
ImmutableMultiset<BindingKind> bindingKinds =
- Multimaps.index(duplicateBindings, BindingElement::bindingKind).keys();
+ Multimaps.index(duplicateBindings, BindingWithoutComponent::bindingKind).keys();
return bindingKinds.count(INJECTION) == 1 && bindingKinds.size() == 2;
}
private void reportExplicitBindingConflictsWithInject(
- ImmutableSetMultimap<BindingElement, Binding> duplicateBindings,
+ ImmutableCollection<Binding> duplicateBindings,
DiagnosticReporter diagnosticReporter,
- Kind diagnosticKind,
+ Diagnostic.Kind diagnosticKind,
ComponentNode rootComponent) {
- Binding injectBinding =
- rootmostBindingWithKind(k -> k.equals(INJECTION), duplicateBindings.values());
- Binding explicitBinding =
- rootmostBindingWithKind(k -> !k.equals(INJECTION), duplicateBindings.values());
+ Binding injectBinding = rootmostBindingWithKind(k -> k.equals(INJECTION), duplicateBindings);
+ Binding explicitBinding = rootmostBindingWithKind(k -> !k.equals(INJECTION), duplicateBindings);
StringBuilder message =
new StringBuilder()
.append(explicitBinding.key())
@@ -226,47 +223,45 @@
binding.componentPath());
}
- private String duplicateBindingMessage(
- Binding oneBinding, ImmutableSet<Binding> duplicateBindings, BindingGraph graph) {
- StringBuilder message =
- new StringBuilder().append(oneBinding.key()).append(" is bound multiple times:");
- formatDeclarations(message, 1, declarations(graph, duplicateBindings));
- if (compilerOptions.experimentalDaggerErrorMessages()) {
- message.append(String.format("\n%sin component: [%s]", INDENT, oneBinding.componentPath()));
- }
- return message.toString();
- }
-
- private String incompatibleBindingsMessage(
- Binding oneBinding, ImmutableSet<Binding> duplicateBindings, BindingGraph graph) {
- Key key = oneBinding.key();
- ImmutableSet<dagger.spi.model.Binding> multibindings =
+ private void reportDuplicateBindings(
+ ImmutableCollection<Binding> duplicateBindings,
+ BindingGraph graph,
+ DiagnosticReporter diagnosticReporter) {
+ StringBuilder message = new StringBuilder();
+ Binding oneBinding = duplicateBindings.asList().get(0);
+ ImmutableSet<Binding> multibindings =
duplicateBindings.stream()
.filter(binding -> binding.kind().isMultibinding())
.collect(toImmutableSet());
- verify(
- multibindings.size() == 1, "expected only one multibinding for %s: %s", key, multibindings);
- StringBuilder message = new StringBuilder();
- java.util.Formatter messageFormatter = new java.util.Formatter(message);
- messageFormatter.format("%s has incompatible bindings or declarations:\n", key);
- message.append(INDENT);
- dagger.spi.model.Binding multibinding = getOnlyElement(multibindings);
- messageFormatter.format("%s bindings and declarations:", multibindingTypeString(multibinding));
- formatDeclarations(message, 2, declarations(graph, multibindings));
+ if (multibindings.isEmpty()) {
+ message.append(oneBinding.key()).append(" is bound multiple times:");
+ formatDeclarations(message, 2, declarations(graph, duplicateBindings));
+ } else {
+ Binding oneMultibinding = multibindings.asList().get(0);
+ message.append(oneMultibinding.key()).append(" has incompatible bindings or declarations:\n");
+ message
+ .append(INDENT)
+ .append(multibindingTypeString(oneMultibinding))
+ .append(" bindings and declarations:");
+ formatDeclarations(message, 2, declarations(graph, multibindings));
+ ImmutableSet<BindingDeclaration> uniqueBindingDeclarations =
+ duplicateBindings.stream()
+ .filter(binding -> !binding.kind().isMultibinding())
+ .flatMap(binding -> declarations(graph, binding).stream())
+ .filter(declaration -> !(declaration instanceof MultibindingDeclaration))
+ .collect(toImmutableSet());
+ if (!uniqueBindingDeclarations.isEmpty()) {
+ message.append('\n').append(INDENT).append("Unique bindings and declarations:");
+ formatDeclarations(message, 2, uniqueBindingDeclarations);
+ }
+ }
- Set<dagger.spi.model.Binding> uniqueBindings =
- Sets.filter(duplicateBindings, binding -> !binding.equals(multibinding));
- message.append('\n').append(INDENT).append("Unique bindings and declarations:");
- formatDeclarations(
- message,
- 2,
- Sets.filter(
- declarations(graph, uniqueBindings),
- declaration -> !(declaration instanceof MultibindingDeclaration)));
if (compilerOptions.experimentalDaggerErrorMessages()) {
message.append(String.format("\n%sin component: [%s]", INDENT, oneBinding.componentPath()));
+ diagnosticReporter.reportComponent(ERROR, graph.rootComponentNode(), message.toString());
+ } else {
+ diagnosticReporter.reportBinding(ERROR, oneBinding, message.toString());
}
- return message.toString();
}
private void formatDeclarations(
@@ -278,7 +273,7 @@
}
private ImmutableSet<BindingDeclaration> declarations(
- BindingGraph graph, Set<dagger.spi.model.Binding> bindings) {
+ BindingGraph graph, ImmutableCollection<Binding> bindings) {
return bindings.stream()
.flatMap(binding -> declarations(graph, binding).stream())
.distinct()
@@ -286,8 +281,7 @@
.collect(toImmutableSet());
}
- private ImmutableSet<BindingDeclaration> declarations(
- BindingGraph graph, dagger.spi.model.Binding binding) {
+ private ImmutableSet<BindingDeclaration> declarations(BindingGraph graph, Binding binding) {
ImmutableSet.Builder<BindingDeclaration> declarations = ImmutableSet.builder();
BindingNode bindingNode = (BindingNode) binding;
bindingNode.associatedDeclarations().forEach(declarations::add);
@@ -301,7 +295,7 @@
return declarations.build();
}
- private String multibindingTypeString(dagger.spi.model.Binding multibinding) {
+ private String multibindingTypeString(Binding multibinding) {
switch (multibinding.kind()) {
case MULTIBOUND_MAP:
return "Map";
@@ -327,23 +321,45 @@
/** The identifying information about a binding, excluding its {@link Binding#componentPath()}. */
@AutoValue
- abstract static class BindingElement {
+ abstract static class BindingWithoutComponent {
abstract BindingKind bindingKind();
+ abstract Key bindingKey();
+
abstract Optional<XElement> bindingElement();
abstract Optional<XTypeElement> contributingModule();
- static ImmutableSetMultimap<BindingElement, Binding> index(Set<Binding> bindings) {
- return bindings.stream().collect(toImmutableSetMultimap(BindingElement::forBinding, b -> b));
+ static ImmutableSetMultimap<BindingWithoutComponent, Binding> index(Set<Binding> bindings) {
+ return bindings.stream()
+ .collect(toImmutableSetMultimap(BindingWithoutComponent::forBinding, b -> b));
}
- private static BindingElement forBinding(Binding binding) {
- return new AutoValue_DuplicateBindingsValidator_BindingElement(
+ private static BindingWithoutComponent forBinding(Binding binding) {
+ return new AutoValue_DuplicateBindingsValidator_BindingWithoutComponent(
binding.kind(),
+ binding.key(),
binding.bindingElement().map(DaggerElement::xprocessing),
binding.contributingModule().map(DaggerTypeElement::xprocessing));
}
}
+
+
+ /** The identifying information about a key with the given type equivalence. */
+ @AutoValue
+ abstract static class KeyWithTypeEquivalence {
+ abstract Optional<DaggerAnnotation> qualifier();
+
+ abstract Equivalence.Wrapper<XType> wrappedType();
+
+ abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
+
+ private static KeyWithTypeEquivalence forKey(Key key, Equivalence<XType> typeEquivalence) {
+ return new AutoValue_DuplicateBindingsValidator_KeyWithTypeEquivalence(
+ key.qualifier(),
+ typeEquivalence.wrap(key.type().xprocessing()),
+ key.multibindingContributionIdentifier());
+ }
+ }
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
index 3643870..c1108a8 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
@@ -18,9 +18,9 @@
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.base.Scopes.getReadableSource;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
import static dagger.internal.codegen.xprocessing.XElements.asExecutable;
import static dagger.internal.codegen.xprocessing.XElements.closestEnclosingTypeElement;
-import static dagger.spi.model.BindingKind.INJECTION;
import static java.util.stream.Collectors.joining;
import static javax.tools.Diagnostic.Kind.ERROR;
@@ -29,12 +29,12 @@
import dagger.internal.codegen.base.Scopes;
import dagger.internal.codegen.binding.MethodSignatureFormatter;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.DiagnosticReporter;
import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.DiagnosticReporter;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
@@ -69,9 +69,9 @@
public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
DiagnosticMessageGenerator diagnosticMessageGenerator =
diagnosticMessageGeneratorFactory.create(bindingGraph);
- ImmutableSetMultimap.Builder<ComponentNode, dagger.spi.model.Binding> incompatibleBindings =
- ImmutableSetMultimap.builder();
- for (dagger.spi.model.Binding binding : bindingGraph.bindings()) {
+ ImmutableSetMultimap.Builder<ComponentNode, dagger.internal.codegen.model.Binding>
+ incompatibleBindings = ImmutableSetMultimap.builder();
+ for (dagger.internal.codegen.model.Binding binding : bindingGraph.bindings()) {
binding
.scope()
.filter(scope -> !scope.isReusable())
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
index ae153a0..2151295 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
@@ -16,15 +16,15 @@
package dagger.internal.codegen.bindinggraphvalidation;
-import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.DiagnosticReporter;
import dagger.internal.codegen.validation.InjectValidator;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
import dagger.internal.codegen.validation.ValidationReport;
import dagger.internal.codegen.validation.ValidationReport.Item;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.DiagnosticReporter;
import javax.inject.Inject;
/** Validates bindings from {@code @Inject}-annotated constructors. */
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
index 0698bef..87e8771 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
@@ -21,7 +21,7 @@
import static dagger.internal.codegen.base.Formatter.INDENT;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
-import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
import static javax.tools.Diagnostic.Kind.ERROR;
import com.google.common.collect.ImmutableList;
@@ -37,11 +37,11 @@
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.DiagnosticReporter;
-import dagger.spi.model.Key;
import java.util.Set;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
index 724a980..774ee5d 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
@@ -16,34 +16,49 @@
package dagger.internal.codegen.bindinggraphvalidation;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.Iterables.getOnlyElement;
import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
import static dagger.internal.codegen.base.Keys.isValidMembersInjectionKey;
import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding;
import static dagger.internal.codegen.binding.DependencyRequestFormatter.DOUBLE_INDENT;
import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
import static dagger.internal.codegen.xprocessing.XTypes.isWildcard;
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.room.compiler.processing.XType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.WildcardTypeName;
import dagger.internal.codegen.binding.DependencyRequestFormatter;
import dagger.internal.codegen.binding.InjectBindingRegistry;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.MissingBinding;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.validation.DiagnosticMessageGenerator;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Edge;
-import dagger.spi.model.BindingGraph.MissingBinding;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DiagnosticReporter;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.xprocessing.XTypes;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
import java.util.List;
-import java.util.stream.Collectors;
+import java.util.Optional;
import javax.inject.Inject;
/** Reports errors for missing bindings. */
@@ -97,11 +112,32 @@
BindingGraph prunedGraph,
BindingGraph fullGraph,
DiagnosticReporter diagnosticReporter) {
+ ImmutableSet<Binding> wildcardAlternatives =
+ getSimilarTypeBindings(fullGraph, missingBinding.key());
+ String wildcardTypeErrorMessage = "";
+ if (!wildcardAlternatives.isEmpty()) {
+ wildcardTypeErrorMessage =
+ String.format(
+ "\nFound similar bindings:\n %s",
+ String.join(
+ "\n ",
+ wildcardAlternatives.stream()
+ .map(
+ binding -> binding.key().type() + " in [" + binding.componentPath() + "]")
+ .collect(toImmutableSet())))
+ + "\n(In Kotlin source, a type like 'Set<Foo>' may"
+ + " be translated as 'Set<? extends Foo>'. To avoid this implicit"
+ + " conversion you can add '@JvmSuppressWildcards' on the associated type"
+ + " argument, e.g. 'Set<@JvmSuppressWildcards Foo>'.)";
+ }
+
List<ComponentPath> alternativeComponents =
- fullGraph.bindings(missingBinding.key()).stream()
- .map(Binding::componentPath)
- .distinct()
- .collect(Collectors.toList());
+ wildcardAlternatives.isEmpty()
+ ? fullGraph.bindings(missingBinding.key()).stream()
+ .map(Binding::componentPath)
+ .distinct()
+ .collect(toImmutableList())
+ : ImmutableList.of();
// Print component name for each binding along the dependency path if the missing binding
// exists in a different component than expected
if (alternativeComponents.isEmpty()) {
@@ -113,6 +149,8 @@
ERROR,
fullGraph.componentNode(missingBinding.componentPath()).get(),
missingBindingErrorMessage(missingBinding, fullGraph)
+ + wildcardTypeErrorMessage
+ + "\n\nMissing binding usage:"
+ diagnosticMessageGeneratorFactory.create(prunedGraph).getMessage(missingBinding));
} else {
diagnosticReporter.reportComponent(
@@ -123,6 +161,45 @@
}
}
+ private static ImmutableSet<Binding> getSimilarTypeBindings(
+ BindingGraph graph, Key missingBindingKey) {
+ XType missingBindingType = missingBindingKey.type().xprocessing();
+ Optional<DaggerAnnotation> missingBindingQualifier = missingBindingKey.qualifier();
+ ImmutableList<TypeName> flatMissingBindingType = flattenBindingType(missingBindingType);
+ if (flatMissingBindingType.size() <= 1) {
+ return ImmutableSet.of();
+ }
+ return graph.bindings().stream()
+ .filter(
+ binding ->
+ binding.key().qualifier().equals(missingBindingQualifier)
+ && isSimilarType(binding.key().type().xprocessing(), flatMissingBindingType))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Unwraps a parameterized type to a list of TypeNames. e.g. {@code Map<Foo, List<Bar>>} to {@code
+ * [Map, Foo, List, Bar]}.
+ */
+ private static ImmutableList<TypeName> flattenBindingType(XType type) {
+ return ImmutableList.copyOf(new TypeDfsIterator(type));
+ }
+
+ private static boolean isSimilarType(XType type, List<TypeName> flatTypeNames) {
+ return Iterators.elementsEqual(flatTypeNames.iterator(), new TypeDfsIterator(type));
+ }
+
+ private static TypeName getBound(WildcardTypeName wildcardType) {
+ // Note: The javapoet API returns a list to be extensible, but there's currently no way to get
+ // multiple bounds, and it's not really clear what we should do if there were multiple bounds
+ // so we just assume there's only one for now. The javapoet API also guarantees that there will
+ // always be at least one upper bound -- in the absence of an explicit upper bound the Object
+ // type is used (e.g. Set<?> has an upper bound of Object).
+ return !wildcardType.lowerBounds.isEmpty()
+ ? getOnlyElement(wildcardType.lowerBounds)
+ : getOnlyElement(wildcardType.upperBounds);
+ }
+
private String missingBindingErrorMessage(MissingBinding missingBinding, BindingGraph graph) {
Key key = missingBinding.key();
StringBuilder errorMessage = new StringBuilder();
@@ -167,7 +244,7 @@
getComponentFromDependencyEdge(dependencyTrace.get(0), graph, false);
boolean hasSameComponentName = false;
for (ComponentPath component : alternativeComponentPath) {
- message.append("\nA binding for ").append(missingBinding.key()).append(" exists in ");
+ message.append("\nNote: A binding for ").append(missingBinding.key()).append(" exists in ");
String currentComponentName = component.currentComponent().className().canonicalName();
if (currentComponentName.contentEquals(missingComponentName)) {
hasSameComponentName = true;
@@ -214,11 +291,11 @@
if (source instanceof ComponentNode) {
return canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind());
}
- if (source instanceof dagger.spi.model.Binding) {
- return ((dagger.spi.model.Binding) source).isProduction();
+ if (source instanceof Binding) {
+ return ((Binding) source).isProduction();
}
throw new IllegalArgumentException(
- "expected a dagger.spi.model.Binding or ComponentNode: " + source);
+ "expected a dagger.internal.codegen.model.Binding or ComponentNode: " + source);
}
private boolean typeHasInjectionSites(Key key) {
@@ -239,4 +316,52 @@
private Node source(Edge edge, BindingGraph graph) {
return graph.network().incidentNodes(edge).source();
}
+
+ /**
+ * An iterator over a list of TypeNames produced by flattening a parameterized type. e.g. {@code
+ * Map<Foo, List<Bar>>} to {@code [Map, Foo, List, Bar]}.
+ *
+ * <p>The iterator returns the bound when encounters a wildcard type.
+ */
+ private static class TypeDfsIterator implements Iterator<TypeName> {
+ final Deque<XType> stack = new ArrayDeque<>();
+
+ TypeDfsIterator(XType root) {
+ stack.push(root);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return !stack.isEmpty();
+ }
+
+ @Override
+ public TypeName next() {
+ XType next = stack.pop();
+ if (isDeclared(next)) {
+ if (XTypes.isRawParameterizedType(next)) {
+ XType obj = getProcessingEnv(next).requireType(TypeName.OBJECT);
+ for (int i = 0; i < next.getTypeElement().getType().getTypeArguments().size(); i++) {
+ stack.push(obj);
+ }
+ } else {
+ for (XType arg : Lists.reverse(next.getTypeArguments())) {
+ stack.push(arg);
+ }
+ }
+ }
+ return getBaseTypeName(next);
+ }
+
+ private static TypeName getBaseTypeName(XType type) {
+ if (isDeclared(type)) {
+ return type.getRawType().getTypeName();
+ }
+ TypeName typeName = type.getTypeName();
+ if (typeName instanceof WildcardTypeName) {
+ return getBound((WildcardTypeName) typeName);
+ }
+ return typeName;
+ }
+ }
}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
index bbc026e..e586cc6 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
@@ -24,11 +24,11 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.DiagnosticReporter;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.DiagnosticReporter;
import javax.inject.Inject;
/**
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
index 7ad0e9f..d8305df 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
@@ -22,12 +22,12 @@
import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
import static javax.tools.Diagnostic.Kind.ERROR;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.DiagnosticReporter;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.DiagnosticReporter;
import java.util.stream.Stream;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java
index 6b7de40..f767da8 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/SetMultibindingValidator.java
@@ -16,8 +16,8 @@
package dagger.internal.codegen.bindinggraphvalidation;
-import static dagger.spi.model.BindingKind.DELEGATE;
-import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_SET;
import static javax.tools.Diagnostic.Kind.ERROR;
import com.google.common.base.Joiner;
@@ -25,11 +25,11 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.DiagnosticReporter;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.DiagnosticReporter;
-import dagger.spi.model.Key;
import javax.inject.Inject;
/** Validates that there are not multiple set binding contributions to the same binding. */
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
index 1ecff19..0196d03 100644
--- a/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
+++ b/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
@@ -31,11 +31,11 @@
import com.google.common.collect.Sets.SetView;
import dagger.internal.codegen.base.Util;
import dagger.internal.codegen.binding.ComponentNodeImpl;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.DiagnosticReporter;
import dagger.internal.codegen.validation.ValidationBindingGraphPlugin;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.DiagnosticReporter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
diff --git a/java/dagger/internal/codegen/compileroption/CompilerOptions.java b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
index 18e133e..42599e0 100644
--- a/java/dagger/internal/codegen/compileroption/CompilerOptions.java
+++ b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
@@ -150,4 +150,13 @@
* eventually become the default and enforced.
*/
public abstract boolean strictMultibindingValidation();
+
+ /**
+ * Returns {@code true} if we should ignore the variance in provision key types.
+ *
+ * <p>By enabling this flag, Dagger will no longer allow provisioning multiple keys that only
+ * differ by the key type's variance (a.k.a. wildcards). As an example, the provisioning a binding
+ * for {@code Foo<? extends Bar>} and {@code Foo<Bar>} would result in a duplicate binding error.
+ */
+ public abstract boolean ignoreProvisionKeyWildcards();
}
diff --git a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
index a516b1a..356d55b 100644
--- a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
+++ b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
@@ -31,6 +31,7 @@
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.GENERATED_CLASS_EXTENDS_COMPONENT;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
+import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PROVISION_KEY_WILDCARDS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
@@ -213,6 +214,11 @@
}
@Override
+ public boolean ignoreProvisionKeyWildcards() {
+ return isEnabled(IGNORE_PROVISION_KEY_WILDCARDS);
+ }
+
+ @Override
public boolean strictMultibindingValidation() {
return isEnabled(STRICT_MULTIBINDING_VALIDATION);
}
@@ -353,6 +359,8 @@
GENERATED_CLASS_EXTENDS_COMPONENT,
+ IGNORE_PROVISION_KEY_WILDCARDS,
+
VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED)
;
diff --git a/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java b/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
index 4d130b6..6e77835 100644
--- a/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
+++ b/java/dagger/internal/codegen/javac/JavacPluginCompilerOptions.java
@@ -140,4 +140,9 @@
public boolean generatedClassExtendsComponent() {
return false;
}
+
+ @Override
+ public boolean ignoreProvisionKeyWildcards() {
+ return false;
+ }
}
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
index 0056a72..b27ae91 100644
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
+++ b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen.kotlin;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static dagger.internal.codegen.xprocessing.XElements.getFieldDescriptor;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import androidx.room.compiler.processing.XAnnotation;
@@ -32,7 +31,6 @@
import com.google.common.collect.ImmutableSet;
import dagger.internal.codegen.extension.DaggerCollectors;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.xprocessing.XElements;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -74,7 +72,7 @@
@Memoized
ImmutableMap<String, XMethodElement> methodDescriptors() {
return typeElement().getDeclaredMethods().stream()
- .collect(toImmutableMap(XElements::getMethodDescriptor, Function.identity()));
+ .collect(toImmutableMap(XMethodElement::getJvmDescriptor, Function.identity()));
}
/** Gets the synthetic method for annotations of a given field element. */
@@ -133,7 +131,7 @@
}
private PropertyMetadata findProperty(XFieldElement field) {
- String fieldDescriptor = getFieldDescriptor(field);
+ String fieldDescriptor = field.getJvmDescriptor();
if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) {
return classMetadata().propertiesByFieldSignature().get(fieldDescriptor);
} else {
diff --git a/java/dagger/internal/codegen/kythe/BUILD b/java/dagger/internal/codegen/kythe/BUILD
index b1025f3..9b2e63b 100644
--- a/java/dagger/internal/codegen/kythe/BUILD
+++ b/java/dagger/internal/codegen/kythe/BUILD
@@ -32,9 +32,9 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/xprocessing",
- "//java/dagger/spi",
"//third_party/java/auto:service",
"//third_party/java/error_prone:annotations",
"//third_party/java/guava/collect",
diff --git a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
index 52ff652..3280b4f 100644
--- a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
+++ b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
@@ -44,12 +44,12 @@
import dagger.internal.codegen.binding.ModuleDescriptor;
import dagger.internal.codegen.javac.JavacPluginModule;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.validation.InjectBindingRegistryModule;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Edge;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.DependencyRequest;
import java.util.Optional;
import java.util.logging.Logger;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/model/BUILD b/java/dagger/internal/codegen/model/BUILD
new file mode 100644
index 0000000..e6c944b
--- /dev/null
+++ b/java/dagger/internal/codegen/model/BUILD
@@ -0,0 +1,41 @@
+# Copyright (C) 2023 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Dagger's core APIs exposed for plugins
+
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//:src"])
+
+java_library(
+ name = "model",
+ srcs = glob(["*.java"]),
+ plugins = ["//java/dagger/internal/codegen/bootstrap"],
+ deps = [
+ "//java/dagger:core",
+ "//java/dagger/internal/codegen/extension",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//java/dagger/producers",
+ "//java/dagger/spi",
+ "//third_party/java/auto:common",
+ "//third_party/java/auto:value",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/graph",
+ "//third_party/java/javapoet",
+ "//third_party/java/jsr330_inject",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
+ ],
+)
diff --git a/java/dagger/internal/codegen/model/Binding.java b/java/dagger/internal/codegen/model/Binding.java
new file mode 100644
index 0000000..f5bf66c
--- /dev/null
+++ b/java/dagger/internal/codegen/model/Binding.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
+import java.util.Optional;
+
+/**
+ * The association between a {@link Key} and the way in which instances of the key are provided.
+ * Includes any {@linkplain DependencyRequest dependencies} that are needed in order to provide the
+ * instances.
+ *
+ * <p>If a binding is owned by more than one component, there is one {@code Binding} for every
+ * owning component.
+ */
+public interface Binding extends MaybeBinding {
+ @Override
+ ComponentPath componentPath();
+
+ /** @deprecated This always returns {@code Optional.of(this)}. */
+ @Override
+ @Deprecated
+ default Optional<Binding> binding() {
+ return Optional.of(this);
+ }
+ /**
+ * The dependencies of this binding. The order of the dependencies corresponds to the order in
+ * which they will be injected when the binding is requested.
+ */
+ ImmutableSet<DependencyRequest> dependencies();
+
+ /**
+ * The {@link DaggerElement} that declares this binding. Absent for
+ * {@linkplain BindingKind binding kinds} that are not always declared by exactly one element.
+ *
+ * <p>For example, consider {@link BindingKind#MULTIBOUND_SET}. A component with many
+ * {@code @IntoSet} bindings for the same key will have a synthetic binding that depends on all
+ * contributions, but with no identifiying binding element. A {@code @Multibinds} method will also
+ * contribute a synthetic binding, but since multiple {@code @Multibinds} methods can coexist in
+ * the same component (and contribute to one single binding), it has no binding element.
+ */
+ Optional<DaggerElement> bindingElement();
+
+ /**
+ * The {@link DaggerTypeElement} of the module which contributes this binding. Absent for bindings
+ * that have no {@link #bindingElement() binding element}.
+ */
+ Optional<DaggerTypeElement> contributingModule();
+
+ /**
+ * Returns {@code true} if using this binding requires an instance of the {@link
+ * #contributingModule()}.
+ */
+ boolean requiresModuleInstance();
+
+ /** The scope of this binding if it has one. */
+ Optional<Scope> scope();
+
+ /**
+ * Returns {@code true} if this binding may provide {@code null} instead of an instance of {@link
+ * #key()}. Nullable bindings cannot be requested from {@linkplain DependencyRequest#isNullable()
+ * non-nullable dependency requests}.
+ */
+ boolean isNullable();
+
+ /** Returns {@code true} if this is a production binding, e.g. an {@code @Produces} method. */
+ boolean isProduction();
+
+ /** The kind of binding this instance represents. */
+ BindingKind kind();
+
+}
diff --git a/java/dagger/internal/codegen/model/BindingGraph.java b/java/dagger/internal/codegen/model/BindingGraph.java
new file mode 100644
index 0000000..9d8b39e
--- /dev/null
+++ b/java/dagger/internal/codegen/model/BindingGraph.java
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static com.google.common.collect.Sets.intersection;
+import static com.google.common.graph.Graphs.inducedSubgraph;
+import static com.google.common.graph.Graphs.reachableNodes;
+import static com.google.common.graph.Graphs.transpose;
+import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import dagger.Module;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * A graph of bindings, dependency requests, and components.
+ *
+ * <p>A {@link BindingGraph} represents one of the following:
+ *
+ * <ul>
+ * <li>an entire component hierarchy rooted at a {@link dagger.Component} or {@link
+ * dagger.producers.ProductionComponent}
+ * <li>a partial component hierarchy rooted at a {@link dagger.Subcomponent} or {@link
+ * dagger.producers.ProductionSubcomponent} (only when the value of {@code
+ * -Adagger.fullBindingGraphValidation} is not {@code NONE})
+ * <li>the bindings installed by a {@link Module} or {@link dagger.producers.ProducerModule},
+ * including all subcomponents generated by {@link Module#subcomponents()} ()} and {@link
+ * dagger.producers.ProducerModule#subcomponents()} ()}
+ * </ul>
+ *
+ * In the case of a {@link BindingGraph} representing a module, the root {@link ComponentNode} will
+ * actually represent the module type. The graph will also be a {@linkplain #isFullBindingGraph()
+ * full binding graph}, which means it will contain all bindings in all modules, as well as nodes
+ * for their dependencies. Otherwise it will contain only bindings that are reachable from at least
+ * one {@linkplain #entryPointEdges() entry point}.
+ *
+ * <h3>Nodes</h3>
+ *
+ * <p>There is a <b>{@link Binding}</b> for each owned binding in the graph. If a binding is owned
+ * by more than one component, there is one binding object for that binding for every owning
+ * component.
+ *
+ * <p>There is a <b>{@linkplain ComponentNode component node}</b> (without a binding) for each
+ * component in the graph.
+ *
+ * <h3>Edges</h3>
+ *
+ * <p>There is a <b>{@linkplain DependencyEdge dependency edge}</b> for each dependency request in
+ * the graph. Its target node is the binding for the binding that satisfies the request. For entry
+ * point dependency requests, the source node is the component node for the component for which it
+ * is an entry point. For other dependency requests, the source node is the binding for the binding
+ * that contains the request.
+ *
+ * <p>There is a <b>subcomponent edge</b> for each parent-child component relationship in the graph.
+ * The target node is the component node for the child component. For subcomponents defined by a
+ * {@linkplain SubcomponentCreatorBindingEdge subcomponent creator binding} (either a method on the
+ * component or a set of {@code @Module.subcomponents} annotation values), the source node is the
+ * binding for the {@code @Subcomponent.Builder} type. For subcomponents defined by {@linkplain
+ * ChildFactoryMethodEdge subcomponent factory methods}, the source node is the component node for
+ * the parent.
+ *
+ * <p><b>Note that this API is experimental and will change.</b>
+ */
+public abstract class BindingGraph {
+ /** Returns the graph in its {@link Network} representation. */
+ public abstract ImmutableNetwork<Node, Edge> network();
+
+ @Override
+ public String toString() {
+ return network().toString();
+ }
+
+ /**
+ * Returns {@code true} if this graph was constructed from a module for full binding graph
+ * validation.
+ *
+ * @deprecated use {@link #isFullBindingGraph()} to tell if this is a full binding graph, or
+ * {@link ComponentNode#isRealComponent() rootComponentNode().isRealComponent()} to tell if
+ * the root component node is really a component or derived from a module. Dagger can generate
+ * full binding graphs for components and subcomponents as well as modules.
+ */
+ @Deprecated
+ public boolean isModuleBindingGraph() {
+ return !rootComponentNode().isRealComponent();
+ }
+
+ /**
+ * Returns {@code true} if this is a full binding graph, which contains all bindings installed in
+ * the component, or {@code false} if it is a reachable binding graph, which contains only
+ * bindings that are reachable from at least one {@linkplain #entryPointEdges() entry point}.
+ *
+ * @see <a href="https://dagger.dev/compiler-options#full-binding-graph-validation">Full binding
+ * graph validation</a>
+ */
+ public abstract boolean isFullBindingGraph();
+
+ /**
+ * Returns {@code true} if the {@link #rootComponentNode()} is a subcomponent. This occurs in
+ * when {@code -Adagger.fullBindingGraphValidation} is used in a compilation with a subcomponent.
+ *
+ * @deprecated use {@link ComponentNode#isSubcomponent() rootComponentNode().isSubcomponent()}
+ * instead
+ */
+ @Deprecated
+ public boolean isPartialBindingGraph() {
+ return rootComponentNode().isSubcomponent();
+ }
+
+ /** Returns the bindings. */
+ public ImmutableSet<Binding> bindings() {
+ return nodes(Binding.class);
+ }
+
+ /** Returns the bindings for a key. */
+ public ImmutableSet<Binding> bindings(Key key) {
+ return nodes(Binding.class).stream()
+ .filter(binding -> binding.key().equals(key))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the nodes that represent missing bindings. */
+ public ImmutableSet<MissingBinding> missingBindings() {
+ return nodes(MissingBinding.class);
+ }
+
+ /** Returns the component nodes. */
+ public ImmutableSet<ComponentNode> componentNodes() {
+ return nodes(ComponentNode.class);
+ }
+
+ /** Returns the component node for a component. */
+ public Optional<ComponentNode> componentNode(ComponentPath component) {
+ return componentNodes().stream()
+ .filter(node -> node.componentPath().equals(component))
+ .findFirst();
+ }
+
+ /** Returns the component nodes for a component. */
+ public ImmutableSet<ComponentNode> componentNodes(DaggerTypeElement component) {
+ return componentNodes().stream()
+ .filter(node -> node.componentPath().currentComponent().equals(component))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the component node for the root component. */
+ public ComponentNode rootComponentNode() {
+ return componentNodes().stream()
+ .filter(node -> node.componentPath().atRoot())
+ .findFirst()
+ .get();
+ }
+
+ /** Returns the dependency edges. */
+ public ImmutableSet<DependencyEdge> dependencyEdges() {
+ return dependencyEdgeStream().collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the dependency edges for the dependencies of a binding. For valid graphs, each {@link
+ * DependencyRequest} will map to a single {@link DependencyEdge}. When conflicting bindings exist
+ * for a key, the multimap will have several edges for that {@link DependencyRequest}. Graphs that
+ * have no binding for a key will have an edge whose {@linkplain EndpointPair#target() target
+ * node} is a {@link MissingBinding}.
+ */
+ public ImmutableSetMultimap<DependencyRequest, DependencyEdge> dependencyEdges(
+ Binding binding) {
+ return dependencyEdgeStream(binding)
+ .collect(toImmutableSetMultimap(DependencyEdge::dependencyRequest, edge -> edge));
+ }
+
+ /** Returns the dependency edges for a dependency request. */
+ public ImmutableSet<DependencyEdge> dependencyEdges(DependencyRequest dependencyRequest) {
+ return dependencyEdgeStream()
+ .filter(edge -> edge.dependencyRequest().equals(dependencyRequest))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the dependency edges for the entry points of a given {@code component}. Each edge's
+ * source node is that component's component node.
+ */
+ public ImmutableSet<DependencyEdge> entryPointEdges(ComponentPath component) {
+ return dependencyEdgeStream(componentNode(component).get()).collect(toImmutableSet());
+ }
+
+ private Stream<DependencyEdge> dependencyEdgeStream(Node node) {
+ return network().outEdges(node).stream().flatMap(instancesOf(DependencyEdge.class));
+ }
+
+ /**
+ * Returns the dependency edges for all entry points for all components and subcomponents. Each
+ * edge's source node is a component node.
+ */
+ public ImmutableSet<DependencyEdge> entryPointEdges() {
+ return entryPointEdgeStream().collect(toImmutableSet());
+ }
+
+ /** Returns the binding or missing binding nodes that directly satisfy entry points. */
+ public ImmutableSet<MaybeBinding> entryPointBindings() {
+ return entryPointEdgeStream()
+ .map(edge -> (MaybeBinding) network().incidentNodes(edge).target())
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the edges for entry points that transitively depend on a binding or missing binding for
+ * a key.
+ */
+ public ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(
+ MaybeBinding binding) {
+ ImmutableNetwork<Node, DependencyEdge> dependencyGraph = dependencyGraph();
+ Network<Node, DependencyEdge> subgraphDependingOnBinding =
+ inducedSubgraph(
+ dependencyGraph, reachableNodes(transpose(dependencyGraph).asGraph(), binding));
+ return intersection(entryPointEdges(), subgraphDependingOnBinding.edges()).immutableCopy();
+ }
+
+ /** Returns the bindings that directly request a given binding as a dependency. */
+ public ImmutableSet<Binding> requestingBindings(MaybeBinding binding) {
+ return network().predecessors(binding).stream()
+ .flatMap(instancesOf(Binding.class))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the bindings that a given binding directly requests as a dependency. Does not include
+ * any {@link MissingBinding}s.
+ *
+ * @see #requestedMaybeMissingBindings(Binding)
+ */
+ public ImmutableSet<Binding> requestedBindings(Binding binding) {
+ return network().successors(binding).stream()
+ .flatMap(instancesOf(Binding.class))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the bindings or missing bindings that a given binding directly requests as a
+ * dependency.
+ *
+ * @see #requestedBindings(Binding)
+ */
+ public ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
+ return network().successors(binding).stream()
+ .flatMap(instancesOf(MaybeBinding.class))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns a subnetwork that contains all nodes but only {@link DependencyEdge}s. */
+ // TODO(dpb): Make public. Cache.
+ private ImmutableNetwork<Node, DependencyEdge> dependencyGraph() {
+ MutableNetwork<Node, DependencyEdge> dependencyGraph =
+ NetworkBuilder.from(network())
+ .expectedNodeCount(network().nodes().size())
+ .expectedEdgeCount((int) dependencyEdgeStream().count())
+ .build();
+ network().nodes().forEach(dependencyGraph::addNode); // include disconnected nodes
+ dependencyEdgeStream()
+ .forEach(
+ edge -> {
+ EndpointPair<Node> endpoints = network().incidentNodes(edge);
+ dependencyGraph.addEdge(endpoints.source(), endpoints.target(), edge);
+ });
+ return ImmutableNetwork.copyOf(dependencyGraph);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private <N extends Node> ImmutableSet<N> nodes(Class<N> clazz) {
+ return (ImmutableSet) nodesByClass().get(clazz);
+ }
+
+ private static final ImmutableSet<Class<? extends Node>> NODE_TYPES =
+ ImmutableSet.of(Binding.class, MissingBinding.class, ComponentNode.class);
+
+ protected ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
+ return network().nodes().stream()
+ .collect(
+ toImmutableSetMultimap(
+ node ->
+ NODE_TYPES.stream().filter(clazz -> clazz.isInstance(node)).findFirst().get(),
+ node -> node));
+ }
+
+ private Stream<DependencyEdge> dependencyEdgeStream() {
+ return network().edges().stream().flatMap(instancesOf(DependencyEdge.class));
+ }
+
+ private Stream<DependencyEdge> entryPointEdgeStream() {
+ return dependencyEdgeStream().filter(DependencyEdge::isEntryPoint);
+ }
+
+ /**
+ * An edge in the binding graph. Either a {@link DependencyEdge}, a {@link
+ * ChildFactoryMethodEdge}, or a {@link SubcomponentCreatorBindingEdge}.
+ */
+ public interface Edge {}
+
+ /**
+ * An edge that represents a dependency on a binding.
+ *
+ * <p>Because one {@link DependencyRequest} may represent a dependency from two bindings (e.g., a
+ * dependency of {@code Foo<String>} and {@code Foo<Number>} may have the same key and request
+ * element), this class does not override {@link #equals(Object)} to use value semantics.
+ *
+ * <p>For entry points, the source node is the {@link ComponentNode} that contains the entry
+ * point. Otherwise the source node is a {@link Binding}.
+ *
+ * <p>For dependencies on missing bindings, the target node is a {@link MissingBinding}. Otherwise
+ * the target node is a {@link Binding}.
+ */
+ public interface DependencyEdge extends Edge {
+ /** The dependency request. */
+ DependencyRequest dependencyRequest();
+
+ /** Returns {@code true} if this edge represents an entry point. */
+ boolean isEntryPoint();
+ }
+
+ /**
+ * An edge that represents a subcomponent factory method linking a parent component to a child
+ * subcomponent.
+ */
+ public interface ChildFactoryMethodEdge extends Edge {
+ /** The subcomponent factory method element. */
+ DaggerExecutableElement factoryMethod();
+ }
+
+ /**
+ * An edge that represents the link between a parent component and a child subcomponent implied by
+ * a subcomponent creator ({@linkplain dagger.Subcomponent.Builder builder} or {@linkplain
+ * dagger.Subcomponent.Factory factory}) binding.
+ *
+ * <p>The {@linkplain com.google.common.graph.EndpointPair#source() source node} of this edge is a
+ * {@link Binding} for the subcomponent creator {@link Key} and the {@linkplain
+ * com.google.common.graph.EndpointPair#target() target node} is a {@link ComponentNode} for the
+ * child subcomponent.
+ */
+ public interface SubcomponentCreatorBindingEdge extends Edge {
+ /**
+ * The modules that {@linkplain Module#subcomponents() declare the subcomponent} that generated
+ * this edge. Empty if the parent component has a subcomponent creator method and there are no
+ * declaring modules.
+ */
+ ImmutableSet<DaggerTypeElement> declaringModules();
+ }
+
+ /** A node in the binding graph. Either a {@link Binding} or a {@link ComponentNode}. */
+ // TODO(dpb): Make all the node/edge types top-level.
+ public interface Node {
+ /** The component this node belongs to. */
+ ComponentPath componentPath();
+ }
+
+ /** A node in the binding graph that is either a {@link Binding} or a {@link MissingBinding}. */
+ public interface MaybeBinding extends Node {
+
+ /** The component that owns the binding, or in which the binding is missing. */
+ @Override
+ ComponentPath componentPath();
+
+ /** The key of the binding, or for which there is no binding. */
+ Key key();
+
+ /** The binding, or empty if missing. */
+ Optional<Binding> binding();
+ }
+
+ /** A node in the binding graph that represents a missing binding for a key in a component. */
+ public abstract static class MissingBinding implements MaybeBinding {
+ /** The component in which the binding is missing. */
+ @Override
+ public abstract ComponentPath componentPath();
+
+ /** The key for which there is no binding. */
+ @Override
+ public abstract Key key();
+
+ /** @deprecated This always returns {@code Optional.empty()}. */
+ @Override
+ @Deprecated
+ public Optional<Binding> binding() {
+ return Optional.empty();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("missing binding for %s in %s", key(), componentPath());
+ }
+ }
+
+ /**
+ * A <b>component node</b> in the graph. Every entry point {@linkplain DependencyEdge dependency
+ * edge}'s source node is a component node for the component containing the entry point.
+ */
+ public interface ComponentNode extends Node {
+
+ /** The component represented by this node. */
+ @Override
+ ComponentPath componentPath();
+
+ /**
+ * Returns {@code true} if the component is a {@code @Subcomponent} or
+ * {@code @ProductionSubcomponent}.
+ */
+ boolean isSubcomponent();
+
+ /**
+ * Returns {@code true} if the component is a real component, or {@code false} if it is a
+ * fictional component based on a module.
+ */
+ boolean isRealComponent();
+
+ /** The entry points on this component. */
+ ImmutableSet<DependencyRequest> entryPoints();
+
+ /** The scopes declared on this component. */
+ ImmutableSet<Scope> scopes();
+ }
+}
diff --git a/java/dagger/internal/codegen/model/BindingGraphPlugin.java b/java/dagger/internal/codegen/model/BindingGraphPlugin.java
new file mode 100644
index 0000000..5cef92e
--- /dev/null
+++ b/java/dagger/internal/codegen/model/BindingGraphPlugin.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+// TODO(bcorso): Move this into dagger/spi?
+/**
+ * A pluggable visitor for {@link BindingGraph}.
+ *
+ * <p>Note: This is still experimental and will change.
+ */
+public interface BindingGraphPlugin {
+ /**
+ * Called once for each valid root binding graph encountered by the Dagger processor. May report
+ * diagnostics using {@code diagnosticReporter}.
+ */
+ void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter);
+
+ /**
+ * Initializes this plugin with a {@link DaggerProcessingEnv}.
+ *
+ * <p>This will be called once per instance of this plugin, before any graph is
+ * {@linkplain #visitGraph(BindingGraph, DiagnosticReporter) visited}.
+ */
+ default void init(DaggerProcessingEnv processingEnv, Map<String, String> options) {}
+
+ /**
+ * Returns the annotation-processing options that this plugin uses to configure behavior.
+ *
+ * @see javax.annotation.processing.Processor#getSupportedOptions()
+ */
+ default Set<String> supportedOptions() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * A distinguishing name of the plugin that will be used in diagnostics printed to the messager.
+ * By default, the {@linkplain Class#getCanonicalName() fully qualified name} of the plugin is
+ * used.
+ */
+ default String pluginName() {
+ return getClass().getCanonicalName();
+ }
+
+ /**
+ * Perform any extra work after the plugin finished all its visiting. This will be called once per
+ * instance of this plugin, after all graphs were {@linkplain #visitGraph(BindingGraph,
+ * DiagnosticReporter) visited}
+ */
+ default void onPluginEnd() {}
+}
diff --git a/java/dagger/internal/codegen/model/BindingKind.java b/java/dagger/internal/codegen/model/BindingKind.java
new file mode 100644
index 0000000..95dc959
--- /dev/null
+++ b/java/dagger/internal/codegen/model/BindingKind.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+/** Represents the different kinds of {@link Binding}s that can exist in a binding graph. */
+public enum BindingKind {
+ /** A binding for an {@link javax.inject.Inject}-annotated constructor. */
+ INJECTION,
+
+ /** A binding for a {@link dagger.Provides}-annotated method. */
+ PROVISION,
+
+ /**
+ * A binding for an {@link javax.inject.Inject}-annotated constructor that contains at least one
+ * {@link dagger.assisted.Assisted}-annotated parameter.
+ */
+ ASSISTED_INJECTION,
+
+ /** A binding for an {@link dagger.assisted.AssistedFactory}-annotated type. */
+ ASSISTED_FACTORY,
+
+ /**
+ * An implicit binding for a {@link dagger.Component}- or {@link
+ * dagger.producers.ProductionComponent}-annotated type.
+ */
+ COMPONENT,
+
+ /**
+ * A binding for a provision method on a component's {@linkplain dagger.Component#dependencies()
+ * dependency}.
+ */
+ COMPONENT_PROVISION,
+
+ /**
+ * A binding for an instance of a component's {@linkplain dagger.Component#dependencies()
+ * dependency}.
+ */
+ COMPONENT_DEPENDENCY,
+
+ /** A binding for a {@link dagger.MembersInjector} of a type. */
+ MEMBERS_INJECTOR,
+
+ /**
+ * A binding for a subcomponent creator (a {@linkplain dagger.Subcomponent.Builder builder} or
+ * {@linkplain dagger.Subcomponent.Factory factory}).
+ *
+ * @since 2.22 (previously named {@code SUBCOMPONENT_BUILDER})
+ */
+ SUBCOMPONENT_CREATOR,
+
+ /** A binding for a {@link dagger.BindsInstance}-annotated builder method. */
+ BOUND_INSTANCE,
+
+ /** A binding for a {@link dagger.producers.Produces}-annotated method. */
+ PRODUCTION,
+
+ /**
+ * A binding for a production method on a production component's {@linkplain
+ * dagger.producers.ProductionComponent#dependencies()} dependency} that returns a {@link
+ * com.google.common.util.concurrent.ListenableFuture} or {@link
+ * com.google.common.util.concurrent.FluentFuture}. Methods on production component dependencies
+ * that don't return a future are considered {@linkplain #COMPONENT_PROVISION component provision
+ * bindings}.
+ */
+ COMPONENT_PRODUCTION,
+
+ /**
+ * A synthetic binding for a multibound set that depends on individual multibinding {@link
+ * #PROVISION} or {@link #PRODUCTION} contributions.
+ */
+ MULTIBOUND_SET,
+
+ /**
+ * A synthetic binding for a multibound map that depends on the individual multibinding {@link
+ * #PROVISION} or {@link #PRODUCTION} contributions.
+ */
+ MULTIBOUND_MAP,
+
+ /**
+ * A synthetic binding for {@code Optional} of a type or a {@link javax.inject.Provider}, {@link
+ * dagger.Lazy}, or {@code Provider} of {@code Lazy} of a type. Generated by a {@link
+ * dagger.BindsOptionalOf} declaration.
+ */
+ OPTIONAL,
+
+ /**
+ * A binding for {@link dagger.Binds}-annotated method that that delegates from requests for one
+ * key to another.
+ */
+ // TODO(dpb,ronshapiro): This name is confusing and could use work. Not all usages of @Binds
+ // bindings are simple delegations and we should have a name that better reflects that
+ DELEGATE,
+
+ /** A binding for a members injection method on a component. */
+ MEMBERS_INJECTION,
+ ;
+
+ /**
+ * Returns {@code true} if this is a kind of multibinding (not a contribution to a multibinding,
+ * but the multibinding itself).
+ */
+ public boolean isMultibinding() {
+ switch (this) {
+ case MULTIBOUND_MAP:
+ case MULTIBOUND_SET:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/model/CompilerEnvironment.java b/java/dagger/internal/codegen/model/CompilerEnvironment.java
new file mode 100644
index 0000000..aa0d01c
--- /dev/null
+++ b/java/dagger/internal/codegen/model/CompilerEnvironment.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+/** Types for the compiler in use for annotation processing. */
+public enum CompilerEnvironment {
+ JAVA,
+ KSP
+}
diff --git a/java/dagger/internal/codegen/model/ComponentPath.java b/java/dagger/internal/codegen/model/ComponentPath.java
new file mode 100644
index 0000000..da7827d
--- /dev/null
+++ b/java/dagger/internal/codegen/model/ComponentPath.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getLast;
+import static java.util.stream.Collectors.joining;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+
+/** A path containing a component and all of its ancestor components. */
+@AutoValue
+public abstract class ComponentPath {
+ /** Returns a new {@link ComponentPath} from {@code components}. */
+ public static ComponentPath create(Iterable<DaggerTypeElement> components) {
+ return new AutoValue_ComponentPath(ImmutableList.copyOf(components));
+ }
+
+ /**
+ * Returns the component types, starting from the {@linkplain #rootComponent() root
+ * component} and ending with the {@linkplain #currentComponent() current component}.
+ */
+ public abstract ImmutableList<DaggerTypeElement> components();
+
+ /**
+ * Returns the root {@link dagger.Component}- or {@link
+ * dagger.producers.ProductionComponent}-annotated type
+ */
+ public final DaggerTypeElement rootComponent() {
+ return components().get(0);
+ }
+
+ /** Returns the component at the end of the path. */
+ @Memoized
+ public DaggerTypeElement currentComponent() {
+ return getLast(components());
+ }
+
+ /**
+ * Returns the parent of the {@linkplain #currentComponent()} current component}.
+ *
+ * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component}
+ */
+ public final DaggerTypeElement parentComponent() {
+ checkState(!atRoot());
+ return components().reverse().get(1);
+ }
+
+ /**
+ * Returns this path's parent path.
+ *
+ * @throws IllegalStateException if the current graph is the {@linkplain #atRoot() root component}
+ */
+ // TODO(ronshapiro): consider memoizing this
+ public final ComponentPath parent() {
+ checkState(!atRoot());
+ return create(components().subList(0, components().size() - 1));
+ }
+
+ /** Returns the path from the root component to the {@code child} of the current component. */
+ public final ComponentPath childPath(DaggerTypeElement child) {
+ return create(
+ ImmutableList.<DaggerTypeElement>builder().addAll(components()).add(child).build());
+ }
+
+ /**
+ * Returns {@code true} if the {@linkplain #currentComponent()} current component} is the
+ * {@linkplain #rootComponent()} root component}.
+ */
+ public final boolean atRoot() {
+ return components().size() == 1;
+ }
+
+ @Override
+ public final String toString() {
+ return components().stream()
+ .map(DaggerTypeElement::className)
+ .map(ClassName::canonicalName)
+ .collect(joining(" → "));
+ }
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+}
diff --git a/java/dagger/internal/codegen/model/DaggerAnnotation.java b/java/dagger/internal/codegen/model/DaggerAnnotation.java
new file mode 100644
index 0000000..4a59871
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DaggerAnnotation.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XAnnotation;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Preconditions;
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import javax.lang.model.element.AnnotationMirror;
+
+/** Wrapper type for an annotation. */
+@AutoValue
+public abstract class DaggerAnnotation {
+
+ public static DaggerAnnotation from(XAnnotation annotation) {
+ Preconditions.checkNotNull(annotation);
+ return new AutoValue_DaggerAnnotation(XAnnotations.equivalence().wrap(annotation));
+ }
+
+ abstract Equivalence.Wrapper<XAnnotation> equivalenceWrapper();
+
+ public DaggerTypeElement annotationTypeElement() {
+ return DaggerTypeElement.from(xprocessing().getType().getTypeElement());
+ }
+
+ public ClassName className() {
+ return annotationTypeElement().className();
+ }
+
+ public XAnnotation xprocessing() {
+ return equivalenceWrapper().get();
+ }
+
+ public AnnotationMirror java() {
+ return toJavac(xprocessing());
+ }
+
+ @Override
+ public final String toString() {
+ return XAnnotations.toString(xprocessing());
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DaggerElement.java b/java/dagger/internal/codegen/model/DaggerElement.java
new file mode 100644
index 0000000..cf2ac52
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DaggerElement.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XElement;
+import com.google.auto.value.AutoValue;
+import javax.lang.model.element.Element;
+
+/** Wrapper type for an element. */
+@AutoValue
+public abstract class DaggerElement {
+ public static DaggerElement from(XElement element) {
+ return new AutoValue_DaggerElement(element);
+ }
+
+ public abstract XElement xprocessing();
+
+ public Element java() {
+ return toJavac(xprocessing());
+ }
+
+ @Override
+ public final String toString() {
+ return xprocessing().toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DaggerExecutableElement.java b/java/dagger/internal/codegen/model/DaggerExecutableElement.java
new file mode 100644
index 0000000..484e446
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DaggerExecutableElement.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import androidx.room.compiler.processing.XExecutableElement;
+import com.google.auto.value.AutoValue;
+import javax.lang.model.element.ExecutableElement;
+
+/** Wrapper type for an executable element. */
+@AutoValue
+public abstract class DaggerExecutableElement {
+ public static DaggerExecutableElement from(XExecutableElement executableElement) {
+ return new AutoValue_DaggerExecutableElement(checkNotNull(executableElement));
+ }
+
+ public abstract XExecutableElement xprocessing();
+
+ public ExecutableElement java() {
+ return toJavac(xprocessing());
+ }
+
+ @Override
+ public final String toString() {
+ return xprocessing().toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DaggerProcessingEnv.java b/java/dagger/internal/codegen/model/DaggerProcessingEnv.java
new file mode 100644
index 0000000..6645b90
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DaggerProcessingEnv.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import com.google.auto.value.AutoValue;
+import javax.annotation.processing.ProcessingEnvironment;
+
+/** Wrapper type for an element. */
+@AutoValue
+public abstract class DaggerProcessingEnv {
+ /** Represents a type of backend used for compilation. */
+ public enum Backend { JAVAC, KSP }
+
+ public static DaggerProcessingEnv from(XProcessingEnv processingEnv) {
+ return new AutoValue_DaggerProcessingEnv(processingEnv);
+ }
+
+ public abstract XProcessingEnv xprocessing();
+
+ /** Returns the backend used in this compilation. */
+ public Backend getBackend() {
+ return Backend.valueOf(xprocessing().getBackend().name());
+ }
+
+ public ProcessingEnvironment java() {
+ return toJavac(xprocessing());
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DaggerType.java b/java/dagger/internal/codegen/model/DaggerType.java
new file mode 100644
index 0000000..c606f15
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DaggerType.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XType;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Preconditions;
+import dagger.internal.codegen.xprocessing.XTypes;
+import javax.lang.model.type.TypeMirror;
+
+/** Wrapper type for a type. */
+@AutoValue
+public abstract class DaggerType {
+ public static DaggerType from(XType type) {
+ Preconditions.checkNotNull(type);
+ return new AutoValue_DaggerType(XTypes.equivalence().wrap(type));
+ }
+
+ abstract Equivalence.Wrapper<XType> equivalenceWrapper();
+
+ public XType xprocessing() {
+ return equivalenceWrapper().get();
+ }
+
+ public TypeMirror java() {
+ return toJavac(xprocessing());
+ }
+
+ @Override
+ public final String toString() {
+ // We define our own stable string rather than use XType#toString() here because
+ // XType#toString() is currently not stable across backends. In particular, in javac it returns
+ // the qualified type but in ksp it returns the simple name.
+ // TODO(bcorso): Consider changing XProcessing so that #toString() is stable across backends.
+ return XTypes.toStableString(xprocessing());
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DaggerTypeElement.java b/java/dagger/internal/codegen/model/DaggerTypeElement.java
new file mode 100644
index 0000000..77e0c4f
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DaggerTypeElement.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.auto.value.AutoValue;
+import com.squareup.javapoet.ClassName;
+import javax.lang.model.element.TypeElement;
+
+/** Wrapper type for a type element. */
+@AutoValue
+public abstract class DaggerTypeElement {
+ public static DaggerTypeElement from(XTypeElement typeElement) {
+ return new AutoValue_DaggerTypeElement(typeElement);
+ }
+
+ public abstract XTypeElement xprocessing();
+
+ public TypeElement java() {
+ return toJavac(xprocessing());
+ }
+
+ public ClassName className() {
+ return xprocessing().getClassName();
+ }
+
+ @Override
+ public final String toString() {
+ return xprocessing().toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DependencyRequest.java b/java/dagger/internal/codegen/model/DependencyRequest.java
new file mode 100644
index 0000000..aa120c0
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DependencyRequest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import com.google.auto.value.AutoValue;
+import dagger.Provides;
+import java.util.Optional;
+import javax.inject.Inject;
+
+/**
+ * Represents a request for a {@link Key} at an injection point. For example, parameters to {@link
+ * Inject} constructors, {@link Provides} methods, and component methods are all dependency
+ * requests.
+ *
+ * <p id="synthetic">A dependency request is considered to be <em>synthetic</em> if it does not have
+ * an {@link DaggerElement} in code that requests the key directly. For example, an {@link
+ * java.util.concurrent.Executor} is required for all {@code @Produces} methods to run
+ * asynchronously even though it is not directly specified as a parameter to the binding method.
+ */
+@AutoValue
+public abstract class DependencyRequest {
+ /** The kind of this request. */
+ public abstract RequestKind kind();
+
+ /** The key of this request. */
+ public abstract Key key();
+
+ /**
+ * The element that declares this dependency request. Absent for <a href="#synthetic">synthetic
+ * </a> requests.
+ */
+ public abstract Optional<DaggerElement> requestElement();
+
+ /**
+ * Returns {@code true} if this request allows null objects. A request is nullable if it is
+ * has an annotation with "Nullable" as its simple name.
+ */
+ public abstract boolean isNullable();
+
+ /** Returns a new builder of dependency requests. */
+ public static DependencyRequest.Builder builder() {
+ return new AutoValue_DependencyRequest.Builder().isNullable(false);
+ }
+
+ /** A builder of {@link DependencyRequest}s. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder kind(RequestKind kind);
+
+ public abstract Builder key(Key key);
+
+ public abstract Builder requestElement(DaggerElement element);
+
+ public abstract Builder isNullable(boolean isNullable);
+
+ public abstract DependencyRequest build();
+ }
+}
diff --git a/java/dagger/internal/codegen/model/DiagnosticReporter.java b/java/dagger/internal/codegen/model/DiagnosticReporter.java
new file mode 100644
index 0000000..b2dda61
--- /dev/null
+++ b/java/dagger/internal/codegen/model/DiagnosticReporter.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static com.google.common.collect.Lists.asList;
+
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
+import javax.tools.Diagnostic;
+
+// TODO(bcorso): Move this into dagger/spi?
+/**
+ * An object that {@link BindingGraphPlugin}s can use to report diagnostics while visiting a {@link
+ * BindingGraph}.
+ *
+ * <p>Note: This API is still experimental and will change.
+ */
+public abstract class DiagnosticReporter {
+ /**
+ * Reports a diagnostic for a component. For non-root components, includes information about the
+ * path from the root component.
+ */
+ public abstract void reportComponent(
+ Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message);
+
+ /**
+ * Reports a diagnostic for a component. For non-root components, includes information about the
+ * path from the root component.
+ */
+ @FormatMethod
+ public final void reportComponent(
+ Diagnostic.Kind diagnosticKind,
+ ComponentNode componentNode,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportComponent(
+ diagnosticKind, componentNode, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ /**
+ * Reports a diagnostic for a binding or missing binding. Includes information about how the
+ * binding is reachable from entry points.
+ */
+ public abstract void reportBinding(
+ Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message);
+
+ /**
+ * Reports a diagnostic for a binding or missing binding. Includes information about how the
+ * binding is reachable from entry points.
+ */
+ @FormatMethod
+ public final void reportBinding(
+ Diagnostic.Kind diagnosticKind,
+ MaybeBinding binding,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportBinding(diagnosticKind, binding, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ /**
+ * Reports a diagnostic for a dependency. Includes information about how the dependency is
+ * reachable from entry points.
+ */
+ public abstract void reportDependency(
+ Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message);
+
+ /**
+ * Reports a diagnostic for a dependency. Includes information about how the dependency is
+ * reachable from entry points.
+ */
+ @FormatMethod
+ public final void reportDependency(
+ Diagnostic.Kind diagnosticKind,
+ DependencyEdge dependencyEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportDependency(
+ diagnosticKind, dependencyEdge, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ /** Reports a diagnostic for a subcomponent factory method. */
+ public abstract void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String message);
+
+ /** Reports a diagnostic for a subcomponent factory method. */
+ @FormatMethod
+ public final void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportSubcomponentFactoryMethod(
+ diagnosticKind, childFactoryMethodEdge, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ private String formatMessage(String messageFormat, Object firstArg, Object[] moreArgs) {
+ return String.format(messageFormat, asList(firstArg, moreArgs).toArray());
+ }
+}
diff --git a/java/dagger/internal/codegen/model/Key.java b/java/dagger/internal/codegen/model/Key.java
new file mode 100644
index 0000000..585bdea
--- /dev/null
+++ b/java/dagger/internal/codegen/model/Key.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.base.Joiner;
+import dagger.internal.codegen.xprocessing.XAnnotations;
+import dagger.internal.codegen.xprocessing.XElements;
+import java.util.Optional;
+
+/**
+ * A {@linkplain DaggerType type} and an optional {@linkplain javax.inject.Qualifier qualifier} that
+ * is the lookup key for a binding.
+ */
+@AutoValue
+public abstract class Key {
+ /**
+ * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix for the
+ * type of this key.
+ */
+ public abstract Optional<DaggerAnnotation> qualifier();
+
+ /** The type represented by this key. */
+ public abstract DaggerType type();
+
+ /**
+ * Distinguishes keys for multibinding contributions that share a {@link #type()} and {@link
+ * #qualifier()}.
+ *
+ * <p>Each multibound map and set has a synthetic multibinding that depends on the specific
+ * contributions to that map or set using keys that identify those multibinding contributions.
+ *
+ * <p>Absent except for multibinding contributions.
+ */
+ public abstract Optional<MultibindingContributionIdentifier> multibindingContributionIdentifier();
+
+ /** Returns a {@link Builder} that inherits the properties of this key. */
+ abstract Builder toBuilder();
+
+ /** Returns a copy of this key with the type replaced with the given type. */
+ public Key withType(DaggerType newType) {
+ return toBuilder().type(newType).build();
+ }
+
+ /**
+ * Returns a copy of this key with the multibinding contribution identifier replaced with the
+ * given multibinding contribution identifier.
+ */
+ public Key withMultibindingContributionIdentifier(
+ DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
+ return toBuilder()
+ .multibindingContributionIdentifier(contributingModule, bindingMethod)
+ .build();
+ }
+
+ /** Returns a copy of this key with the multibinding contribution identifier, if any, removed. */
+ public Key withoutMultibindingContributionIdentifier() {
+ return toBuilder().multibindingContributionIdentifier(Optional.empty()).build();
+ }
+
+ // The main hashCode/equality bottleneck is in MoreTypes.equivalence(). It's possible that we can
+ // avoid this by tuning that method. Perhaps we can also avoid the issue entirely by interning all
+ // Keys
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
+
+ @Override
+ public final String toString() {
+ return Joiner.on(' ')
+ .skipNulls()
+ .join(
+ qualifier()
+ .map(DaggerAnnotation::xprocessing)
+ .map(XAnnotations::toStableString)
+ .orElse(null),
+ type(),
+ multibindingContributionIdentifier().orElse(null));
+ }
+
+ /** Returns a builder for {@link Key}s. */
+ public static Builder builder(DaggerType type) {
+ return new AutoValue_Key.Builder().type(type);
+ }
+
+ /** A builder for {@link Key}s. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder type(DaggerType type);
+
+ public abstract Builder qualifier(Optional<DaggerAnnotation> qualifier);
+
+ public abstract Builder qualifier(DaggerAnnotation qualifier);
+
+ public final Builder multibindingContributionIdentifier(
+ DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
+ return multibindingContributionIdentifier(
+ Optional.of(
+ MultibindingContributionIdentifier.create(contributingModule, bindingMethod)));
+ }
+
+ abstract Builder multibindingContributionIdentifier(
+ Optional<MultibindingContributionIdentifier> identifier);
+
+ public abstract Key build();
+ }
+
+ /**
+ * An object that identifies a multibinding contribution method and the module class that
+ * contributes it to the graph.
+ *
+ * @see #multibindingContributionIdentifier()
+ */
+ @AutoValue
+ public abstract static class MultibindingContributionIdentifier {
+ private static MultibindingContributionIdentifier create(
+ DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
+ return new AutoValue_Key_MultibindingContributionIdentifier(
+ contributingModule, bindingMethod);
+ }
+
+ /** Returns the module containing the multibinding method. */
+ public abstract DaggerTypeElement contributingModule();
+
+ /** Returns the multibinding method that defines teh multibinding contribution. */
+ public abstract DaggerExecutableElement bindingMethod();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned string is human-readable and distinguishes the keys in the same way as the
+ * whole object.
+ */
+ @Override
+ public String toString() {
+ return String.format(
+ "%s#%s",
+ contributingModule().xprocessing().getQualifiedName(),
+ XElements.getSimpleName(bindingMethod().xprocessing()));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/model/MoreAnnotationMirrors.java b/java/dagger/internal/codegen/model/MoreAnnotationMirrors.java
new file mode 100644
index 0000000..9b45b89
--- /dev/null
+++ b/java/dagger/internal/codegen/model/MoreAnnotationMirrors.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.CodeBlock;
+import java.util.List;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+
+/** Utility class for qualifier transformations */
+final class MoreAnnotationMirrors {
+ /**
+ * Returns a String rendering of an {@link AnnotationMirror} that includes attributes in the order
+ * defined in the annotation type.
+ */
+ public static String toStableString(DaggerAnnotation qualifier) {
+ return stableAnnotationMirrorToString(qualifier.java());
+ }
+
+ /**
+ * Returns a String rendering of an {@link AnnotationMirror} that includes attributes in the order
+ * defined in the annotation type. This will produce the same output for {@linkplain
+ * com.google.auto.common.AnnotationMirrors#equivalence() equal} {@link AnnotationMirror}s even if
+ * default values are omitted or their attributes were written in different orders, e.g.
+ * {@code @A(b = "b", c = "c")} and {@code @A(c = "c", b = "b", attributeWithDefaultValue =
+ * "default value")}.
+ */
+ // TODO(ronshapiro): move this to auto-common
+ private static String stableAnnotationMirrorToString(AnnotationMirror qualifier) {
+ StringBuilder builder = new StringBuilder("@").append(qualifier.getAnnotationType());
+ ImmutableMap<ExecutableElement, AnnotationValue> elementValues =
+ getAnnotationValuesWithDefaults(qualifier);
+ if (!elementValues.isEmpty()) {
+ ImmutableMap.Builder<String, String> namedValuesBuilder = ImmutableMap.builder();
+ elementValues.forEach(
+ (key, value) ->
+ namedValuesBuilder.put(
+ key.getSimpleName().toString(), stableAnnotationValueToString(value)));
+ ImmutableMap<String, String> namedValues = namedValuesBuilder.build();
+ builder.append('(');
+ if (namedValues.size() == 1 && namedValues.containsKey("value")) {
+ // Omit "value ="
+ builder.append(namedValues.get("value"));
+ } else {
+ builder.append(Joiner.on(", ").withKeyValueSeparator("=").join(namedValues));
+ }
+ builder.append(')');
+ }
+ return builder.toString();
+ }
+
+ private static String stableAnnotationValueToString(AnnotationValue annotationValue) {
+ return annotationValue.accept(
+ new SimpleAnnotationValueVisitor8<String, Void>() {
+ @Override
+ protected String defaultAction(Object value, Void ignore) {
+ return value.toString();
+ }
+
+ @Override
+ public String visitString(String value, Void ignore) {
+ return CodeBlock.of("$S", value).toString();
+ }
+
+ @Override
+ public String visitAnnotation(AnnotationMirror value, Void ignore) {
+ return stableAnnotationMirrorToString(value);
+ }
+
+ @Override
+ public String visitArray(List<? extends AnnotationValue> value, Void ignore) {
+ return value.stream()
+ .map(MoreAnnotationMirrors::stableAnnotationValueToString)
+ .collect(joining(", ", "{", "}"));
+ }
+ },
+ null);
+ }
+
+ private MoreAnnotationMirrors() {}
+}
diff --git a/java/dagger/internal/codegen/model/RequestKind.java b/java/dagger/internal/codegen/model/RequestKind.java
new file mode 100644
index 0000000..581a829
--- /dev/null
+++ b/java/dagger/internal/codegen/model/RequestKind.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+
+import dagger.Lazy;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+
+/**
+ * Represents the different kinds of {@link javax.lang.model.type.TypeMirror types} that may be
+ * requested as dependencies for the same key. For example, {@code String}, {@code
+ * Provider<String>}, and {@code Lazy<String>} can all be requested if a key exists for {@code
+ * String}; they have the {@link #INSTANCE}, {@link #PROVIDER}, and {@link #LAZY} request kinds,
+ * respectively.
+ */
+public enum RequestKind {
+ /** A default request for an instance. E.g.: {@code FooType} */
+ INSTANCE,
+
+ /** A request for a {@link Provider}. E.g.: {@code Provider<FooType>} */
+ PROVIDER,
+
+ /** A request for a {@link Lazy}. E.g.: {@code Lazy<FooType>} */
+ LAZY,
+
+ /** A request for a {@link Provider} of a {@link Lazy}. E.g.: {@code Provider<Lazy<FooType>>} */
+ PROVIDER_OF_LAZY,
+
+ /**
+ * A request for a members injection. E.g. {@code void injectMembers(FooType);}. Can only be
+ * requested by component interfaces.
+ */
+ MEMBERS_INJECTION,
+
+ /** A request for a {@link Producer}. E.g.: {@code Producer<FooType>} */
+ PRODUCER,
+
+ /** A request for a {@link Produced}. E.g.: {@code Produced<FooType>} */
+ PRODUCED,
+
+ /**
+ * A request for a {@link com.google.common.util.concurrent.ListenableFuture}. E.g.: {@code
+ * ListenableFuture<FooType>}. These can only be requested by component interfaces.
+ */
+ FUTURE,
+ ;
+
+ /** Returns a string that represents requests of this kind for a key. */
+ public String format(Key key) {
+ switch (this) {
+ case INSTANCE:
+ return key.toString();
+
+ case PROVIDER_OF_LAZY:
+ return String.format("Provider<Lazy<%s>>", key);
+
+ case MEMBERS_INJECTION:
+ return String.format("injectMembers(%s)", key);
+
+ case FUTURE:
+ return String.format("ListenableFuture<%s>", key);
+
+ default:
+ return String.format("%s<%s>", UPPER_UNDERSCORE.to(UPPER_CAMEL, name()), key);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/model/Scope.java b/java/dagger/internal/codegen/model/Scope.java
new file mode 100644
index 0000000..0ea13b3
--- /dev/null
+++ b/java/dagger/internal/codegen/model/Scope.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.model;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.value.AutoValue;
+import com.squareup.javapoet.ClassName;
+
+/** A representation of a {@link javax.inject.Scope}. */
+@AutoValue
+public abstract class Scope {
+ /**
+ * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
+ */
+ public static Scope scope(DaggerAnnotation scopeAnnotation) {
+ checkArgument(isScope(scopeAnnotation));
+ return new AutoValue_Scope(scopeAnnotation);
+ }
+
+ /**
+ * Returns {@code true} if {@link #scopeAnnotation()} is a {@link javax.inject.Scope} annotation.
+ */
+ public static boolean isScope(DaggerAnnotation scopeAnnotation) {
+ return isScope(scopeAnnotation.annotationTypeElement());
+ }
+
+ /**
+ * Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation.
+ */
+ public static boolean isScope(DaggerTypeElement scopeAnnotationType) {
+ return scopeAnnotationType.xprocessing().hasAnnotation(SCOPE)
+ || scopeAnnotationType.xprocessing().hasAnnotation(SCOPE_JAVAX);
+ }
+
+ private static final ClassName PRODUCTION_SCOPE =
+ ClassName.get("dagger.producers", "ProductionScope");
+ private static final ClassName SINGLETON = ClassName.get("jakarta.inject", "Singleton");
+ private static final ClassName SINGLETON_JAVAX = ClassName.get("javax.inject", "Singleton");
+ private static final ClassName REUSABLE = ClassName.get("dagger", "Reusable");
+ private static final ClassName SCOPE = ClassName.get("jakarta.inject", "Scope");
+ private static final ClassName SCOPE_JAVAX = ClassName.get("javax.inject", "Scope");
+
+
+ /** The {@link DaggerAnnotation} that represents the scope annotation. */
+ public abstract DaggerAnnotation scopeAnnotation();
+
+ public final ClassName className() {
+ return scopeAnnotation().className();
+ }
+
+ /** Returns {@code true} if this scope is the {@link javax.inject.Singleton @Singleton} scope. */
+ public final boolean isSingleton() {
+ return isScope(SINGLETON) || isScope(SINGLETON_JAVAX);
+ }
+
+ /** Returns {@code true} if this scope is the {@link dagger.Reusable @Reusable} scope. */
+ public final boolean isReusable() {
+ return isScope(REUSABLE);
+ }
+
+ /**
+ * Returns {@code true} if this scope is the {@link
+ * dagger.producers.ProductionScope @ProductionScope} scope.
+ */
+ public final boolean isProductionScope() {
+ return isScope(PRODUCTION_SCOPE);
+ }
+
+ private boolean isScope(ClassName annotation) {
+ return scopeAnnotation().className().equals(annotation);
+ }
+
+ /** Returns a debug representation of the scope. */
+ @Override
+ public final String toString() {
+ return scopeAnnotation().toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/processingstep/BUILD b/java/dagger/internal/codegen/processingstep/BUILD
index 97d79af..bcd8c33 100644
--- a/java/dagger/internal/codegen/processingstep/BUILD
+++ b/java/dagger/internal/codegen/processingstep/BUILD
@@ -31,10 +31,10 @@
"//java/dagger/internal/codegen/extension",
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
"//java/dagger/internal/codegen/xprocessing",
- "//java/dagger/spi",
"//third_party/java/auto:common",
"//third_party/java/error_prone:annotations",
"//third_party/java/guava/base",
diff --git a/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java b/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java
index bac8d21..5b17c00 100644
--- a/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java
+++ b/java/dagger/internal/codegen/processingstep/ComponentProcessingStep.java
@@ -105,7 +105,7 @@
return;
}
- Supplier<dagger.spi.model.BindingGraph> fullBindingGraphSupplier =
+ Supplier<dagger.internal.codegen.model.BindingGraph> fullBindingGraphSupplier =
Suppliers.memoize(
() -> bindingGraphFactory.create(componentDescriptor, true).topLevelBindingGraph());
if (bindingGraphValidator.shouldDoFullBindingGraphValidation(component)) {
diff --git a/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java b/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java
index e3daf21..1df14ec 100644
--- a/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java
+++ b/java/dagger/internal/codegen/processingstep/ModuleProcessingStep.java
@@ -130,7 +130,11 @@
inaccessibleMapKeyProxyGenerator.generate(bindsMethodBinding(module, method), messager);
}
}
- moduleConstructorProxyGenerator.generate(module, messager);
+ // We should never need to generate a constructor proxy for a companion object since we never
+ // need to call a companion object's constructor.
+ if (!module.isCompanionObject()) {
+ moduleConstructorProxyGenerator.generate(module, messager);
+ }
}
private <B extends ContributionBinding> void generate(
diff --git a/java/dagger/internal/codegen/validation/BUILD b/java/dagger/internal/codegen/validation/BUILD
index fa2a6b8..cc36708 100644
--- a/java/dagger/internal/codegen/validation/BUILD
+++ b/java/dagger/internal/codegen/validation/BUILD
@@ -33,6 +33,7 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/xprocessing",
"//java/dagger/spi",
"//third_party/java/auto:common",
@@ -46,5 +47,6 @@
"//third_party/java/guava/util/concurrent",
"//third_party/java/javapoet",
"//third_party/java/jsr330_inject",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
diff --git a/java/dagger/internal/codegen/validation/BindingElementValidator.java b/java/dagger/internal/codegen/validation/BindingElementValidator.java
index 16812e6..c7c9f76 100644
--- a/java/dagger/internal/codegen/validation/BindingElementValidator.java
+++ b/java/dagger/internal/codegen/validation/BindingElementValidator.java
@@ -39,9 +39,9 @@
import dagger.internal.codegen.base.SetType;
import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XElements;
-import dagger.spi.model.Key;
-import dagger.spi.model.Scope;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/validation/BindingGraphValidator.java b/java/dagger/internal/codegen/validation/BindingGraphValidator.java
index d20fe99..e478f4b 100644
--- a/java/dagger/internal/codegen/validation/BindingGraphValidator.java
+++ b/java/dagger/internal/codegen/validation/BindingGraphValidator.java
@@ -21,7 +21,7 @@
import com.google.common.base.Supplier;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ValidationType;
-import dagger.spi.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph;
import javax.inject.Inject;
import javax.inject.Singleton;
diff --git a/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java b/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
index d0a924f..10523ef 100644
--- a/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
@@ -63,8 +63,8 @@
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ValidationType;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.Scope;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
diff --git a/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java b/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
index 6ea19d6..6a129cc 100644
--- a/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
@@ -43,7 +43,7 @@
import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.binding.ModuleDescriptor;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.model.Scope;
import java.util.Collection;
import java.util.Formatter;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/validation/ComponentValidator.java b/java/dagger/internal/codegen/validation/ComponentValidator.java
index b3fc1a9..b503448 100644
--- a/java/dagger/internal/codegen/validation/ComponentValidator.java
+++ b/java/dagger/internal/codegen/validation/ComponentValidator.java
@@ -69,10 +69,10 @@
import dagger.internal.codegen.binding.MethodSignatureFormatter;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.xprocessing.XTypeElements;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashMap;
diff --git a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
index 8f49b0e..5510048 100644
--- a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
+++ b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
@@ -44,8 +44,8 @@
import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.xprocessing.XTypes;
-import dagger.spi.model.RequestKind;
import java.util.Optional;
import javax.inject.Inject;
@@ -92,7 +92,11 @@
new Validator(report, requestElement, requestType).validate();
}
- /** Returns {@code true} if a kotlin inject field is missing metadata about its qualifiers. */
+ /**
+ * Returns {@code true} if a kotlin inject field is missing metadata about its qualifiers.
+ *
+ * <p>See https://youtrack.jetbrains.com/issue/KT-34684.
+ */
private boolean missingQualifierMetadata(XElement requestElement) {
if (isField(requestElement)) {
XFieldElement fieldElement = asField(requestElement);
diff --git a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
index 6767524..fc83e31 100644
--- a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
+++ b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
@@ -52,14 +52,14 @@
import dagger.internal.codegen.base.ElementFormatter;
import dagger.internal.codegen.base.Formatter;
import dagger.internal.codegen.binding.DependencyRequestFormatter;
-import dagger.spi.model.Binding;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.Edge;
-import dagger.spi.model.BindingGraph.MaybeBinding;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.DaggerElement;
+import dagger.internal.codegen.model.Binding;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.Edge;
+import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.DaggerElement;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
@@ -262,7 +262,8 @@
* Returns the dependency trace from one of the {@code entryPoints} to {@code binding} to {@code
* message} as a list <i>ending with</i> the entry point.
*/
- // TODO(ronshapiro): Adding a DependencyPath type to dagger.spi.model could be useful, i.e.
+ // TODO(ronshapiro): Adding a DependencyPath type to dagger.internal.codegen.model could be
+ // useful, i.e.
// bindingGraph.shortestPathFromEntryPoint(DependencyEdge, MaybeBindingNode)
public ImmutableList<DependencyEdge> dependencyTrace(
MaybeBinding binding, ImmutableSet<DependencyEdge> entryPoints) {
diff --git a/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java b/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
index 66ad74b..dad81d5 100644
--- a/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
+++ b/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
@@ -24,12 +24,12 @@
import androidx.room.compiler.processing.XMessager;
import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraph.DependencyEdge;
-import dagger.spi.model.BindingGraph.MaybeBinding;
-import dagger.spi.model.DiagnosticReporter;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraph.DependencyEdge;
+import dagger.internal.codegen.model.BindingGraph.MaybeBinding;
+import dagger.internal.codegen.model.DiagnosticReporter;
import javax.inject.Inject;
import javax.tools.Diagnostic;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
diff --git a/java/dagger/internal/codegen/validation/External.java b/java/dagger/internal/codegen/validation/External.java
index 73787f5..7fbbdbc 100644
--- a/java/dagger/internal/codegen/validation/External.java
+++ b/java/dagger/internal/codegen/validation/External.java
@@ -22,8 +22,8 @@
import javax.inject.Qualifier;
/**
- * Qualifier annotation for the {@link dagger.spi.model.BindingGraphPlugin}s that are registered by
- * users.
+ * Qualifier annotation for the {@link dagger.internal.codegen.model.BindingGraphPlugin}s that are
+ * registered by users.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java b/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java
deleted file mode 100644
index af1836b..0000000
--- a/java/dagger/internal/codegen/validation/ExternalBindingGraphConverter.java
+++ /dev/null
@@ -1,433 +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.internal.codegen.validation;
-
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.graph.EndpointPair;
-import com.google.common.graph.ImmutableNetwork;
-import com.google.common.graph.MutableNetwork;
-import com.google.common.graph.Network;
-import com.google.common.graph.NetworkBuilder;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
-import dagger.model.BindingKind;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Key.MultibindingContributionIdentifier;
-import dagger.model.RequestKind;
-import dagger.model.Scope;
-import dagger.spi.DiagnosticReporter;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DaggerElement;
-import dagger.spi.model.DaggerTypeElement;
-import java.util.Optional;
-import javax.tools.Diagnostic;
-
-/** A Utility class for converting to the {@link BindingGraph} used by external plugins. */
-public final class ExternalBindingGraphConverter {
- private ExternalBindingGraphConverter() {}
-
- /** Returns a {@link DiagnosticReporter} from a {@link dagger.spi.DiagnosticReporter}. */
- public static DiagnosticReporter fromSpiModel(dagger.spi.model.DiagnosticReporter reporter) {
- return DiagnosticReporterImpl.create(reporter);
- }
-
- /** Returns a {@link BindingGraph} from a {@link dagger.spi.model.BindingGraph}. */
- public static BindingGraph fromSpiModel(dagger.spi.model.BindingGraph graph) {
- return BindingGraphImpl.create(graph);
- }
-
- private static ImmutableNetwork<Node, Edge> fromSpiModel(
- Network<dagger.spi.model.BindingGraph.Node, dagger.spi.model.BindingGraph.Edge> spiNetwork) {
- MutableNetwork<Node, Edge> network =
- NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
-
- ImmutableMap<dagger.spi.model.BindingGraph.Node, Node> fromSpiNodes =
- spiNetwork.nodes().stream()
- .collect(
- toImmutableMap(
- spiNode -> spiNode,
- ExternalBindingGraphConverter::fromSpiModel));
-
- for (Node node : fromSpiNodes.values()) {
- network.addNode(node);
- }
- for (dagger.spi.model.BindingGraph.Edge edge : spiNetwork.edges()) {
- EndpointPair<dagger.spi.model.BindingGraph.Node> edgePair = spiNetwork.incidentNodes(edge);
- network.addEdge(
- fromSpiNodes.get(edgePair.source()),
- fromSpiNodes.get(edgePair.target()),
- fromSpiModel(edge));
- }
- return ImmutableNetwork.copyOf(network);
- }
-
- private static Node fromSpiModel(dagger.spi.model.BindingGraph.Node node) {
- if (node instanceof dagger.spi.model.Binding) {
- return BindingNodeImpl.create((dagger.spi.model.Binding) node);
- } else if (node instanceof dagger.spi.model.BindingGraph.ComponentNode) {
- return ComponentNodeImpl.create((dagger.spi.model.BindingGraph.ComponentNode) node);
- } else if (node instanceof dagger.spi.model.BindingGraph.MissingBinding) {
- return MissingBindingImpl.create((dagger.spi.model.BindingGraph.MissingBinding) node);
- } else {
- throw new IllegalStateException("Unhandled node type: " + node.getClass());
- }
- }
-
- private static Edge fromSpiModel(dagger.spi.model.BindingGraph.Edge edge) {
- if (edge instanceof dagger.spi.model.BindingGraph.DependencyEdge) {
- return DependencyEdgeImpl.create((dagger.spi.model.BindingGraph.DependencyEdge) edge);
- } else if (edge instanceof dagger.spi.model.BindingGraph.ChildFactoryMethodEdge) {
- return ChildFactoryMethodEdgeImpl.create(
- (dagger.spi.model.BindingGraph.ChildFactoryMethodEdge) edge);
- } else if (edge instanceof dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge) {
- return SubcomponentCreatorBindingEdgeImpl.create(
- (dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge) edge);
- } else {
- throw new IllegalStateException("Unhandled edge type: " + edge.getClass());
- }
- }
-
- private static MultibindingContributionIdentifier fromSpiModel(
- dagger.spi.model.Key.MultibindingContributionIdentifier identifier) {
- return new MultibindingContributionIdentifier(
- identifier.bindingMethod(), identifier.contributingModule());
- }
-
- private static Key fromSpiModel(dagger.spi.model.Key key) {
- return Key.builder(key.type().java())
- .qualifier(key.qualifier().map(DaggerAnnotation::java))
- .multibindingContributionIdentifier(
- key.multibindingContributionIdentifier().isPresent()
- ? Optional.of(fromSpiModel(key.multibindingContributionIdentifier().get()))
- : Optional.empty())
- .build();
- }
-
- private static BindingKind fromSpiModel(dagger.spi.model.BindingKind bindingKind) {
- return BindingKind.valueOf(bindingKind.name());
- }
-
- private static RequestKind fromSpiModel(dagger.spi.model.RequestKind requestKind) {
- return RequestKind.valueOf(requestKind.name());
- }
-
- private static DependencyRequest fromSpiModel(dagger.spi.model.DependencyRequest request) {
- DependencyRequest.Builder builder =
- DependencyRequest.builder()
- .kind(fromSpiModel(request.kind()))
- .key(fromSpiModel(request.key()))
- .isNullable(request.isNullable());
-
- request.requestElement().ifPresent(e -> builder.requestElement(e.java()));
- return builder.build();
- }
-
- private static Scope fromSpiModel(dagger.spi.model.Scope scope) {
- return Scope.scope(scope.scopeAnnotation().java());
- }
-
- private static ComponentPath fromSpiModel(dagger.spi.model.ComponentPath path) {
- return ComponentPath.create(
- path.components().stream().map(DaggerTypeElement::java).collect(toImmutableList()));
- }
-
- private static dagger.spi.model.BindingGraph.ComponentNode toSpiModel(
- ComponentNode componentNode) {
- return ((ComponentNodeImpl) componentNode).spiDelegate();
- }
-
- private static dagger.spi.model.BindingGraph.MaybeBinding toSpiModel(MaybeBinding maybeBinding) {
- if (maybeBinding instanceof MissingBindingImpl) {
- return ((MissingBindingImpl) maybeBinding).spiDelegate();
- } else if (maybeBinding instanceof BindingNodeImpl) {
- return ((BindingNodeImpl) maybeBinding).spiDelegate();
- } else {
- throw new IllegalStateException("Unhandled binding type: " + maybeBinding.getClass());
- }
- }
-
- private static dagger.spi.model.BindingGraph.DependencyEdge toSpiModel(
- DependencyEdge dependencyEdge) {
- return ((DependencyEdgeImpl) dependencyEdge).spiDelegate();
- }
-
- private static dagger.spi.model.BindingGraph.ChildFactoryMethodEdge toSpiModel(
- ChildFactoryMethodEdge childFactoryMethodEdge) {
- return ((ChildFactoryMethodEdgeImpl) childFactoryMethodEdge).spiDelegate();
- }
-
- @AutoValue
- abstract static class ComponentNodeImpl implements ComponentNode {
- static ComponentNode create(dagger.spi.model.BindingGraph.ComponentNode componentNode) {
- return new AutoValue_ExternalBindingGraphConverter_ComponentNodeImpl(
- fromSpiModel(componentNode.componentPath()),
- componentNode.isSubcomponent(),
- componentNode.isRealComponent(),
- componentNode.entryPoints().stream()
- .map(ExternalBindingGraphConverter::fromSpiModel)
- .collect(toImmutableSet()),
- componentNode.scopes().stream()
- .map(ExternalBindingGraphConverter::fromSpiModel)
- .collect(toImmutableSet()),
- componentNode);
- }
-
- abstract dagger.spi.model.BindingGraph.ComponentNode spiDelegate();
-
- @Override
- public final String toString() {
- return spiDelegate().toString();
- }
- }
-
- @AutoValue
- abstract static class BindingNodeImpl implements Binding {
- static Binding create(dagger.spi.model.Binding binding) {
- return new AutoValue_ExternalBindingGraphConverter_BindingNodeImpl(
- fromSpiModel(binding.key()),
- fromSpiModel(binding.componentPath()),
- binding.dependencies().stream()
- .map(ExternalBindingGraphConverter::fromSpiModel)
- .collect(toImmutableSet()),
- binding.bindingElement().map(DaggerElement::java),
- binding.contributingModule().map(DaggerTypeElement::java),
- binding.requiresModuleInstance(),
- binding.scope().map(ExternalBindingGraphConverter::fromSpiModel),
- binding.isNullable(),
- binding.isProduction(),
- fromSpiModel(binding.kind()),
- binding);
- }
-
- abstract dagger.spi.model.Binding spiDelegate();
-
- @Override
- public final String toString() {
- return spiDelegate().toString();
- }
- }
-
- @AutoValue
- abstract static class MissingBindingImpl extends MissingBinding {
- static MissingBinding create(dagger.spi.model.BindingGraph.MissingBinding missingBinding) {
- return new AutoValue_ExternalBindingGraphConverter_MissingBindingImpl(
- fromSpiModel(missingBinding.componentPath()),
- fromSpiModel(missingBinding.key()),
- missingBinding);
- }
-
- abstract dagger.spi.model.BindingGraph.MissingBinding spiDelegate();
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object o);
- }
-
- @AutoValue
- abstract static class DependencyEdgeImpl implements DependencyEdge {
- static DependencyEdge create(dagger.spi.model.BindingGraph.DependencyEdge dependencyEdge) {
- return new AutoValue_ExternalBindingGraphConverter_DependencyEdgeImpl(
- fromSpiModel(dependencyEdge.dependencyRequest()),
- dependencyEdge.isEntryPoint(),
- dependencyEdge);
- }
-
- abstract dagger.spi.model.BindingGraph.DependencyEdge spiDelegate();
-
- @Override
- public final String toString() {
- return spiDelegate().toString();
- }
- }
-
- @AutoValue
- abstract static class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
- static ChildFactoryMethodEdge create(
- dagger.spi.model.BindingGraph.ChildFactoryMethodEdge childFactoryMethodEdge) {
- return new AutoValue_ExternalBindingGraphConverter_ChildFactoryMethodEdgeImpl(
- childFactoryMethodEdge.factoryMethod().java(), childFactoryMethodEdge);
- }
-
- abstract dagger.spi.model.BindingGraph.ChildFactoryMethodEdge spiDelegate();
-
- @Override
- public final String toString() {
- return spiDelegate().toString();
- }
- }
-
- @AutoValue
- abstract static class SubcomponentCreatorBindingEdgeImpl
- implements SubcomponentCreatorBindingEdge {
- static SubcomponentCreatorBindingEdge create(
- dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge
- subcomponentCreatorBindingEdge) {
- return new AutoValue_ExternalBindingGraphConverter_SubcomponentCreatorBindingEdgeImpl(
- subcomponentCreatorBindingEdge.declaringModules().stream()
- .map(DaggerTypeElement::java)
- .collect(toImmutableSet()),
- subcomponentCreatorBindingEdge);
- }
-
- abstract dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge spiDelegate();
-
- @Override
- public final String toString() {
- return spiDelegate().toString();
- }
- }
-
- @AutoValue
- abstract static class BindingGraphImpl extends BindingGraph {
- static BindingGraph create(dagger.spi.model.BindingGraph bindingGraph) {
- BindingGraphImpl bindingGraphImpl =
- new AutoValue_ExternalBindingGraphConverter_BindingGraphImpl(
- fromSpiModel(bindingGraph.network()), bindingGraph.isFullBindingGraph());
-
- bindingGraphImpl.componentNodesByPath =
- bindingGraphImpl.componentNodes().stream()
- .collect(toImmutableMap(ComponentNode::componentPath, node -> node));
-
- return bindingGraphImpl;
- }
-
- private ImmutableMap<ComponentPath, ComponentNode> componentNodesByPath;
-
- // This overrides dagger.model.BindingGraph with a more efficient implementation.
- @Override
- public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
- return componentNodesByPath.containsKey(componentPath)
- ? Optional.of(componentNodesByPath.get(componentPath))
- : Optional.empty();
- }
-
- // This overrides dagger.model.BindingGraph to memoize the output.
- @Override
- @Memoized
- public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
- return super.nodesByClass();
- }
- }
-
- private static final class DiagnosticReporterImpl implements DiagnosticReporter {
- static DiagnosticReporterImpl create(dagger.spi.model.DiagnosticReporter reporter) {
- return new DiagnosticReporterImpl(reporter);
- }
-
- private final dagger.spi.model.DiagnosticReporter delegate;
-
- DiagnosticReporterImpl(dagger.spi.model.DiagnosticReporter delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public void reportComponent(
- Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message) {
- delegate.reportComponent(diagnosticKind, toSpiModel(componentNode), message);
- }
-
- @Override
- @FormatMethod
- public void reportComponent(
- Diagnostic.Kind diagnosticKind,
- ComponentNode componentNode,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- delegate.reportComponent(
- diagnosticKind, toSpiModel(componentNode), messageFormat, firstArg, moreArgs);
- }
-
- @Override
- public void reportBinding(
- Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
- delegate.reportBinding(diagnosticKind, toSpiModel(binding), message);
- }
-
- @Override
- @FormatMethod
- public void reportBinding(
- Diagnostic.Kind diagnosticKind,
- MaybeBinding binding,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- delegate.reportBinding(
- diagnosticKind, toSpiModel(binding), messageFormat, firstArg, moreArgs);
- }
-
- @Override
- public void reportDependency(
- Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
- delegate.reportDependency(diagnosticKind, toSpiModel(dependencyEdge), message);
- }
-
- @Override
- @FormatMethod
- public void reportDependency(
- Diagnostic.Kind diagnosticKind,
- DependencyEdge dependencyEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- delegate.reportDependency(
- diagnosticKind, toSpiModel(dependencyEdge), messageFormat, firstArg, moreArgs);
- }
-
- @Override
- public void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String message) {
- delegate.reportSubcomponentFactoryMethod(
- diagnosticKind, toSpiModel(childFactoryMethodEdge), message);
- }
-
- @Override
- @FormatMethod
- public void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- delegate.reportSubcomponentFactoryMethod(
- diagnosticKind, toSpiModel(childFactoryMethodEdge), messageFormat, firstArg, moreArgs);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java b/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
index d628246..ba8e6a0 100644
--- a/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
+++ b/java/dagger/internal/codegen/validation/ExternalBindingGraphPlugins.java
@@ -30,7 +30,6 @@
import dagger.spi.DiagnosticReporter;
import dagger.spi.model.BindingGraph;
import dagger.spi.model.BindingGraphPlugin;
-import dagger.spi.model.DaggerProcessingEnv;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
@@ -82,7 +81,7 @@
supportedOptions.isEmpty()
? ImmutableMap.of()
: Maps.filterKeys(processingOptions, supportedOptions::contains);
- plugin.init(DaggerProcessingEnv.from(processingEnv), filteredOptions);
+ plugin.init(SpiModelBindingGraphConverter.toSpiModel(processingEnv), filteredOptions);
}
private void initializeLegacyPlugin(dagger.spi.BindingGraphPlugin plugin) {
@@ -96,22 +95,21 @@
}
/** Returns {@code false} if any of the plugins reported an error. */
- boolean visit(BindingGraph graph) {
+ boolean visit(dagger.internal.codegen.model.BindingGraph graph) {
return visitLegacyPlugins(graph) && visitPlugins(graph);
}
- private boolean visitLegacyPlugins(BindingGraph graph) {
+ private boolean visitLegacyPlugins(dagger.internal.codegen.model.BindingGraph graph) {
// Return early to avoid converting the binding graph when there are no external plugins.
if (legacyPlugins.isEmpty()) {
return true;
}
-
- dagger.model.BindingGraph legacyGraph = ExternalBindingGraphConverter.fromSpiModel(graph);
+ dagger.model.BindingGraph legacyGraph = ModelBindingGraphConverter.toModel(graph);
boolean isClean = true;
for (dagger.spi.BindingGraphPlugin legacyPlugin : legacyPlugins) {
DiagnosticReporterImpl reporter =
diagnosticReporterFactory.reporter(graph, legacyPlugin.pluginName());
- DiagnosticReporter legacyReporter = ExternalBindingGraphConverter.fromSpiModel(reporter);
+ DiagnosticReporter legacyReporter = ModelBindingGraphConverter.toModel(reporter);
legacyPlugin.visitGraph(legacyGraph, legacyReporter);
if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
isClean = false;
@@ -120,12 +118,13 @@
return isClean;
}
- private boolean visitPlugins(BindingGraph graph) {
+ private boolean visitPlugins(dagger.internal.codegen.model.BindingGraph graph) {
+ BindingGraph spiGraph = SpiModelBindingGraphConverter.toSpiModel(graph, processingEnv);
boolean isClean = true;
for (BindingGraphPlugin plugin : plugins) {
DiagnosticReporterImpl reporter =
diagnosticReporterFactory.reporter(graph, plugin.pluginName());
- plugin.visitGraph(graph, reporter);
+ plugin.visitGraph(spiGraph, SpiModelBindingGraphConverter.toSpiModel(reporter));
if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
isClean = false;
}
diff --git a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
index 3c2ed69..cc2d6e9 100644
--- a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
+++ b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
@@ -55,7 +55,7 @@
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.Key;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/validation/InjectValidator.java b/java/dagger/internal/codegen/validation/InjectValidator.java
index e359a6d..f223f6a 100644
--- a/java/dagger/internal/codegen/validation/InjectValidator.java
+++ b/java/dagger/internal/codegen/validation/InjectValidator.java
@@ -48,8 +48,8 @@
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.langmodel.Accessibility;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XAnnotations;
-import dagger.spi.model.Scope;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/validation/ModelBindingGraphConverter.java b/java/dagger/internal/codegen/validation/ModelBindingGraphConverter.java
new file mode 100644
index 0000000..314ed5f
--- /dev/null
+++ b/java/dagger/internal/codegen/validation/ModelBindingGraphConverter.java
@@ -0,0 +1,445 @@
+/*
+ * 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.internal.codegen.validation;
+
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DaggerElement;
+import dagger.internal.codegen.model.DaggerTypeElement;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.model.Binding;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.BindingGraph.Edge;
+import dagger.model.BindingGraph.MaybeBinding;
+import dagger.model.BindingGraph.MissingBinding;
+import dagger.model.BindingGraph.Node;
+import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
+import dagger.model.BindingKind;
+import dagger.model.ComponentPath;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.Key.MultibindingContributionIdentifier;
+import dagger.model.RequestKind;
+import dagger.model.Scope;
+import dagger.spi.DiagnosticReporter;
+import java.util.Optional;
+import javax.tools.Diagnostic;
+
+/** A Utility class for converting to the {@link BindingGraph} used by external plugins. */
+public final class ModelBindingGraphConverter {
+ private ModelBindingGraphConverter() {}
+
+ /** Returns a {@link DiagnosticReporter} from a {@link dagger.spi.DiagnosticReporter}. */
+ public static DiagnosticReporter toModel(
+ dagger.internal.codegen.model.DiagnosticReporter reporter) {
+ return DiagnosticReporterImpl.create(reporter);
+ }
+
+ /** Returns a {@link BindingGraph} from a {@link dagger.internal.codegen.model.BindingGraph}. */
+ public static BindingGraph toModel(dagger.internal.codegen.model.BindingGraph graph) {
+ return BindingGraphImpl.create(graph);
+ }
+
+ private static ImmutableNetwork<Node, Edge> toModel(
+ Network<
+ dagger.internal.codegen.model.BindingGraph.Node,
+ dagger.internal.codegen.model.BindingGraph.Edge>
+ internalNetwork) {
+ MutableNetwork<Node, Edge> network =
+ NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
+
+ ImmutableMap<dagger.internal.codegen.model.BindingGraph.Node, Node> fromInternalNodes =
+ internalNetwork.nodes().stream()
+ .collect(toImmutableMap(node -> node, ModelBindingGraphConverter::toModel));
+
+ for (Node node : fromInternalNodes.values()) {
+ network.addNode(node);
+ }
+ for (dagger.internal.codegen.model.BindingGraph.Edge edge : internalNetwork.edges()) {
+ EndpointPair<dagger.internal.codegen.model.BindingGraph.Node> edgePair =
+ internalNetwork.incidentNodes(edge);
+ network.addEdge(
+ fromInternalNodes.get(edgePair.source()),
+ fromInternalNodes.get(edgePair.target()),
+ toModel(edge));
+ }
+ return ImmutableNetwork.copyOf(network);
+ }
+
+ private static Node toModel(dagger.internal.codegen.model.BindingGraph.Node node) {
+ if (node instanceof dagger.internal.codegen.model.Binding) {
+ return BindingNodeImpl.create((dagger.internal.codegen.model.Binding) node);
+ } else if (node instanceof dagger.internal.codegen.model.BindingGraph.ComponentNode) {
+ return ComponentNodeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.ComponentNode) node);
+ } else if (node instanceof dagger.internal.codegen.model.BindingGraph.MissingBinding) {
+ return MissingBindingImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.MissingBinding) node);
+ } else {
+ throw new IllegalStateException("Unhandled node type: " + node.getClass());
+ }
+ }
+
+ private static Edge toModel(dagger.internal.codegen.model.BindingGraph.Edge edge) {
+ if (edge instanceof dagger.internal.codegen.model.BindingGraph.DependencyEdge) {
+ return DependencyEdgeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.DependencyEdge) edge);
+ } else if (edge instanceof dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge) {
+ return ChildFactoryMethodEdgeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge) edge);
+ } else if (edge
+ instanceof dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge) {
+ return SubcomponentCreatorBindingEdgeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge) edge);
+ } else {
+ throw new IllegalStateException("Unhandled edge type: " + edge.getClass());
+ }
+ }
+
+ private static MultibindingContributionIdentifier toModel(
+ dagger.internal.codegen.model.Key.MultibindingContributionIdentifier identifier) {
+ return new MultibindingContributionIdentifier(
+ XElements.getSimpleName(identifier.bindingMethod().xprocessing()),
+ identifier.contributingModule().xprocessing().getQualifiedName());
+ }
+
+ private static Key toModel(dagger.internal.codegen.model.Key key) {
+ return Key.builder(key.type().java())
+ .qualifier(key.qualifier().map(DaggerAnnotation::java))
+ .multibindingContributionIdentifier(
+ key.multibindingContributionIdentifier().isPresent()
+ ? Optional.of(toModel(key.multibindingContributionIdentifier().get()))
+ : Optional.empty())
+ .build();
+ }
+
+ private static BindingKind toModel(dagger.internal.codegen.model.BindingKind bindingKind) {
+ return BindingKind.valueOf(bindingKind.name());
+ }
+
+ private static RequestKind toModel(dagger.internal.codegen.model.RequestKind requestKind) {
+ return RequestKind.valueOf(requestKind.name());
+ }
+
+ private static DependencyRequest toModel(
+ dagger.internal.codegen.model.DependencyRequest request) {
+ DependencyRequest.Builder builder =
+ DependencyRequest.builder()
+ .kind(toModel(request.kind()))
+ .key(toModel(request.key()))
+ .isNullable(request.isNullable());
+
+ request.requestElement().ifPresent(e -> builder.requestElement(e.java()));
+ return builder.build();
+ }
+
+ private static Scope toModel(dagger.internal.codegen.model.Scope scope) {
+ return Scope.scope(scope.scopeAnnotation().java());
+ }
+
+ private static ComponentPath toModel(dagger.internal.codegen.model.ComponentPath path) {
+ return ComponentPath.create(
+ path.components().stream().map(DaggerTypeElement::java).collect(toImmutableList()));
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.ComponentNode toInternal(
+ ComponentNode componentNode) {
+ return ((ComponentNodeImpl) componentNode).delegate();
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.MaybeBinding toInternal(
+ MaybeBinding maybeBinding) {
+ if (maybeBinding instanceof MissingBindingImpl) {
+ return ((MissingBindingImpl) maybeBinding).delegate();
+ } else if (maybeBinding instanceof BindingNodeImpl) {
+ return ((BindingNodeImpl) maybeBinding).delegate();
+ } else {
+ throw new IllegalStateException("Unhandled binding type: " + maybeBinding.getClass());
+ }
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.DependencyEdge toInternal(
+ DependencyEdge dependencyEdge) {
+ return ((DependencyEdgeImpl) dependencyEdge).delegate();
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge toInternal(
+ ChildFactoryMethodEdge childFactoryMethodEdge) {
+ return ((ChildFactoryMethodEdgeImpl) childFactoryMethodEdge).delegate();
+ }
+
+ @AutoValue
+ abstract static class ComponentNodeImpl implements ComponentNode {
+ static ComponentNode create(
+ dagger.internal.codegen.model.BindingGraph.ComponentNode componentNode) {
+ return new AutoValue_ModelBindingGraphConverter_ComponentNodeImpl(
+ toModel(componentNode.componentPath()),
+ componentNode.isSubcomponent(),
+ componentNode.isRealComponent(),
+ componentNode.entryPoints().stream()
+ .map(ModelBindingGraphConverter::toModel)
+ .collect(toImmutableSet()),
+ componentNode.scopes().stream()
+ .map(ModelBindingGraphConverter::toModel)
+ .collect(toImmutableSet()),
+ componentNode);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.ComponentNode delegate();
+
+ @Override
+ public final String toString() {
+ return delegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class BindingNodeImpl implements Binding {
+ static Binding create(dagger.internal.codegen.model.Binding binding) {
+ return new AutoValue_ModelBindingGraphConverter_BindingNodeImpl(
+ toModel(binding.key()),
+ toModel(binding.componentPath()),
+ binding.dependencies().stream()
+ .map(ModelBindingGraphConverter::toModel)
+ .collect(toImmutableSet()),
+ binding.bindingElement().map(DaggerElement::java),
+ binding.contributingModule().map(DaggerTypeElement::java),
+ binding.requiresModuleInstance(),
+ binding.scope().map(ModelBindingGraphConverter::toModel),
+ binding.isNullable(),
+ binding.isProduction(),
+ toModel(binding.kind()),
+ binding);
+ }
+
+ abstract dagger.internal.codegen.model.Binding delegate();
+
+ @Override
+ public final String toString() {
+ return delegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class MissingBindingImpl extends MissingBinding {
+ static MissingBinding create(
+ dagger.internal.codegen.model.BindingGraph.MissingBinding missingBinding) {
+ return new AutoValue_ModelBindingGraphConverter_MissingBindingImpl(
+ toModel(missingBinding.componentPath()), toModel(missingBinding.key()), missingBinding);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.MissingBinding delegate();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
+ }
+
+ @AutoValue
+ abstract static class DependencyEdgeImpl implements DependencyEdge {
+ static DependencyEdge create(
+ dagger.internal.codegen.model.BindingGraph.DependencyEdge dependencyEdge) {
+ return new AutoValue_ModelBindingGraphConverter_DependencyEdgeImpl(
+ toModel(dependencyEdge.dependencyRequest()),
+ dependencyEdge.isEntryPoint(),
+ dependencyEdge);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.DependencyEdge delegate();
+
+ @Override
+ public final String toString() {
+ return delegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
+ static ChildFactoryMethodEdge create(
+ dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge childFactoryMethodEdge) {
+ return new AutoValue_ModelBindingGraphConverter_ChildFactoryMethodEdgeImpl(
+ childFactoryMethodEdge.factoryMethod().java(), childFactoryMethodEdge);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge delegate();
+
+ @Override
+ public final String toString() {
+ return delegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class SubcomponentCreatorBindingEdgeImpl
+ implements SubcomponentCreatorBindingEdge {
+ static SubcomponentCreatorBindingEdge create(
+ dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge
+ subcomponentCreatorBindingEdge) {
+ return new AutoValue_ModelBindingGraphConverter_SubcomponentCreatorBindingEdgeImpl(
+ subcomponentCreatorBindingEdge.declaringModules().stream()
+ .map(DaggerTypeElement::java)
+ .collect(toImmutableSet()),
+ subcomponentCreatorBindingEdge);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge delegate();
+
+ @Override
+ public final String toString() {
+ return delegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class BindingGraphImpl extends BindingGraph {
+ static BindingGraph create(dagger.internal.codegen.model.BindingGraph bindingGraph) {
+ BindingGraphImpl bindingGraphImpl =
+ new AutoValue_ModelBindingGraphConverter_BindingGraphImpl(
+ toModel(bindingGraph.network()), bindingGraph.isFullBindingGraph());
+
+ bindingGraphImpl.componentNodesByPath =
+ bindingGraphImpl.componentNodes().stream()
+ .collect(toImmutableMap(ComponentNode::componentPath, node -> node));
+
+ return bindingGraphImpl;
+ }
+
+ private ImmutableMap<ComponentPath, ComponentNode> componentNodesByPath;
+
+ // This overrides dagger.model.BindingGraph with a more efficient implementation.
+ @Override
+ public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
+ return componentNodesByPath.containsKey(componentPath)
+ ? Optional.of(componentNodesByPath.get(componentPath))
+ : Optional.empty();
+ }
+
+ // This overrides dagger.model.BindingGraph to memoize the output.
+ @Override
+ @Memoized
+ public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
+ return super.nodesByClass();
+ }
+ }
+
+ private static final class DiagnosticReporterImpl implements DiagnosticReporter {
+ static DiagnosticReporterImpl create(
+ dagger.internal.codegen.model.DiagnosticReporter reporter) {
+ return new DiagnosticReporterImpl(reporter);
+ }
+
+ private final dagger.internal.codegen.model.DiagnosticReporter delegate;
+
+ DiagnosticReporterImpl(dagger.internal.codegen.model.DiagnosticReporter delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message) {
+ delegate.reportComponent(diagnosticKind, toInternal(componentNode), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind,
+ ComponentNode componentNode,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportComponent(
+ diagnosticKind, toInternal(componentNode), messageFormat, firstArg, moreArgs);
+ }
+
+ @Override
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
+ delegate.reportBinding(diagnosticKind, toInternal(binding), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind,
+ MaybeBinding binding,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportBinding(
+ diagnosticKind, toInternal(binding), messageFormat, firstArg, moreArgs);
+ }
+
+ @Override
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
+ delegate.reportDependency(diagnosticKind, toInternal(dependencyEdge), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind,
+ DependencyEdge dependencyEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportDependency(
+ diagnosticKind, toInternal(dependencyEdge), messageFormat, firstArg, moreArgs);
+ }
+
+ @Override
+ public void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String message) {
+ delegate.reportSubcomponentFactoryMethod(
+ diagnosticKind, toInternal(childFactoryMethodEdge), message);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ delegate.reportSubcomponentFactoryMethod(
+ diagnosticKind, toInternal(childFactoryMethodEdge), messageFormat, firstArg, moreArgs);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/validation/ModuleValidator.java b/java/dagger/internal/codegen/validation/ModuleValidator.java
index 1e65187..a1d9b0d 100644
--- a/java/dagger/internal/codegen/validation/ModuleValidator.java
+++ b/java/dagger/internal/codegen/validation/ModuleValidator.java
@@ -62,10 +62,10 @@
import dagger.internal.codegen.binding.InjectionAnnotations;
import dagger.internal.codegen.binding.MethodSignatureFormatter;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.xprocessing.XElements;
import dagger.internal.codegen.xprocessing.XTypeElements;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.Scope;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
@@ -537,7 +537,7 @@
private void validateModuleVisibility(
XTypeElement moduleElement, ModuleKind moduleKind, ValidationReport.Builder reportBuilder) {
- if (moduleElement.isPrivate()) {
+ if (moduleElement.isPrivate() || moduleElement.isKtPrivate()) {
reportBuilder.addError("Modules cannot be private.", moduleElement);
} else if (isEffectivelyPrivate(moduleElement)) {
reportBuilder.addError("Modules cannot be enclosed in private types.", moduleElement);
diff --git a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
index 4e7ccda..cf78b63 100644
--- a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
+++ b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen.validation;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableAnnotation;
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING;
import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_CONCRETE;
@@ -29,6 +28,7 @@
import androidx.room.compiler.processing.XType;
import com.google.common.util.concurrent.ListenableFuture;
import dagger.internal.codegen.binding.InjectionAnnotations;
+import dagger.internal.codegen.binding.Nullability;
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.xprocessing.XTypes;
import java.util.Optional;
@@ -89,7 +89,8 @@
*/
// TODO(beder): Properly handle nullable with producer methods.
private void checkNullable() {
- if (getNullableAnnotation(method).isPresent()) {
+ Nullability nullability = Nullability.of(method);
+ if (nullability.nullableAnnotation().isPresent()) {
report.addWarning("@Nullable on @Produces methods does not do anything");
}
}
diff --git a/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java b/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java
new file mode 100644
index 0000000..75d0f7f
--- /dev/null
+++ b/java/dagger/internal/codegen/validation/SpiModelBindingGraphConverter.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.validation;
+
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static androidx.room.compiler.processing.compat.XConverters.toKS;
+import static androidx.room.compiler.processing.compat.XConverters.toKSResolver;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+
+import androidx.room.compiler.processing.XAnnotation;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XExecutableElement;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import dagger.internal.codegen.xprocessing.XElements;
+import dagger.spi.model.Binding;
+import dagger.spi.model.BindingGraph;
+import dagger.spi.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.spi.model.BindingGraph.ComponentNode;
+import dagger.spi.model.BindingGraph.DependencyEdge;
+import dagger.spi.model.BindingGraph.Edge;
+import dagger.spi.model.BindingGraph.MaybeBinding;
+import dagger.spi.model.BindingGraph.MissingBinding;
+import dagger.spi.model.BindingGraph.Node;
+import dagger.spi.model.BindingGraph.SubcomponentCreatorBindingEdge;
+import dagger.spi.model.BindingKind;
+import dagger.spi.model.ComponentPath;
+import dagger.spi.model.DaggerAnnotation;
+import dagger.spi.model.DaggerElement;
+import dagger.spi.model.DaggerExecutableElement;
+import dagger.spi.model.DaggerProcessingEnv;
+import dagger.spi.model.DaggerProcessingEnv.Backend;
+import dagger.spi.model.DaggerType;
+import dagger.spi.model.DaggerTypeElement;
+import dagger.spi.model.DependencyRequest;
+import dagger.spi.model.DiagnosticReporter;
+import dagger.spi.model.Key;
+import dagger.spi.model.RequestKind;
+import dagger.spi.model.Scope;
+import java.util.Optional;
+import javax.tools.Diagnostic;
+
+/** A Utility class for converting to the {@link BindingGraph} used by external plugins. */
+public final class SpiModelBindingGraphConverter {
+ private SpiModelBindingGraphConverter() {}
+
+ public static DiagnosticReporter toSpiModel(
+ dagger.internal.codegen.model.DiagnosticReporter reporter) {
+ return DiagnosticReporterImpl.create(reporter);
+ }
+
+ public static BindingGraph toSpiModel(
+ dagger.internal.codegen.model.BindingGraph graph, XProcessingEnv env) {
+ return BindingGraphImpl.create(graph, env);
+ }
+
+ private static ImmutableNetwork<Node, Edge> toSpiModel(
+ Network<
+ dagger.internal.codegen.model.BindingGraph.Node,
+ dagger.internal.codegen.model.BindingGraph.Edge>
+ internalNetwork,
+ XProcessingEnv env) {
+ MutableNetwork<Node, Edge> network =
+ NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
+
+ ImmutableMap<dagger.internal.codegen.model.BindingGraph.Node, Node> fromInternalNodes =
+ internalNetwork.nodes().stream()
+ .collect(
+ toImmutableMap(
+ node -> node, node -> SpiModelBindingGraphConverter.toSpiModel(node, env)));
+
+ for (Node node : fromInternalNodes.values()) {
+ network.addNode(node);
+ }
+ for (dagger.internal.codegen.model.BindingGraph.Edge edge : internalNetwork.edges()) {
+ EndpointPair<dagger.internal.codegen.model.BindingGraph.Node> edgePair =
+ internalNetwork.incidentNodes(edge);
+ network.addEdge(
+ fromInternalNodes.get(edgePair.source()),
+ fromInternalNodes.get(edgePair.target()),
+ toSpiModel(edge, env));
+ }
+ return ImmutableNetwork.copyOf(network);
+ }
+
+ private static Node toSpiModel(
+ dagger.internal.codegen.model.BindingGraph.Node node, XProcessingEnv env) {
+ if (node instanceof dagger.internal.codegen.model.Binding) {
+ return BindingNodeImpl.create((dagger.internal.codegen.model.Binding) node, env);
+ } else if (node instanceof dagger.internal.codegen.model.BindingGraph.ComponentNode) {
+ return ComponentNodeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.ComponentNode) node, env);
+ } else if (node instanceof dagger.internal.codegen.model.BindingGraph.MissingBinding) {
+ return MissingBindingImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.MissingBinding) node, env);
+ } else {
+ throw new IllegalStateException("Unhandled node type: " + node.getClass());
+ }
+ }
+
+ private static Edge toSpiModel(
+ dagger.internal.codegen.model.BindingGraph.Edge edge, XProcessingEnv env) {
+ if (edge instanceof dagger.internal.codegen.model.BindingGraph.DependencyEdge) {
+ return DependencyEdgeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.DependencyEdge) edge, env);
+ } else if (edge instanceof dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge) {
+ return ChildFactoryMethodEdgeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge) edge, env);
+ } else if (edge
+ instanceof dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge) {
+ return SubcomponentCreatorBindingEdgeImpl.create(
+ (dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge) edge, env);
+ } else {
+ throw new IllegalStateException("Unhandled edge type: " + edge.getClass());
+ }
+ }
+
+ private static Key toSpiModel(dagger.internal.codegen.model.Key key, XProcessingEnv env) {
+ Key.Builder builder =
+ Key.builder(toSpiModel(key.type().xprocessing(), env))
+ .qualifier(key.qualifier().map(qualifier -> toSpiModel(qualifier.xprocessing(), env)));
+ if (key.multibindingContributionIdentifier().isPresent()) {
+ return builder
+ .multibindingContributionIdentifier(
+ toSpiModel(
+ key.multibindingContributionIdentifier().get().contributingModule().xprocessing(),
+ env),
+ toSpiModel(
+ key.multibindingContributionIdentifier().get().bindingMethod().xprocessing(),
+ env))
+ .build();
+ }
+ return builder.build().withoutMultibindingContributionIdentifier();
+ }
+
+ private static BindingKind toSpiModel(dagger.internal.codegen.model.BindingKind bindingKind) {
+ return BindingKind.valueOf(bindingKind.name());
+ }
+
+ private static RequestKind toSpiModel(dagger.internal.codegen.model.RequestKind requestKind) {
+ return RequestKind.valueOf(requestKind.name());
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ private static DependencyRequest toSpiModel(
+ dagger.internal.codegen.model.DependencyRequest request, XProcessingEnv env) {
+ DependencyRequest.Builder builder =
+ DependencyRequest.builder()
+ .kind(toSpiModel(request.kind()))
+ .key(toSpiModel(request.key(), env))
+ .isNullable(request.isNullable());
+
+ request
+ .requestElement()
+ .ifPresent(e -> builder.requestElement(toSpiModel(e.xprocessing(), env)));
+ return builder.build();
+ }
+
+ private static Scope toSpiModel(dagger.internal.codegen.model.Scope scope, XProcessingEnv env) {
+ return Scope.scope(toSpiModel(scope.scopeAnnotation().xprocessing(), env));
+ }
+
+ private static ComponentPath toSpiModel(
+ dagger.internal.codegen.model.ComponentPath path, XProcessingEnv env) {
+ return ComponentPath.create(
+ path.components().stream()
+ .map(component -> toSpiModel(component.xprocessing(), env))
+ .collect(toImmutableList()));
+ }
+
+ private static DaggerTypeElement toSpiModel(XTypeElement typeElement, XProcessingEnv env) {
+ switch (env.getBackend()) {
+ case JAVAC:
+ return DaggerTypeElement.fromJavac(toJavac(typeElement));
+ case KSP:
+ return DaggerTypeElement.fromKsp(toKS(typeElement));
+ }
+ throw new IllegalStateException(
+ String.format("Backend %s is not supported yet.", env.getBackend()));
+ }
+
+ private static DaggerType toSpiModel(XType type, XProcessingEnv env) {
+ switch (env.getBackend()) {
+ case JAVAC:
+ return DaggerType.fromJavac(toJavac(type));
+ case KSP:
+ return DaggerType.fromKsp(toKS(type));
+ }
+ throw new IllegalStateException(
+ String.format("Backend %s is not supported yet.", env.getBackend()));
+ }
+
+ static DaggerAnnotation toSpiModel(XAnnotation annotation, XProcessingEnv env) {
+ DaggerTypeElement typeElement = toSpiModel(annotation.getTypeElement(), env);
+
+ switch (env.getBackend()) {
+ case JAVAC:
+ return DaggerAnnotation.fromJavac(typeElement, toJavac(annotation));
+ case KSP:
+ return DaggerAnnotation.fromKsp(typeElement, toKS(annotation));
+ }
+ throw new IllegalStateException(
+ String.format("Backend %s is not supported yet.", env.getBackend()));
+ }
+
+ private static DaggerElement toSpiModel(XElement element, XProcessingEnv env) {
+ switch (env.getBackend()) {
+ case JAVAC:
+ return DaggerElement.fromJavac(toJavac(element));
+ case KSP:
+ return DaggerElement.fromKsp(XElements.toKSAnnotated(element));
+ }
+ throw new IllegalStateException(
+ String.format("Backend %s is not supported yet.", env.getBackend()));
+ }
+
+ private static DaggerExecutableElement toSpiModel(
+ XExecutableElement executableElement, XProcessingEnv env) {
+ switch (env.getBackend()) {
+ case JAVAC:
+ return DaggerExecutableElement.fromJava(toJavac(executableElement));
+ case KSP:
+ return DaggerExecutableElement.fromKsp(toKS(executableElement));
+ }
+ throw new IllegalStateException(
+ String.format("Backend %s is not supported yet.", env.getBackend()));
+ }
+
+ static DaggerProcessingEnv toSpiModel(XProcessingEnv env) {
+ switch (env.getBackend()) {
+ case JAVAC:
+ return DaggerProcessingEnv.fromJavac(toJavac(env));
+ case KSP:
+ return DaggerProcessingEnv.fromKsp(toKS(env), toKSResolver(env));
+ }
+ throw new IllegalStateException(
+ String.format("Backend %s is not supported yet.", env.getBackend()));
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.ComponentNode toInternal(
+ ComponentNode componentNode) {
+ return ((ComponentNodeImpl) componentNode).internalDelegate();
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.MaybeBinding toInternal(
+ MaybeBinding maybeBinding) {
+ if (maybeBinding instanceof MissingBindingImpl) {
+ return ((MissingBindingImpl) maybeBinding).internalDelegate();
+ } else if (maybeBinding instanceof BindingNodeImpl) {
+ return ((BindingNodeImpl) maybeBinding).internalDelegate();
+ } else {
+ throw new IllegalStateException("Unhandled binding type: " + maybeBinding.getClass());
+ }
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.DependencyEdge toInternal(
+ DependencyEdge dependencyEdge) {
+ return ((DependencyEdgeImpl) dependencyEdge).internalDelegate();
+ }
+
+ private static dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge toInternal(
+ ChildFactoryMethodEdge childFactoryMethodEdge) {
+ return ((ChildFactoryMethodEdgeImpl) childFactoryMethodEdge).internalDelegate();
+ }
+
+ @AutoValue
+ abstract static class ComponentNodeImpl implements ComponentNode {
+ static ComponentNode create(
+ dagger.internal.codegen.model.BindingGraph.ComponentNode componentNode,
+ XProcessingEnv env) {
+ return new AutoValue_SpiModelBindingGraphConverter_ComponentNodeImpl(
+ toSpiModel(componentNode.componentPath(), env),
+ componentNode.isSubcomponent(),
+ componentNode.isRealComponent(),
+ componentNode.entryPoints().stream()
+ .map(request -> SpiModelBindingGraphConverter.toSpiModel(request, env))
+ .collect(toImmutableSet()),
+ componentNode.scopes().stream()
+ .map(request -> SpiModelBindingGraphConverter.toSpiModel(request, env))
+ .collect(toImmutableSet()),
+ componentNode);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.ComponentNode internalDelegate();
+
+ @Override
+ public final String toString() {
+ return internalDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class BindingNodeImpl implements Binding {
+ static Binding create(dagger.internal.codegen.model.Binding binding, XProcessingEnv env) {
+ return new AutoValue_SpiModelBindingGraphConverter_BindingNodeImpl(
+ toSpiModel(binding.key(), env),
+ toSpiModel(binding.componentPath(), env),
+ binding.dependencies().stream()
+ .map(request -> SpiModelBindingGraphConverter.toSpiModel(request, env))
+ .collect(toImmutableSet()),
+ binding.bindingElement().map(element -> toSpiModel(element.xprocessing(), env)),
+ binding.contributingModule().map(module -> toSpiModel(module.xprocessing(), env)),
+ binding.requiresModuleInstance(),
+ binding.scope().map(scope -> SpiModelBindingGraphConverter.toSpiModel(scope, env)),
+ binding.isNullable(),
+ binding.isProduction(),
+ toSpiModel(binding.kind()),
+ binding);
+ }
+
+ abstract dagger.internal.codegen.model.Binding internalDelegate();
+
+ @Override
+ public final String toString() {
+ return internalDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class MissingBindingImpl extends MissingBinding {
+ static MissingBinding create(
+ dagger.internal.codegen.model.BindingGraph.MissingBinding missingBinding,
+ XProcessingEnv env) {
+ return new AutoValue_SpiModelBindingGraphConverter_MissingBindingImpl(
+ toSpiModel(missingBinding.componentPath(), env),
+ toSpiModel(missingBinding.key(), env),
+ missingBinding);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.MissingBinding internalDelegate();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
+ }
+
+ @AutoValue
+ abstract static class DependencyEdgeImpl implements DependencyEdge {
+ static DependencyEdge create(
+ dagger.internal.codegen.model.BindingGraph.DependencyEdge dependencyEdge,
+ XProcessingEnv env) {
+ return new AutoValue_SpiModelBindingGraphConverter_DependencyEdgeImpl(
+ toSpiModel(dependencyEdge.dependencyRequest(), env),
+ dependencyEdge.isEntryPoint(),
+ dependencyEdge);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.DependencyEdge internalDelegate();
+
+ @Override
+ public final String toString() {
+ return internalDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
+ static ChildFactoryMethodEdge create(
+ dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge childFactoryMethodEdge,
+ XProcessingEnv env) {
+ return new AutoValue_SpiModelBindingGraphConverter_ChildFactoryMethodEdgeImpl(
+ toSpiModel(childFactoryMethodEdge.factoryMethod().xprocessing(), env),
+ childFactoryMethodEdge);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.ChildFactoryMethodEdge internalDelegate();
+
+ @Override
+ public final String toString() {
+ return internalDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class SubcomponentCreatorBindingEdgeImpl
+ implements SubcomponentCreatorBindingEdge {
+ static SubcomponentCreatorBindingEdge create(
+ dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge
+ subcomponentCreatorBindingEdge,
+ XProcessingEnv env) {
+ return new AutoValue_SpiModelBindingGraphConverter_SubcomponentCreatorBindingEdgeImpl(
+ subcomponentCreatorBindingEdge.declaringModules().stream()
+ .map(module -> toSpiModel(module.xprocessing(), env))
+ .collect(toImmutableSet()),
+ subcomponentCreatorBindingEdge);
+ }
+
+ abstract dagger.internal.codegen.model.BindingGraph.SubcomponentCreatorBindingEdge
+ internalDelegate();
+
+ @Override
+ public final String toString() {
+ return internalDelegate().toString();
+ }
+ }
+
+ @AutoValue
+ abstract static class BindingGraphImpl extends BindingGraph {
+ static BindingGraph create(
+ dagger.internal.codegen.model.BindingGraph bindingGraph, XProcessingEnv env) {
+ BindingGraphImpl bindingGraphImpl =
+ new AutoValue_SpiModelBindingGraphConverter_BindingGraphImpl(
+ toSpiModel(bindingGraph.network(), env),
+ bindingGraph.isFullBindingGraph(),
+ Backend.valueOf(env.getBackend().name()));
+
+ bindingGraphImpl.componentNodesByPath =
+ bindingGraphImpl.componentNodes().stream()
+ .collect(toImmutableMap(ComponentNode::componentPath, node -> node));
+
+ return bindingGraphImpl;
+ }
+
+ private ImmutableMap<ComponentPath, ComponentNode> componentNodesByPath;
+
+ // This overrides dagger.model.BindingGraph with a more efficient implementation.
+ @Override
+ public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
+ return componentNodesByPath.containsKey(componentPath)
+ ? Optional.of(componentNodesByPath.get(componentPath))
+ : Optional.empty();
+ }
+
+ // This overrides dagger.model.BindingGraph to memoize the output.
+ @Override
+ @Memoized
+ public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
+ return super.nodesByClass();
+ }
+ }
+
+ private static final class DiagnosticReporterImpl extends DiagnosticReporter {
+ static DiagnosticReporterImpl create(
+ dagger.internal.codegen.model.DiagnosticReporter reporter) {
+ return new DiagnosticReporterImpl(reporter);
+ }
+
+ private final dagger.internal.codegen.model.DiagnosticReporter delegate;
+
+ DiagnosticReporterImpl(dagger.internal.codegen.model.DiagnosticReporter delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String message) {
+ delegate.reportComponent(diagnosticKind, toInternal(componentNode), message);
+ }
+
+ @Override
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
+ delegate.reportBinding(diagnosticKind, toInternal(binding), message);
+ }
+
+ @Override
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
+ delegate.reportDependency(diagnosticKind, toInternal(dependencyEdge), message);
+ }
+
+ @Override
+ public void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String message) {
+ delegate.reportSubcomponentFactoryMethod(
+ diagnosticKind, toInternal(childFactoryMethodEdge), message);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/validation/Validation.java b/java/dagger/internal/codegen/validation/Validation.java
index 6d73151..3f9fcc7 100644
--- a/java/dagger/internal/codegen/validation/Validation.java
+++ b/java/dagger/internal/codegen/validation/Validation.java
@@ -22,8 +22,8 @@
import javax.inject.Qualifier;
/**
- * Qualifier annotation for the {@link dagger.spi.model.BindingGraphPlugin}s that are used to
- * implement core Dagger validation.
+ * Qualifier annotation for the {@link dagger.internal.codegen.model.BindingGraphPlugin}s that are
+ * used to implement core Dagger validation.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugin.java b/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugin.java
index e431069..b64d580 100644
--- a/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugin.java
+++ b/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugin.java
@@ -17,10 +17,10 @@
package dagger.internal.codegen.validation;
import com.google.common.base.Preconditions;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraph.ComponentNode;
-import dagger.spi.model.BindingGraphPlugin;
-import dagger.spi.model.DiagnosticReporter;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraph.ComponentNode;
+import dagger.internal.codegen.model.BindingGraphPlugin;
+import dagger.internal.codegen.model.DiagnosticReporter;
import java.util.HashSet;
import java.util.Set;
diff --git a/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java b/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java
index 9e2bbf4..dd22852 100644
--- a/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java
+++ b/java/dagger/internal/codegen/validation/ValidationBindingGraphPlugins.java
@@ -28,10 +28,10 @@
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ProcessingOptions;
import dagger.internal.codegen.compileroption.ValidationType;
+import dagger.internal.codegen.model.BindingGraph;
+import dagger.internal.codegen.model.BindingGraphPlugin;
+import dagger.internal.codegen.model.DaggerProcessingEnv;
import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
-import dagger.spi.model.BindingGraph;
-import dagger.spi.model.BindingGraphPlugin;
-import dagger.spi.model.DaggerProcessingEnv;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java b/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
index 7256fd6..43811af 100644
--- a/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
@@ -19,7 +19,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.javapoet.CodeBlocks.anonymousProvider;
-import static dagger.spi.model.RequestKind.INSTANCE;
+import static dagger.internal.codegen.model.RequestKind.INSTANCE;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
index cda0a0c..93a8ce5 100644
--- a/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/AssistedFactoryRequestRepresentation.java
@@ -38,7 +38,7 @@
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.Optional;
/**
diff --git a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
index 308b4b1..42551a0 100644
--- a/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
+++ b/java/dagger/internal/codegen/writing/AssistedInjectionParameters.java
@@ -32,8 +32,8 @@
import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata;
import dagger.internal.codegen.binding.Binding;
+import dagger.internal.codegen.model.BindingKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
import java.util.List;
/** Utility class for generating unique assisted parameter names for a component shard. */
diff --git a/java/dagger/internal/codegen/writing/BUILD b/java/dagger/internal/codegen/writing/BUILD
index c99a253..c8f9b61 100644
--- a/java/dagger/internal/codegen/writing/BUILD
+++ b/java/dagger/internal/codegen/writing/BUILD
@@ -33,9 +33,9 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/xprocessing",
"//java/dagger/producers",
- "//java/dagger/spi",
"//third_party/java/auto:common",
"//third_party/java/auto:value",
"//third_party/java/error_prone:annotations",
diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java
index e4028dd..204d6fa 100644
--- a/java/dagger/internal/codegen/writing/ComponentImplementation.java
+++ b/java/dagger/internal/codegen/writing/ComponentImplementation.java
@@ -84,10 +84,10 @@
import dagger.internal.codegen.javapoet.TypeNames;
import dagger.internal.codegen.javapoet.TypeSpecs;
import dagger.internal.codegen.langmodel.Accessibility;
+import dagger.internal.codegen.model.BindingGraph.Node;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.xprocessing.XTypeElements;
-import dagger.spi.model.BindingGraph.Node;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
diff --git a/java/dagger/internal/codegen/writing/ComponentNames.java b/java/dagger/internal/codegen/writing/ComponentNames.java
index 8101037..b5f2f2f 100644
--- a/java/dagger/internal/codegen/writing/ComponentNames.java
+++ b/java/dagger/internal/codegen/writing/ComponentNames.java
@@ -36,8 +36,8 @@
import dagger.internal.codegen.binding.ComponentDescriptor;
import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.spi.model.ComponentPath;
-import dagger.spi.model.Key;
+import dagger.internal.codegen.model.ComponentPath;
+import dagger.internal.codegen.model.Key;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
diff --git a/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java b/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
index cfe6deb..124eba1 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequestRepresentations.java
@@ -47,8 +47,8 @@
import dagger.internal.codegen.binding.ProductionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.RequestKind;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java b/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
index cdfdf26..cb442d4 100644
--- a/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
+++ b/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
@@ -23,8 +23,8 @@
/**
* A factory for expressions of {@link ComponentRequirement}s in the generated component. This is
* <em>not</em> a {@link RequestRepresentation}, since {@link ComponentRequirement}s do not have a
- * {@link dagger.spi.model.Key}. See {@link ComponentRequirementRequestRepresentation} for binding
- * expressions that are themselves a component requirement.
+ * {@link dagger.internal.codegen.model.Key}. See {@link ComponentRequirementRequestRepresentation}
+ * for binding expressions that are themselves a component requirement.
*/
interface ComponentRequirementExpression {
/**
diff --git a/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java b/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
index 777bdff..673a659 100644
--- a/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DelegateRequestRepresentation.java
@@ -22,7 +22,7 @@
import static dagger.internal.codegen.base.RequestKinds.requestType;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.spi.model.BindingKind.DELEGATE;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
@@ -36,7 +36,7 @@
import dagger.internal.codegen.binding.BindsTypeChecker;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.Expression;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.RequestKind;
/** A {@link dagger.internal.codegen.writing.RequestRepresentation} for {@code @Binds} methods. */
final class DelegateRequestRepresentation extends RequestRepresentation {
diff --git a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
index 096d109..1fbb2cb 100644
--- a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
@@ -27,8 +27,8 @@
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.spi.model.DependencyRequest;
/** A framework instance creation expression for a {@link dagger.Binds @Binds} binding. */
final class DelegatingFrameworkInstanceCreationExpression
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
index 339aeca..49cc024 100644
--- a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
@@ -47,6 +47,7 @@
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.xprocessing.XAnnotations;
/**
* A {@link javax.inject.Provider} creation expression for a provision method on a component's
@@ -102,9 +103,12 @@
.addModifiers(PUBLIC)
.returns(keyType)
.addStatement("return $L", invocation);
- if (binding.nullableType().isPresent()) {
- getMethod.addAnnotation(binding.nullableType().get().getTypeElement().getClassName());
- }
+
+ binding
+ .nullability()
+ .nullableAnnotation()
+ .map(XAnnotations::getClassName)
+ .ifPresent(getMethod::addAnnotation);
// We need to use the componentShard here since the generated type is static and shards are
// not static classes so it can't be nested inside the shard.
diff --git a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
index 4da3df1..4095a60 100644
--- a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceRequestRepresentation.java
@@ -29,8 +29,8 @@
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.Expression;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.RequestKind;
/** A binding expression that depends on a framework instance. */
final class DerivedFromFrameworkInstanceRequestRepresentation extends RequestRepresentation {
diff --git a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
index 2ac3888..1eb4249 100644
--- a/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/DirectInstanceBindingRepresentation.java
@@ -26,8 +26,8 @@
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.RequestKind;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java
index c66204a..1ebbb24 100644
--- a/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviderDependencyRepresentation.java
@@ -33,10 +33,10 @@
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.RequestKind;
/**
* Returns type casted expressions to satisfy dependency requests from experimental switching
diff --git a/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java
index 8bb0ec4..586b5f5 100644
--- a/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java
+++ b/java/dagger/internal/codegen/writing/ExperimentalSwitchingProviders.java
@@ -40,9 +40,9 @@
import com.squareup.javapoet.TypeVariableName;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.spi.model.Key;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/writing/FactoryGenerator.java b/java/dagger/internal/codegen/writing/FactoryGenerator.java
index 015ffd4..9ec1314 100644
--- a/java/dagger/internal/codegen/writing/FactoryGenerator.java
+++ b/java/dagger/internal/codegen/writing/FactoryGenerator.java
@@ -32,10 +32,10 @@
import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
import static dagger.internal.codegen.javapoet.TypeNames.factoryOf;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.PROVISION;
import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static dagger.spi.model.BindingKind.INJECTION;
-import static dagger.spi.model.BindingKind.PROVISION;
import static javax.lang.model.element.Modifier.FINAL;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.PUBLIC;
@@ -44,8 +44,6 @@
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XFiler;
import androidx.room.compiler.processing.XProcessingEnv;
-import androidx.room.compiler.processing.XType;
-import androidx.room.compiler.processing.XTypeElement;
import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -66,13 +64,14 @@
import dagger.internal.codegen.binding.SourceFiles;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.Scope;
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.Scope;
+import dagger.internal.codegen.xprocessing.XAnnotations;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
@@ -270,9 +269,9 @@
if (binding.kind().equals(PROVISION)) {
binding
- .nullableType()
- .map(XType::getTypeElement)
- .map(XTypeElement::getClassName)
+ .nullability()
+ .nullableAnnotation()
+ .map(XAnnotations::getClassName)
.ifPresent(getMethod::addAnnotation);
getMethod.addStatement("return $L", invokeNewInstance);
} else if (!binding.injectionSites().isEmpty()) {
diff --git a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
index c1ae77c..5a98177 100644
--- a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
+++ b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
@@ -34,8 +34,8 @@
import dagger.internal.codegen.binding.FrameworkField;
import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.BindingKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.BindingKind;
import java.util.Optional;
/**
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
index 1e1517c..bb62d52 100644
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingRepresentation.java
@@ -18,8 +18,8 @@
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
import static dagger.internal.codegen.writing.ProvisionBindingRepresentation.needsCaching;
-import static dagger.spi.model.BindingKind.DELEGATE;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
@@ -28,7 +28,7 @@
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.RequestKind;
import java.util.HashMap;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java b/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java
index 8bceddc..1353e88 100644
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java
+++ b/java/dagger/internal/codegen/writing/FrameworkInstanceKind.java
@@ -16,11 +16,11 @@
package dagger.internal.codegen.writing;
-import static dagger.spi.model.BindingKind.DELEGATE;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
import dagger.internal.codegen.binding.ContributionBinding;
+import dagger.internal.codegen.model.BindingKind;
import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
-import dagger.spi.model.BindingKind;
/** Generation mode for satisfying framework request to Provision Binding. */
enum FrameworkInstanceKind {
diff --git a/java/dagger/internal/codegen/writing/InjectionMethods.java b/java/dagger/internal/codegen/writing/InjectionMethods.java
index 13ca2c9..75b950a 100644
--- a/java/dagger/internal/codegen/writing/InjectionMethods.java
+++ b/java/dagger/internal/codegen/writing/InjectionMethods.java
@@ -24,7 +24,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.squareup.javapoet.MethodSpec.methodBuilder;
import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
import static dagger.internal.codegen.binding.SourceFiles.memberInjectedFieldSignatureForVariable;
import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
@@ -71,13 +70,14 @@
import dagger.internal.Preconditions;
import dagger.internal.codegen.base.UniqueNameSet;
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.binding.Nullability;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.extension.DaggerCollectors;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.xprocessing.XAnnotations;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DependencyRequest;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
@@ -406,9 +406,9 @@
if (isVoid(method.getReturnType())) {
return builder.addStatement("$L", invocation).build();
} else {
- getNullableType(method)
- .map(XType::getTypeElement)
- .map(XTypeElement::getClassName)
+ Nullability.of(method)
+ .nullableAnnotation()
+ .map(XAnnotations::getClassName)
.ifPresent(builder::addAnnotation);
return builder
.returns(method.getReturnType().getTypeName())
diff --git a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
index b9bc70b..d32531b 100644
--- a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
@@ -18,7 +18,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.spi.model.BindingKind.INJECTION;
+import static dagger.internal.codegen.model.BindingKind.INJECTION;
import com.squareup.javapoet.CodeBlock;
import dagger.assisted.Assisted;
diff --git a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
index a326e0a..1f857db 100644
--- a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
@@ -31,7 +31,7 @@
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.stream.Stream;
/** A factory creation expression for a multibound map. */
diff --git a/java/dagger/internal/codegen/writing/MapRequestRepresentation.java b/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
index cf14aab..bb49ebe 100644
--- a/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/MapRequestRepresentation.java
@@ -22,8 +22,8 @@
import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression;
import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
@@ -41,8 +41,8 @@
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.Collections;
/** A {@link RequestRepresentation} for multibound maps. */
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java b/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java
index cfad745..a1cde64 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectionBindingRepresentation.java
@@ -23,7 +23,7 @@
import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.RequestKind;
/**
* A binding representation that wraps code generation methods that satisfy all kinds of request for
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
index 38707dc..bac7490 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
@@ -41,9 +41,9 @@
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.spi.model.Key;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
index 9c65a45..82d12dd 100644
--- a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
+++ b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
@@ -61,10 +61,10 @@
import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
import dagger.internal.codegen.binding.SourceFiles;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DaggerAnnotation;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
import java.util.Map.Entry;
import javax.inject.Inject;
diff --git a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
index 97fecae..5cb47bb 100644
--- a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
@@ -22,9 +22,9 @@
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.spi.model.DependencyRequest;
/** An abstract factory creation expression for multibindings. */
abstract class MultibindingFactoryCreationExpression
diff --git a/java/dagger/internal/codegen/writing/OptionalFactories.java b/java/dagger/internal/codegen/writing/OptionalFactories.java
index 43677b4..deb9dbf 100644
--- a/java/dagger/internal/codegen/writing/OptionalFactories.java
+++ b/java/dagger/internal/codegen/writing/OptionalFactories.java
@@ -61,9 +61,9 @@
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.RequestKind;
import dagger.producers.Producer;
import dagger.producers.internal.Producers;
-import dagger.spi.model.RequestKind;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;
diff --git a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
index df9d15e..2f2ae58 100644
--- a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
@@ -27,8 +27,8 @@
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
/**
- * A {@link FrameworkInstanceCreationExpression} for {@link dagger.spi.model.BindingKind#OPTIONAL
- * optional bindings}.
+ * A {@link FrameworkInstanceCreationExpression} for {@link
+ * dagger.internal.codegen.model.BindingKind#OPTIONAL optional bindings}.
*/
final class OptionalFactoryInstanceCreationExpression
implements FrameworkInstanceCreationExpression {
diff --git a/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java b/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
index 28d0495..b775314 100644
--- a/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/OptionalRequestRepresentation.java
@@ -32,7 +32,7 @@
import dagger.internal.codegen.base.OptionalType.OptionalKind;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.javapoet.Expression;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
/** A binding expression for optional bindings. */
final class OptionalRequestRepresentation extends RequestRepresentation {
diff --git a/java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java b/java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java
index a1de5fb..fe973dc 100644
--- a/java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/PrivateMethodRequestRepresentation.java
@@ -35,8 +35,8 @@
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.ExpressionType;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
-import dagger.spi.model.RequestKind;
/**
* A binding expression that wraps the dependency expressions in a private, no-arg method.
diff --git a/java/dagger/internal/codegen/writing/ProducerEntryPointView.java b/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
index 752bc19..648e253 100644
--- a/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
+++ b/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
@@ -29,11 +29,11 @@
import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.producers.Producer;
import dagger.producers.internal.CancellationListener;
import dagger.producers.internal.Producers;
-import dagger.spi.model.RequestKind;
import java.util.Optional;
/**
diff --git a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
index 05b2a21..e6c88a9 100644
--- a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
+++ b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
@@ -74,12 +74,12 @@
import dagger.internal.codegen.javapoet.AnnotationSpecs;
import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.DependencyRequest;
+import dagger.internal.codegen.model.Key;
+import dagger.internal.codegen.model.RequestKind;
import dagger.producers.Producer;
import dagger.producers.internal.AbstractProducesMethodProducer;
import dagger.producers.internal.Producers;
-import dagger.spi.model.DependencyRequest;
-import dagger.spi.model.Key;
-import dagger.spi.model.RequestKind;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
diff --git a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
index d385613..05dd50b 100644
--- a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
@@ -24,9 +24,9 @@
import dagger.assisted.AssistedInject;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
import dagger.producers.Producer;
-import dagger.spi.model.RequestKind;
import java.util.Optional;
/** An {@link Producer} creation expression for provision bindings. */
diff --git a/java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java b/java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java
index 186b159..813010c 100644
--- a/java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProducerNodeInstanceRequestRepresentation.java
@@ -26,9 +26,9 @@
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.producers.internal.Producers;
-import dagger.spi.model.Key;
/** Binding expression for producer node instances. */
final class ProducerNodeInstanceRequestRepresentation
diff --git a/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
index 1e5fa6c..0793d6e 100644
--- a/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProductionBindingRepresentation.java
@@ -17,8 +17,8 @@
package dagger.internal.codegen.writing;
import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_SET;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
diff --git a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
index faed99e..4ae7f37 100644
--- a/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
+++ b/java/dagger/internal/codegen/writing/ProvisionBindingRepresentation.java
@@ -16,8 +16,8 @@
package dagger.internal.codegen.writing;
+import static dagger.internal.codegen.model.BindingKind.DELEGATE;
import static dagger.internal.codegen.writing.DelegateRequestRepresentation.isBindsScopeStrongerThanDependencyScope;
-import static dagger.spi.model.BindingKind.DELEGATE;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
@@ -26,8 +26,8 @@
import dagger.internal.codegen.binding.BindingRequest;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
+import dagger.internal.codegen.model.RequestKind;
import dagger.internal.codegen.writing.ComponentImplementation.CompilerMode;
-import dagger.spi.model.RequestKind;
/**
* A binding representation that wraps code generation methods that satisfy all kinds of request for
diff --git a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
index 624a412..559bb7d 100644
--- a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
+++ b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
@@ -29,7 +29,7 @@
import dagger.internal.codegen.binding.BindingType;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
/** A factory creation expression for a multibound set. */
final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpression {
diff --git a/java/dagger/internal/codegen/writing/SetRequestRepresentation.java b/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
index 5c842a2..f5d77ad 100644
--- a/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/SetRequestRepresentation.java
@@ -38,7 +38,7 @@
import dagger.internal.codegen.javapoet.CodeBlocks;
import dagger.internal.codegen.javapoet.Expression;
import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.spi.model.DependencyRequest;
+import dagger.internal.codegen.model.DependencyRequest;
import java.util.Collections;
/** A binding expression for multibound sets. */
diff --git a/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java b/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
index 0ac9bfd..4026f16 100644
--- a/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
+++ b/java/dagger/internal/codegen/writing/SimpleMethodRequestRepresentation.java
@@ -41,14 +41,14 @@
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.model.DependencyRequest;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
-import dagger.spi.model.DependencyRequest;
import java.util.Optional;
/**
* A binding expression that invokes methods or constructors directly (without attempting to scope)
- * {@link dagger.spi.model.RequestKind#INSTANCE} requests.
+ * {@link dagger.internal.codegen.model.RequestKind#INSTANCE} requests.
*/
final class SimpleMethodRequestRepresentation extends RequestRepresentation {
private final CompilerOptions compilerOptions;
diff --git a/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java b/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
index 5537c8f..070cd63 100644
--- a/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
+++ b/java/dagger/internal/codegen/writing/StaticFactoryInstanceSupplier.java
@@ -16,8 +16,8 @@
package dagger.internal.codegen.writing;
-import static dagger.spi.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.spi.model.BindingKind.MULTIBOUND_SET;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.internal.codegen.model.BindingKind.MULTIBOUND_SET;
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
diff --git a/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java b/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
index 839d136..7bea206 100644
--- a/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
+++ b/java/dagger/internal/codegen/writing/SwitchingProviderInstanceSupplier.java
@@ -26,9 +26,9 @@
import dagger.internal.codegen.binding.Binding;
import dagger.internal.codegen.binding.BindingGraph;
import dagger.internal.codegen.binding.ProvisionBinding;
+import dagger.internal.codegen.model.BindingKind;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.spi.model.BindingKind;
/**
* An object that initializes a framework-type component field for a binding using instances created
diff --git a/java/dagger/internal/codegen/writing/SwitchingProviders.java b/java/dagger/internal/codegen/writing/SwitchingProviders.java
index dc6ec94..e6c3bbf 100644
--- a/java/dagger/internal/codegen/writing/SwitchingProviders.java
+++ b/java/dagger/internal/codegen/writing/SwitchingProviders.java
@@ -41,11 +41,11 @@
import com.squareup.javapoet.TypeVariableName;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.model.BindingKind;
+import dagger.internal.codegen.model.Key;
import dagger.internal.codegen.writing.ComponentImplementation.ShardImplementation;
import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
import dagger.internal.codegen.xprocessing.XProcessingEnvs;
-import dagger.spi.model.BindingKind;
-import dagger.spi.model.Key;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
diff --git a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
index 28c2370..cf4f260 100644
--- a/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
+++ b/java/dagger/internal/codegen/writing/UnscopedDirectInstanceRequestRepresentationFactory.java
@@ -19,7 +19,7 @@
import dagger.internal.codegen.binding.ComponentRequirement;
import dagger.internal.codegen.binding.ContributionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.spi.model.RequestKind;
+import dagger.internal.codegen.model.RequestKind;
import javax.inject.Inject;
/**
diff --git a/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java b/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
index 5f37625..36807c2 100644
--- a/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
+++ b/java/dagger/internal/codegen/writing/UnscopedFrameworkInstanceCreationExpressionFactory.java
@@ -156,7 +156,7 @@
private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
ContributionBinding binding, ComponentRequirement componentRequirement) {
return new InstanceFactoryCreationExpression(
- binding.nullableType().isPresent(),
+ binding.isNullable(),
() ->
componentRequirementExpressions.getExpressionDuringInitialization(
componentRequirement, componentImplementation.name()));
diff --git a/java/dagger/internal/codegen/xprocessing/BUILD b/java/dagger/internal/codegen/xprocessing/BUILD
index b798835..262be17 100644
--- a/java/dagger/internal/codegen/xprocessing/BUILD
+++ b/java/dagger/internal/codegen/xprocessing/BUILD
@@ -34,7 +34,9 @@
"//third_party/java/guava/base",
"//third_party/java/guava/collect",
"//third_party/java/javapoet",
+ "//third_party/java/jsr305_annotations",
"//third_party/kotlin/kotlinpoet",
+ "@maven//:com_google_devtools_ksp_symbol_processing_api",
"@maven//:org_jetbrains_kotlin_kotlin_stdlib",
],
)
diff --git a/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java b/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java
index 7a081fa..b28d9c0 100644
--- a/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java
+++ b/java/dagger/internal/codegen/xprocessing/JavaPoetExt.java
@@ -18,8 +18,10 @@
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
+import androidx.room.compiler.processing.XExecutableParameterElement;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
+import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;
// TODO(bcorso): Consider moving these methods into XProcessing library.
@@ -47,5 +49,10 @@
return builder;
}
+ public static ParameterSpec toParameterSpec(XExecutableParameterElement param) {
+ return ParameterSpec.builder(param.getType().getTypeName(), XElements.getSimpleName(param))
+ .build();
+ }
+
private JavaPoetExt() {}
}
diff --git a/java/dagger/internal/codegen/xprocessing/XAnnotations.java b/java/dagger/internal/codegen/xprocessing/XAnnotations.java
index 98f4dfc..f75fab2 100644
--- a/java/dagger/internal/codegen/xprocessing/XAnnotations.java
+++ b/java/dagger/internal/codegen/xprocessing/XAnnotations.java
@@ -18,13 +18,17 @@
import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static java.util.stream.Collectors.joining;
import androidx.room.compiler.processing.JavaPoetExtKt;
import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import androidx.room.compiler.processing.XTypeElement;
import com.google.auto.common.AnnotationMirrors;
import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import java.util.Arrays;
@@ -35,7 +39,7 @@
/** Returns the {@link AnnotationSpec} for the given annotation */
public static AnnotationSpec getAnnotationSpec(XAnnotation annotation) {
- return JavaPoetExtKt.toAnnotationSpec(annotation);
+ return JavaPoetExtKt.toAnnotationSpec(annotation, false);
}
/** Returns the string representation of the given annotation. */
@@ -101,12 +105,6 @@
if (annotation.getType().isError()) {
return "@" + annotation.getName(); // SUPPRESS_GET_NAME_CHECK
}
- // TODO(b/264089557): Non-annotation elements can be incorrectly treated as annotation in KSP,
- // therefore calling getAnnotationValues() can cause confusing error.
- if (getProcessingEnv(annotation).getBackend() == XProcessingEnv.Backend.KSP
- && annotation.getTypeElement().getConstructors().size() != 1) {
- return String.format("@%s", getClassName(annotation).canonicalName());
- }
return annotation.getAnnotationValues().isEmpty()
// If the annotation doesn't have values then skip the empty parenthesis.
? String.format("@%s", getClassName(annotation).canonicalName())
@@ -132,5 +130,18 @@
}
}
+ /** Returns the value of the given [key] as a type element. */
+ public static XTypeElement getAsTypeElement(XAnnotation annotation, String key) {
+ return annotation.getAsType(key).getTypeElement();
+ }
+
+ /** Returns the value of the given [key] as a list of type elements. */
+ public static ImmutableList<XTypeElement> getAsTypeElementList(
+ XAnnotation annotation, String key) {
+ return annotation.getAsTypeList(key).stream()
+ .map(XType::getTypeElement)
+ .collect(toImmutableList());
+ }
+
private XAnnotations() {}
}
diff --git a/java/dagger/internal/codegen/xprocessing/XElements.java b/java/dagger/internal/codegen/xprocessing/XElements.java
index 53404f8..552be65 100644
--- a/java/dagger/internal/codegen/xprocessing/XElements.java
+++ b/java/dagger/internal/codegen/xprocessing/XElements.java
@@ -22,70 +22,38 @@
import static androidx.room.compiler.processing.XElementKt.isMethodParameter;
import static androidx.room.compiler.processing.XElementKt.isTypeElement;
import static androidx.room.compiler.processing.XElementKt.isVariableElement;
-import static androidx.room.compiler.processing.XTypeKt.isArray;
-import static androidx.room.compiler.processing.XTypeKt.isByte;
-import static androidx.room.compiler.processing.XTypeKt.isInt;
-import static androidx.room.compiler.processing.XTypeKt.isKotlinUnit;
-import static androidx.room.compiler.processing.XTypeKt.isLong;
-import static androidx.room.compiler.processing.XTypeKt.isVoid;
-import static androidx.room.compiler.processing.XTypeKt.isVoidObject;
import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.isType;
+import static androidx.room.compiler.processing.compat.XConverters.toKS;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
-import static dagger.internal.codegen.xprocessing.XTypeElements.isNested;
-import static dagger.internal.codegen.xprocessing.XTypes.isBoolean;
-import static dagger.internal.codegen.xprocessing.XTypes.isChar;
-import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
-import static dagger.internal.codegen.xprocessing.XTypes.isDouble;
-import static dagger.internal.codegen.xprocessing.XTypes.isFloat;
-import static dagger.internal.codegen.xprocessing.XTypes.isShort;
-import static dagger.internal.codegen.xprocessing.XTypes.isTypeVariable;
-import static dagger.internal.codegen.xprocessing.XTypes.isWildcard;
import static java.util.stream.Collectors.joining;
import androidx.room.compiler.processing.XAnnotated;
import androidx.room.compiler.processing.XAnnotation;
-import androidx.room.compiler.processing.XArrayType;
import androidx.room.compiler.processing.XConstructorElement;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XEnumEntry;
import androidx.room.compiler.processing.XEnumTypeElement;
import androidx.room.compiler.processing.XExecutableElement;
import androidx.room.compiler.processing.XExecutableParameterElement;
-import androidx.room.compiler.processing.XExecutableType;
import androidx.room.compiler.processing.XFieldElement;
import androidx.room.compiler.processing.XHasModifiers;
import androidx.room.compiler.processing.XMemberContainer;
import androidx.room.compiler.processing.XMethodElement;
-import androidx.room.compiler.processing.XMethodType;
import androidx.room.compiler.processing.XProcessingEnv;
-import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
import androidx.room.compiler.processing.XTypeParameterElement;
import androidx.room.compiler.processing.XVariableElement;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.ksp.symbol.KSAnnotated;
import com.squareup.javapoet.ClassName;
import java.util.Collection;
import java.util.Optional;
-import javax.lang.model.element.Element;
+import javax.annotation.Nullable;
import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ErrorType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.IntersectionType;
-import javax.lang.model.type.NoType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.SimpleTypeVisitor8;
// TODO(bcorso): Consider moving these methods into XProcessing library.
/** A utility class for {@link XElement} helper methods. */
@@ -126,9 +94,43 @@
throw new AssertionError("No simple name for: " + element);
}
+ private static boolean isSyntheticElement(XElement element) {
+ if (isMethodParameter(element)) {
+ XExecutableParameterElement executableParam = asMethodParameter(element);
+ return executableParam.isContinuationParam()
+ || executableParam.isReceiverParam()
+ || executableParam.isKotlinPropertyParam();
+ }
+ if (isMethod(element)) {
+ return asMethod(element).isKotlinPropertyMethod();
+ }
+ return false;
+ }
+
+ @Nullable
+ public static KSAnnotated toKSAnnotated(XElement element) {
+ if (isSyntheticElement(element)) {
+ return toKS(element);
+ }
+ if (isExecutable(element)) {
+ return toKS(asExecutable(element));
+ }
+ if (isTypeElement(element)) {
+ return toKS(asTypeElement(element));
+ }
+ if (isField(element)) {
+ return toKS(asField(element));
+ }
+ if (isMethodParameter(element)) {
+ return toKS(asMethodParameter(element));
+ }
+ throw new IllegalStateException(
+ "Returning KSAnnotated declaration for " + element + " is not supported.");
+ }
+
/**
* Returns the closest enclosing element that is a {@link XTypeElement} or throws an {@link
- * IllegalStateException} if one doesn't exists.
+ * IllegalStateException} if one doesn't exist.
*/
public static XTypeElement closestEnclosingTypeElement(XElement element) {
return optionalClosestEnclosingTypeElement(element)
@@ -313,216 +315,13 @@
}
/**
- * Returns the field descriptor of the given {@code element}.
- *
- * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.2">JVM
- * specification, section 4.3.2</a>.
- */
- public static String getFieldDescriptor(XFieldElement element) {
- return getSimpleName(element) + ":" + getDescriptor(element.getType());
- }
-
- /**
- * Returns the method descriptor of the given {@code element}.
- *
- * <p>This is useful for matching Kotlin Metadata JVM Signatures with elements from the AST.
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3">JVM
- * specification, section 4.3.3</a>.
- */
- // TODO(bcorso): Expose getMethodDescriptor() method in XProcessing instead.
- public static String getMethodDescriptor(XMethodElement element) {
- return getSimpleName(element) + getDescriptor(element.getExecutableType());
- }
-
- private static String getDescriptor(XExecutableType type) {
- String parameterDescriptors =
- type.getParameterTypes().stream().map(XElements::getDescriptor).collect(joining());
- String returnDescriptor =
- XTypes.isMethod(type) ? getDescriptor(((XMethodType) type).getReturnType()) : "V";
- return "(" + parameterDescriptors + ")" + returnDescriptor;
- }
-
- private static String getDescriptor(XType type) {
- XProcessingEnv processingEnv = getProcessingEnv(type);
- switch (processingEnv.getBackend()) {
- case JAVAC:
- return javacGetDescriptor(toJavac(type));
- case KSP:
- return kspGetDescriptor(type);
- }
- throw new AssertionError("Unexpected backend: " + processingEnv.getBackend());
- }
-
- private static String kspGetDescriptor(XType type) {
- if (isKotlinUnit(type) || type.isNone() || isVoid(type) || isVoidObject(type)) {
- return "V";
- } else if (isArray(type)) {
- XArrayType arrayType = (XArrayType) type;
- return "[" + getDescriptor(arrayType.getComponentType());
- } else if (isDeclared(type) || type.isError()) {
- return "L" + getInternalName(type.getTypeElement()) + ";";
- } else if (XTypes.isExecutable(type)) {
- return getDescriptor((XExecutableType) type);
- } else if (isTypeVariable(type)) {
- // TODO(b/231169600) Expose bounds for type argument from XProcessing to obtain descriptor.
- throw new AssertionError("Generic type is currently unsupported: " + type);
- } else if (isInt(type)) {
- return "I";
- } else if (isLong(type)) {
- return "J";
- } else if (isByte(type)) {
- return "B";
- } else if (isShort(type)) {
- return "S";
- } else if (isDouble(type)) {
- return "D";
- } else if (isFloat(type)) {
- return "F";
- } else if (isBoolean(type)) {
- return "Z";
- } else if (isChar(type)) {
- return "C";
- } else if (isWildcard(type)) {
- return "";
- }
- throw new AssertionError("Unexpected type: " + type);
- }
-
- /**
- * Returns the name of this element in its "internal form".
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2">JVM
- * specification, section 4.2</a>.
- */
- private static String getInternalName(XTypeElement element) {
- if (isNested(element)) {
- return getInternalName(element.getEnclosingTypeElement()) + "$" + getSimpleName(element);
- }
- return element.getQualifiedName().replace('.', '/');
- }
-
- private static String javacGetDescriptor(TypeMirror type) {
- return type.accept(JVM_DESCRIPTOR_TYPE_VISITOR, null);
- }
-
- private static final SimpleTypeVisitor8<String, Void> JVM_DESCRIPTOR_TYPE_VISITOR =
- new SimpleTypeVisitor8<String, Void>() {
-
- @Override
- public String visitArray(ArrayType arrayType, Void v) {
- return "[" + javacGetDescriptor(arrayType.getComponentType());
- }
-
- @Override
- public String visitDeclared(DeclaredType declaredType, Void v) {
- return "L" + getInternalName(declaredType.asElement()) + ";";
- }
-
- @Override
- public String visitError(ErrorType errorType, Void v) {
- // For descriptor generating purposes we don't need a fully modeled type since we are
- // only interested in obtaining the class name in its "internal form".
- return visitDeclared(errorType, v);
- }
-
- @Override
- public String visitExecutable(ExecutableType executableType, Void v) {
- String parameterDescriptors =
- executableType.getParameterTypes().stream()
- .map(XElements::javacGetDescriptor)
- .collect(joining());
- String returnDescriptor = javacGetDescriptor(executableType.getReturnType());
- return "(" + parameterDescriptors + ")" + returnDescriptor;
- }
-
- @Override
- public String visitIntersection(IntersectionType intersectionType, Void v) {
- // For a type variable with multiple bounds: "the erasure of a type variable is determined
- // by the first type in its bound" - JVM Spec Sec 4.4
- return javacGetDescriptor(intersectionType.getBounds().get(0));
- }
-
- @Override
- public String visitNoType(NoType noType, Void v) {
- return "V";
- }
-
- @Override
- public String visitPrimitive(PrimitiveType primitiveType, Void v) {
- switch (primitiveType.getKind()) {
- case BOOLEAN:
- return "Z";
- case BYTE:
- return "B";
- case SHORT:
- return "S";
- case INT:
- return "I";
- case LONG:
- return "J";
- case CHAR:
- return "C";
- case FLOAT:
- return "F";
- case DOUBLE:
- return "D";
- default:
- throw new IllegalArgumentException("Unknown primitive type.");
- }
- }
-
- @Override
- public String visitTypeVariable(TypeVariable typeVariable, Void v) {
- // The erasure of a type variable is the erasure of its leftmost bound. - JVM Spec Sec 4.6
- return javacGetDescriptor(typeVariable.getUpperBound());
- }
-
- @Override
- public String defaultAction(TypeMirror typeMirror, Void v) {
- throw new IllegalArgumentException("Unsupported type: " + typeMirror);
- }
-
- @Override
- public String visitWildcard(WildcardType wildcardType, Void v) {
- return "";
- }
-
- /**
- * Returns the name of this element in its "internal form".
- *
- * <p>For reference, see the <a
- * href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.2">JVM
- * specification, section 4.2</a>.
- */
- private String getInternalName(Element element) {
- if (isType(element)) {
- TypeElement typeElement = asType(element);
- switch (typeElement.getNestingKind()) {
- case TOP_LEVEL:
- return typeElement.getQualifiedName().toString().replace('.', '/');
- case MEMBER:
- return getInternalName(typeElement.getEnclosingElement())
- + "$"
- + typeElement.getSimpleName();
- default:
- throw new IllegalArgumentException("Unsupported nesting kind.");
- }
- }
- return element.getSimpleName().toString();
- }
- };
-
- /**
* Returns a string representation of {@link XElement} that is independent of the backend
* (javac/ksp).
*/
public static String toStableString(XElement element) {
+ if (element == null) {
+ return "<null>";
+ }
try {
if (isTypeElement(element)) {
return asTypeElement(element).getQualifiedName();
@@ -580,5 +379,9 @@
return element.kindName();
}
+ public static String packageName(XElement element) {
+ return element.getClosestMemberContainer().asClassName().getPackageName();
+ }
+
private XElements() {}
}
diff --git a/java/dagger/internal/codegen/xprocessing/XExecutableTypes.java b/java/dagger/internal/codegen/xprocessing/XExecutableTypes.java
index 92c3936..dee7235 100644
--- a/java/dagger/internal/codegen/xprocessing/XExecutableTypes.java
+++ b/java/dagger/internal/codegen/xprocessing/XExecutableTypes.java
@@ -16,17 +16,77 @@
package dagger.internal.codegen.xprocessing;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static java.util.stream.Collectors.joining;
+import androidx.room.compiler.codegen.XTypeNameKt;
import androidx.room.compiler.processing.XConstructorType;
+import androidx.room.compiler.processing.XExecutableElement;
import androidx.room.compiler.processing.XExecutableType;
import androidx.room.compiler.processing.XMethodType;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XType;
+import com.google.common.collect.ImmutableList;
import com.squareup.javapoet.TypeName;
/** A utility class for {@link XExecutableType} helper methods. */
// TODO(bcorso): Consider moving these methods into XProcessing library.
public final class XExecutableTypes {
+ // TODO(b/271177465): Remove this method once XProcessing supports this feature.
+ public static boolean isSubsignature(XExecutableElement method1, XExecutableElement method2) {
+ XProcessingEnv processingEnv = getProcessingEnv(method1);
+ switch (processingEnv.getBackend()) {
+ case JAVAC:
+ return isSubsignatureJavac(method1, method2, processingEnv);
+ case KSP:
+ return isSubsignatureKsp(method1, method2);
+ }
+ throw new AssertionError("Unexpected backend: " + processingEnv.getBackend());
+ }
+
+ private static boolean isSubsignatureKsp(XExecutableElement method1, XExecutableElement method2) {
+ if (method1.getParameters().size() != method2.getParameters().size()) {
+ return false;
+ }
+ ImmutableList<TypeName> method1Parameters = getParameters(method1);
+ ImmutableList<TypeName> method1TypeParameters = getTypeParameters(method1);
+ ImmutableList<TypeName> method2TypeParameters = getTypeParameters(method2);
+ return (method1TypeParameters.equals(method2TypeParameters)
+ && method1Parameters.equals(getParameters(method2)))
+ || (method1TypeParameters
+ .isEmpty() // "The erasure of the signature of a generic method has no type
+ // parameters."
+ && method1Parameters.equals(
+ method2.getExecutableType().getParameterTypes().stream()
+ .map(XTypes::erasedTypeName)
+ .collect(toImmutableList())));
+ }
+
+ private static ImmutableList<TypeName> getParameters(XExecutableElement method) {
+ return method.getExecutableType().getParameterTypes().stream()
+ .map(XType::asTypeName)
+ .map(XTypeNameKt::toJavaPoet)
+ .collect(toImmutableList());
+ }
+
+ private static ImmutableList<TypeName> getTypeParameters(XExecutableElement method) {
+ return method.getTypeParameters().stream()
+ .map(it -> it.getBounds().get(0))
+ .map(XType::asTypeName)
+ .map(XTypeNameKt::toJavaPoet)
+ .collect(toImmutableList());
+ }
+
+ private static boolean isSubsignatureJavac(
+ XExecutableElement method1, XExecutableElement method2, XProcessingEnv env) {
+ return toJavac(env)
+ .getTypeUtils() // ALLOW_TYPES_ELEMENTS
+ .isSubsignature(toJavac(method1.getExecutableType()), toJavac(method2.getExecutableType()));
+ }
+
public static boolean isConstructorType(XExecutableType executableType) {
return executableType instanceof XConstructorType;
}
diff --git a/java/dagger/internal/codegen/xprocessing/XMethodElements.java b/java/dagger/internal/codegen/xprocessing/XMethodElements.java
index 3cd8711..3066d79 100644
--- a/java/dagger/internal/codegen/xprocessing/XMethodElements.java
+++ b/java/dagger/internal/codegen/xprocessing/XMethodElements.java
@@ -16,7 +16,11 @@
package dagger.internal.codegen.xprocessing;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
+import static androidx.room.compiler.processing.compat.XConverters.toJavac;
+
import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XTypeElement;
// TODO(bcorso): Consider moving these methods into XProcessing library.
@@ -36,5 +40,19 @@
return !method.getExecutableType().getTypeVariableNames().isEmpty();
}
+ // TODO(b/278628663): Replace with XMethodElement#isDefault.
+ public static boolean isDefault(XMethodElement method) {
+ XProcessingEnv processingEnv = getProcessingEnv(method);
+ switch (processingEnv.getBackend()) {
+ case JAVAC:
+ return toJavac(method).isDefault();
+ case KSP:
+ throw new AssertionError(
+ "XMethodElement#isDefault() is not supported on KSP yet: "
+ + XElements.toStableString(method));
+ }
+ throw new AssertionError(String.format("Unsupported backend %s", processingEnv.getBackend()));
+ }
+
private XMethodElements() {}
}
diff --git a/java/dagger/internal/codegen/xprocessing/XTypeElements.java b/java/dagger/internal/codegen/xprocessing/XTypeElements.java
index 8f5aa81..6d9c564 100644
--- a/java/dagger/internal/codegen/xprocessing/XTypeElements.java
+++ b/java/dagger/internal/codegen/xprocessing/XTypeElements.java
@@ -16,16 +16,21 @@
package dagger.internal.codegen.xprocessing;
+import static androidx.room.compiler.processing.compat.XConverters.getProcessingEnv;
import static com.google.common.base.Preconditions.checkNotNull;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static kotlin.streams.jdk8.StreamsKt.asStream;
import androidx.room.compiler.processing.XHasModifiers;
import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XTypeElement;
import androidx.room.compiler.processing.XTypeParameterElement;
+import androidx.room.compiler.processing.compat.XConverters;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.ksp.symbol.Origin;
+import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeVariableName;
// TODO(bcorso): Consider moving these methods into XProcessing library.
@@ -81,15 +86,20 @@
.collect(toImmutableList());
}
- // TODO(b/229784604): This is needed until the XProcessing getAllMethods fix is upstreamed. Due
- // to the existing bug, XTypeElement#getAllMethods() will currently contain some inaccessible
- // package-private methods from base classes, so we filter them manually here.
+ // TODO(wanyingd): rename this to getAllMethodsWithoutPrivate, since the private method declared
+ // within this element is being filtered out. This doesn't mirror {@code
+ // MoreElements#getAllMethods}'s behavior but have the same name, and can cause confusion to
+ // developers.
public static ImmutableList<XMethodElement> getAllMethods(XTypeElement type) {
return asStream(type.getAllMethods())
.filter(method -> isAccessibleFrom(method, type))
.collect(toImmutableList());
}
+ public static ImmutableList<XMethodElement> getAllMethodsIncludingPrivate(XTypeElement type) {
+ return asStream(type.getAllMethods()).collect(toImmutableList());
+ }
+
private static boolean isAccessibleFrom(XMethodElement method, XTypeElement type) {
if (method.isPublic() || method.isProtected()) {
return true;
@@ -113,6 +123,10 @@
return allVisibilities(element).contains(Visibility.PRIVATE);
}
+ public static boolean isJvmClass(XTypeElement element) {
+ return element.isClass() || element.isKotlinObject() || element.isCompanionObject();
+ }
+
/**
* Returns a list of visibilities containing visibility of the given element and the visibility of
* its enclosing elements.
@@ -128,5 +142,20 @@
return visibilities.build();
}
+ /** Returns true if the source of the given type element is Kotlin. */
+ public static boolean isKotlinSource(XTypeElement typeElement) {
+ XProcessingEnv processingEnv = getProcessingEnv(typeElement);
+ switch (processingEnv.getBackend()) {
+ case KSP:
+ // If this is KSP, then we should be able to check the origin of the declaration.
+ Origin origin = XConverters.toKS(typeElement).getOrigin();
+ return origin == Origin.KOTLIN || origin == Origin.KOTLIN_LIB;
+ case JAVAC:
+ // If this is KAPT, then the java stubs should have kotlin metadata.
+ return typeElement.hasAnnotation(ClassName.get("kotlin", "Metadata"));
+ }
+ throw new AssertionError("Unhandled backend kind: " + processingEnv.getBackend());
+ }
+
private XTypeElements() {}
}
diff --git a/java/dagger/internal/codegen/xprocessing/XTypes.java b/java/dagger/internal/codegen/xprocessing/XTypes.java
index 8261468..654ce69 100644
--- a/java/dagger/internal/codegen/xprocessing/XTypes.java
+++ b/java/dagger/internal/codegen/xprocessing/XTypes.java
@@ -40,6 +40,7 @@
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.XTypeVariableType;
import com.google.auto.common.MoreElements;
import com.google.common.base.Equivalence;
import com.squareup.javapoet.ArrayTypeName;
@@ -63,26 +64,79 @@
// TODO(bcorso): Consider moving these methods into XProcessing library.
/** A utility class for {@link XType} helper methods. */
public final class XTypes {
- private static final Equivalence<XType> XTYPE_EQUIVALENCE =
- new Equivalence<XType>() {
- @Override
- protected boolean doEquivalent(XType left, XType right) {
- return left.getTypeName().equals(right.getTypeName());
- }
+ private static class XTypeEquivalence extends Equivalence<XType> {
+ private final boolean ignoreVariance;
- @Override
- protected int doHash(XType type) {
- return type.getTypeName().hashCode();
- }
+ XTypeEquivalence(boolean ignoreVariance) {
+ this.ignoreVariance = ignoreVariance;
+ }
- @Override
- public String toString() {
- return "XTypes.equivalence()";
- }
- };
+ @Override
+ protected boolean doEquivalent(XType left, XType right) {
+ return getTypeName(left).equals(getTypeName(right));
+ }
+
+ @Override
+ protected int doHash(XType type) {
+ return getTypeName(type).hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "XTypes.equivalence()";
+ }
+
+ private TypeName getTypeName(XType type) {
+ return ignoreVariance ? stripVariances(type.getTypeName()) : type.getTypeName();
+ }
+ }
+
+ public static TypeName stripVariances(TypeName typeName) {
+ if (typeName instanceof WildcardTypeName) {
+ WildcardTypeName wildcardTypeName = (WildcardTypeName) typeName;
+ if (!wildcardTypeName.lowerBounds.isEmpty()) {
+ return stripVariances(getOnlyElement(wildcardTypeName.lowerBounds));
+ } else if (!wildcardTypeName.upperBounds.isEmpty()) {
+ return stripVariances(getOnlyElement(wildcardTypeName.upperBounds));
+ }
+ } else if (typeName instanceof ArrayTypeName) {
+ ArrayTypeName arrayTypeName = (ArrayTypeName) typeName;
+ return ArrayTypeName.of(stripVariances(arrayTypeName.componentType));
+ } else if (typeName instanceof ParameterizedTypeName) {
+ ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
+ if (parameterizedTypeName.typeArguments.isEmpty()) {
+ return parameterizedTypeName;
+ } else {
+ return ParameterizedTypeName.get(
+ parameterizedTypeName.rawType,
+ parameterizedTypeName.typeArguments.stream()
+ .map(XTypes::stripVariances)
+ .toArray(TypeName[]::new));
+ }
+ }
+ return typeName;
+ }
+
+ private static final Equivalence<XType> XTYPE_EQUIVALENCE_IGNORING_VARIANCE =
+ new XTypeEquivalence(/* ignoreVariance= */ true);
/**
- * Returns an {@link Equivalence} for {@link XType}.
+ * Returns an {@link Equivalence} for {@link XType} based on the {@link TypeName} with variances
+ * ignored (e.g. {@code Foo<? extends Bar>} would be equivalent to {@code Foo<Bar>}).
+ *
+ * <p>Currently, this equivalence does not take into account nullability, as it just relies on
+ * JavaPoet's {@link TypeName}. Thus, two types with the same type name but different nullability
+ * are equal with this equivalence.
+ */
+ public static Equivalence<XType> equivalenceIgnoringVariance() {
+ return XTYPE_EQUIVALENCE_IGNORING_VARIANCE;
+ }
+
+ private static final Equivalence<XType> XTYPE_EQUIVALENCE =
+ new XTypeEquivalence(/* ignoreVariance= */ false);
+
+ /**
+ * Returns an {@link Equivalence} for {@link XType} based on the {@link TypeName}.
*
* <p>Currently, this equivalence does not take into account nullability, as it just relies on
* JavaPoet's {@link TypeName}. Thus, two types with the same type name but different nullability
@@ -215,6 +269,11 @@
return (XArrayType) type;
}
+ /** Returns the given {@code type} as an {@link XTypeVariableType}. */
+ public static XTypeVariableType asTypeVariable(XType type) {
+ return (XTypeVariableType) type;
+ }
+
/** Returns {@code true} if the raw type of {@code type} is equal to {@code className}. */
public static boolean isTypeOf(XType type, ClassName className) {
return isDeclared(type) && type.getTypeElement().getClassName().equals(className);
@@ -283,10 +342,6 @@
return !type.getTypeArguments().isEmpty();
}
- public static boolean isExecutable(XType type) {
- return type instanceof XExecutableType;
- }
-
public static boolean isMethod(XExecutableType type) {
return type instanceof XMethodType;
}
diff --git a/java/dagger/internal/codegen/xprocessing/xprocessing.jar b/java/dagger/internal/codegen/xprocessing/xprocessing.jar
index b034604..1c41e20 100644
--- a/java/dagger/internal/codegen/xprocessing/xprocessing.jar
+++ b/java/dagger/internal/codegen/xprocessing/xprocessing.jar
Binary files differ
diff --git a/java/dagger/model/BindingKind.java b/java/dagger/model/BindingKind.java
index 9bef8fc..1bfb080 100644
--- a/java/dagger/model/BindingKind.java
+++ b/java/dagger/model/BindingKind.java
@@ -98,7 +98,7 @@
OPTIONAL,
/**
- * A binding for {@link dagger.Binds}-annotated method that that delegates from requests for one
+ * A binding for {@link dagger.Binds}-annotated method that delegates from requests for one
* key to another.
*/
// TODO(dpb,ronshapiro): This name is confusing and could use work. Not all usages of @Binds
diff --git a/java/dagger/spi/BUILD b/java/dagger/spi/BUILD
index 0e18ca6..13428c1 100644
--- a/java/dagger/spi/BUILD
+++ b/java/dagger/spi/BUILD
@@ -58,12 +58,10 @@
artifact_target = ":spi",
artifact_target_libs = [
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/model",
"//java/dagger/spi/model",
],
artifact_target_maven_deps = [
- "com.google.auto:auto-common",
"com.google.code.findbugs:jsr305",
"com.google.dagger:dagger-producers",
"com.google.dagger:dagger",
@@ -71,9 +69,7 @@
"com.google.guava:failureaccess",
"com.google.guava:guava",
"com.squareup:javapoet",
- "com.squareup:kotlinpoet",
"javax.inject:javax.inject",
- "org.jetbrains.kotlin:kotlin-stdlib",
],
javadoc_root_packages = [
"dagger.model",
@@ -85,6 +81,7 @@
# util/deploy-dagger.sh
shaded_deps = [
"//third_party/java/auto:common",
+ "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
"//java/dagger/internal/codegen/xprocessing:xprocessing-jar",
],
)
diff --git a/java/dagger/spi/model/BUILD b/java/dagger/spi/model/BUILD
index afe6e9a..e9346dd 100644
--- a/java/dagger/spi/model/BUILD
+++ b/java/dagger/spi/model/BUILD
@@ -15,12 +15,7 @@
# Description:
# Dagger's core APIs exposed for plugins
-load("@rules_java//java:defs.bzl", "java_library")
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
-)
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
package(default_visibility = [
# The dagger/spi should be the only direct dependent on this target.
@@ -32,17 +27,19 @@
filegroup(
name = "model-srcs",
- srcs = glob(["*.java"]),
+ srcs = glob([
+ "*.java",
+ "*.kt",
+ ]),
)
-java_library(
+kt_jvm_library(
name = "model",
srcs = [":model-srcs"],
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ # TODO(wanyingd): Add javacopts explicitly once kt_jvm_library supports them.
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/producers",
"//third_party/java/auto:common",
"//third_party/java/auto:value",
@@ -56,3 +53,9 @@
"@maven//:com_google_devtools_ksp_symbol_processing_api",
],
)
+
+# See: https://github.com/bazelbuild/rules_kotlin/issues/324
+alias(
+ name = "libmodel-src.jar",
+ actual = ":model-sources.jar",
+)
diff --git a/java/dagger/spi/model/BindingGraph.java b/java/dagger/spi/model/BindingGraph.java
index f10ffe2..aab7c2a 100644
--- a/java/dagger/spi/model/BindingGraph.java
+++ b/java/dagger/spi/model/BindingGraph.java
@@ -117,6 +117,8 @@
*/
public abstract boolean isFullBindingGraph();
+ public abstract DaggerProcessingEnv.Backend backend();
+
/**
* Returns {@code true} if the {@link #rootComponentNode()} is a subcomponent. This occurs in
* when {@code -Adagger.fullBindingGraphValidation} is used in a compilation with a subcomponent.
diff --git a/java/dagger/spi/model/ComponentPath.java b/java/dagger/spi/model/ComponentPath.java
index 74195e4..63a5f6b 100644
--- a/java/dagger/spi/model/ComponentPath.java
+++ b/java/dagger/spi/model/ComponentPath.java
@@ -23,7 +23,6 @@
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
/** A path containing a component and all of its ancestor components. */
@AutoValue
@@ -90,10 +89,7 @@
@Override
public final String toString() {
- return components().stream()
- .map(DaggerTypeElement::className)
- .map(ClassName::canonicalName)
- .collect(joining(" → "));
+ return components().stream().map(DaggerTypeElement::qualifiedName).collect(joining(" → "));
}
@Memoized
diff --git a/java/dagger/spi/model/DaggerAnnotation.java b/java/dagger/spi/model/DaggerAnnotation.java
index b7c5ab0..2ec66c0 100644
--- a/java/dagger/spi/model/DaggerAnnotation.java
+++ b/java/dagger/spi/model/DaggerAnnotation.java
@@ -16,45 +16,55 @@
package dagger.spi.model;
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-
-import androidx.room.compiler.processing.XAnnotation;
+import com.google.auto.common.AnnotationMirrors;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Preconditions;
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.xprocessing.XAnnotations;
+import com.google.devtools.ksp.symbol.KSAnnotation;
+import javax.annotation.Nullable;
import javax.lang.model.element.AnnotationMirror;
/** Wrapper type for an annotation. */
@AutoValue
public abstract class DaggerAnnotation {
-
- public static DaggerAnnotation from(XAnnotation annotation) {
- Preconditions.checkNotNull(annotation);
- return new AutoValue_DaggerAnnotation(XAnnotations.equivalence().wrap(annotation));
+ public static DaggerAnnotation fromJavac(
+ DaggerTypeElement annotationTypeElement, AnnotationMirror annotation) {
+ return new AutoValue_DaggerAnnotation(annotationTypeElement, annotation, null);
}
- abstract Equivalence.Wrapper<XAnnotation> equivalenceWrapper();
-
- public DaggerTypeElement annotationTypeElement() {
- return DaggerTypeElement.from(xprocessing().getType().getTypeElement());
+ public static DaggerAnnotation fromKsp(
+ DaggerTypeElement annotationTypeElement, KSAnnotation ksp) {
+ return new AutoValue_DaggerAnnotation(annotationTypeElement, null, ksp);
}
- public ClassName className() {
- return annotationTypeElement().className();
- }
+ public abstract DaggerTypeElement annotationTypeElement();
- public XAnnotation xprocessing() {
- return equivalenceWrapper().get();
- }
+ /**
+ * java representation for the annotation, returns {@code null} if the annotation isn't a java
+ * element.
+ */
+ @Nullable
+ public abstract AnnotationMirror java();
- public AnnotationMirror java() {
- return toJavac(xprocessing());
+ /** KSP declaration for the annotation, returns {@code null} not using KSP. */
+ @Nullable
+ public abstract KSAnnotation ksp();
+
+ public DaggerProcessingEnv.Backend backend() {
+ if (java() != null) {
+ return DaggerProcessingEnv.Backend.JAVAC;
+ } else if (ksp() != null) {
+ return DaggerProcessingEnv.Backend.KSP;
+ }
+ throw new AssertionError("Unexpected backend");
}
@Override
public final String toString() {
- return XAnnotations.toString(xprocessing());
+ switch (backend()) {
+ case JAVAC:
+ return AnnotationMirrors.toString(java());
+ case KSP:
+ return ksp().toString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
}
}
diff --git a/java/dagger/spi/model/DaggerElement.java b/java/dagger/spi/model/DaggerElement.java
index aa1b4a5..0f6a2cf 100644
--- a/java/dagger/spi/model/DaggerElement.java
+++ b/java/dagger/spi/model/DaggerElement.java
@@ -16,27 +16,49 @@
package dagger.spi.model;
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-
-import androidx.room.compiler.processing.XElement;
import com.google.auto.value.AutoValue;
+import com.google.devtools.ksp.symbol.KSAnnotated;
+import javax.annotation.Nullable;
import javax.lang.model.element.Element;
/** Wrapper type for an element. */
@AutoValue
public abstract class DaggerElement {
- public static DaggerElement from(XElement element) {
- return new AutoValue_DaggerElement(element);
+ public static DaggerElement fromJavac(Element element) {
+ return new AutoValue_DaggerElement(element, null);
}
- public abstract XElement xprocessing();
+ public static DaggerElement fromKsp(KSAnnotated ksp) {
+ return new AutoValue_DaggerElement(null, ksp);
+ }
- public Element java() {
- return toJavac(xprocessing());
+ /**
+ * Java representation for the element, returns {@code null} not using java annotation processor.
+ */
+ @Nullable
+ public abstract Element java();
+
+ /** KSP declaration for the element, returns {@code null} not using KSP. */
+ @Nullable
+ public abstract KSAnnotated ksp();
+
+ public DaggerProcessingEnv.Backend backend() {
+ if (java() != null) {
+ return DaggerProcessingEnv.Backend.JAVAC;
+ } else if (ksp() != null) {
+ return DaggerProcessingEnv.Backend.KSP;
+ }
+ throw new AssertionError("Unexpected backend");
}
@Override
public final String toString() {
- return xprocessing().toString();
+ switch (backend()) {
+ case JAVAC:
+ return java().toString();
+ case KSP:
+ return ksp().toString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
}
}
diff --git a/java/dagger/spi/model/DaggerExecutableElement.java b/java/dagger/spi/model/DaggerExecutableElement.java
index e15ca37..7df6a1e 100644
--- a/java/dagger/spi/model/DaggerExecutableElement.java
+++ b/java/dagger/spi/model/DaggerExecutableElement.java
@@ -16,28 +16,59 @@
package dagger.spi.model;
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import androidx.room.compiler.processing.XExecutableElement;
import com.google.auto.value.AutoValue;
+import com.google.devtools.ksp.symbol.KSFunctionDeclaration;
+import javax.annotation.Nullable;
import javax.lang.model.element.ExecutableElement;
/** Wrapper type for an executable element. */
@AutoValue
public abstract class DaggerExecutableElement {
- public static DaggerExecutableElement from(XExecutableElement executableElement) {
- return new AutoValue_DaggerExecutableElement(checkNotNull(executableElement));
+ public static DaggerExecutableElement fromJava(ExecutableElement executableElement) {
+ return new AutoValue_DaggerExecutableElement(executableElement, null);
}
- public abstract XExecutableElement xprocessing();
+ public static DaggerExecutableElement fromKsp(KSFunctionDeclaration declaration) {
+ return new AutoValue_DaggerExecutableElement(null, declaration);
+ }
- public ExecutableElement java() {
- return toJavac(xprocessing());
+ /**
+ * Java representation for the element, returns {@code null} not using java annotation processor.
+ */
+ @Nullable
+ public abstract ExecutableElement java();
+
+ /** KSP declaration for the element, returns {@code null} not using KSP. */
+ @Nullable
+ public abstract KSFunctionDeclaration ksp();
+
+ public DaggerProcessingEnv.Backend backend() {
+ if (java() != null) {
+ return DaggerProcessingEnv.Backend.JAVAC;
+ } else if (ksp() != null) {
+ return DaggerProcessingEnv.Backend.KSP;
+ }
+ throw new AssertionError("Unexpected backend");
}
@Override
public final String toString() {
- return xprocessing().toString();
+ switch (backend()) {
+ case JAVAC:
+ return java().toString();
+ case KSP:
+ return ksp().toString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
+ }
+
+ String simpleName() {
+ switch (backend()) {
+ case JAVAC:
+ return java().getSimpleName().toString();
+ case KSP:
+ return ksp().getSimpleName().toString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
}
}
diff --git a/java/dagger/spi/model/DaggerProcessingEnv.java b/java/dagger/spi/model/DaggerProcessingEnv.java
index 27c0493..8c652c8 100644
--- a/java/dagger/spi/model/DaggerProcessingEnv.java
+++ b/java/dagger/spi/model/DaggerProcessingEnv.java
@@ -16,10 +16,10 @@
package dagger.spi.model;
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-
-import androidx.room.compiler.processing.XProcessingEnv;
import com.google.auto.value.AutoValue;
+import com.google.devtools.ksp.processing.Resolver;
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment;
+import javax.annotation.Nullable;
import javax.annotation.processing.ProcessingEnvironment;
/** Wrapper type for an element. */
@@ -28,18 +28,38 @@
/** Represents a type of backend used for compilation. */
public enum Backend { JAVAC, KSP }
- public static DaggerProcessingEnv from(XProcessingEnv processingEnv) {
- return new AutoValue_DaggerProcessingEnv(processingEnv);
+ public static boolean isJavac(Backend backend) {
+ return backend.equals(Backend.JAVAC);
}
- public abstract XProcessingEnv xprocessing();
+ public static DaggerProcessingEnv fromJavac(ProcessingEnvironment env) {
+ return new AutoValue_DaggerProcessingEnv(env, null, null);
+ }
+
+ public static DaggerProcessingEnv fromKsp(SymbolProcessorEnvironment env, Resolver resolver) {
+ return new AutoValue_DaggerProcessingEnv(null, env, resolver);
+ }
+
+ /**
+ * Java representation for the processing environment, returns {@code null} not using java
+ * annotation processor.
+ */
+ @Nullable
+ public abstract ProcessingEnvironment java();
+
+ @Nullable
+ public abstract SymbolProcessorEnvironment ksp();
+
+ @Nullable
+ public abstract Resolver resolver();
/** Returns the backend used in this compilation. */
- public Backend getBackend() {
- return Backend.valueOf(xprocessing().getBackend().name());
- }
-
- public ProcessingEnvironment java() {
- return toJavac(xprocessing());
+ public DaggerProcessingEnv.Backend backend() {
+ if (java() != null) {
+ return DaggerProcessingEnv.Backend.JAVAC;
+ } else if (ksp() != null) {
+ return DaggerProcessingEnv.Backend.KSP;
+ }
+ throw new AssertionError("Unexpected backend");
}
}
diff --git a/java/dagger/spi/model/DaggerType.java b/java/dagger/spi/model/DaggerType.java
index bb2f77c..249d494 100644
--- a/java/dagger/spi/model/DaggerType.java
+++ b/java/dagger/spi/model/DaggerType.java
@@ -16,39 +16,47 @@
package dagger.spi.model;
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-
-import androidx.room.compiler.processing.XType;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Preconditions;
-import dagger.internal.codegen.xprocessing.XTypes;
+import com.google.devtools.ksp.symbol.KSType;
+import javax.annotation.Nullable;
import javax.lang.model.type.TypeMirror;
/** Wrapper type for a type. */
@AutoValue
public abstract class DaggerType {
- public static DaggerType from(XType type) {
- Preconditions.checkNotNull(type);
- return new AutoValue_DaggerType(XTypes.equivalence().wrap(type));
+ public static DaggerType fromJavac(TypeMirror type) {
+ return new AutoValue_DaggerType(type, null);
}
- abstract Equivalence.Wrapper<XType> equivalenceWrapper();
-
- public XType xprocessing() {
- return equivalenceWrapper().get();
+ public static DaggerType fromKsp(KSType type) {
+ return new AutoValue_DaggerType(null, type);
}
- public TypeMirror java() {
- return toJavac(xprocessing());
+ /** Java representation for the type, returns {@code null} not using java annotation processor. */
+ @Nullable
+ public abstract TypeMirror java();
+
+ /** KSP declaration for the type, returns {@code null} not using KSP. */
+ @Nullable
+ public abstract KSType ksp();
+
+ public DaggerProcessingEnv.Backend backend() {
+ if (java() != null) {
+ return DaggerProcessingEnv.Backend.JAVAC;
+ } else if (ksp() != null) {
+ return DaggerProcessingEnv.Backend.KSP;
+ }
+ throw new AssertionError("Unexpected backend");
}
@Override
public final String toString() {
- // We define our own stable string rather than use XType#toString() here because
- // XType#toString() is currently not stable across backends. In particular, in javac it returns
- // the qualified type but in ksp it returns the simple name.
- // TODO(bcorso): Consider changing XProcessing so that #toString() is stable across backends.
- return XTypes.toStableString(xprocessing());
+ switch (backend()) {
+ case JAVAC:
+ return java().toString();
+ case KSP:
+ return ksp().toString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
}
}
diff --git a/java/dagger/spi/model/DaggerTypeElement.java b/java/dagger/spi/model/DaggerTypeElement.java
index aa47507..2f70a54 100644
--- a/java/dagger/spi/model/DaggerTypeElement.java
+++ b/java/dagger/spi/model/DaggerTypeElement.java
@@ -16,32 +16,78 @@
package dagger.spi.model;
-import static androidx.room.compiler.processing.compat.XConverters.toJavac;
-
-import androidx.room.compiler.processing.XTypeElement;
+import com.google.auto.common.MoreElements;
import com.google.auto.value.AutoValue;
-import com.squareup.javapoet.ClassName;
+import com.google.devtools.ksp.symbol.KSClassDeclaration;
+import javax.annotation.Nullable;
import javax.lang.model.element.TypeElement;
/** Wrapper type for a type element. */
@AutoValue
public abstract class DaggerTypeElement {
- public static DaggerTypeElement from(XTypeElement typeElement) {
- return new AutoValue_DaggerTypeElement(typeElement);
+ public static DaggerTypeElement fromJavac(@Nullable TypeElement element) {
+ return new AutoValue_DaggerTypeElement(element, null);
}
- public abstract XTypeElement xprocessing();
-
- public TypeElement java() {
- return toJavac(xprocessing());
+ public static DaggerTypeElement fromKsp(@Nullable KSClassDeclaration declaration) {
+ return new AutoValue_DaggerTypeElement(null, declaration);
}
- public ClassName className() {
- return xprocessing().getClassName();
+ /** Java representation for the type, returns {@code null} not using java annotation processor. */
+ @Nullable
+ public abstract TypeElement java();
+
+ /** KSP declaration for the element, returns {@code null} not using KSP. */
+ @Nullable
+ public abstract KSClassDeclaration ksp();
+
+ public final boolean hasAnnotation(String annotationName) {
+ switch (backend()) {
+ case JAVAC:
+ return MoreElements.isAnnotationPresent(java(), annotationName);
+ case KSP:
+ return KspUtilsKt.hasAnnotation(ksp(), annotationName);
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
+ }
+
+ public String packageName() {
+ switch (backend()) {
+ case JAVAC:
+ return MoreElements.getPackage(java()).getQualifiedName().toString();
+ case KSP:
+ return KspUtilsKt.getNormalizedPackageName(ksp());
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
+ }
+
+ public String qualifiedName() {
+ switch (backend()) {
+ case JAVAC:
+ return java().getQualifiedName().toString();
+ case KSP:
+ return ksp().getQualifiedName().asString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
+ }
+
+ public DaggerProcessingEnv.Backend backend() {
+ if (java() != null) {
+ return DaggerProcessingEnv.Backend.JAVAC;
+ } else if (ksp() != null) {
+ return DaggerProcessingEnv.Backend.KSP;
+ }
+ throw new AssertionError("Unexpected backend");
}
@Override
public final String toString() {
- return xprocessing().toString();
+ switch (backend()) {
+ case JAVAC:
+ return java().toString();
+ case KSP:
+ return ksp().toString();
+ }
+ throw new IllegalStateException(String.format("Backend %s not supported yet.", backend()));
}
}
diff --git a/java/dagger/spi/model/Key.java b/java/dagger/spi/model/Key.java
index a50e5ac..d871e6d 100644
--- a/java/dagger/spi/model/Key.java
+++ b/java/dagger/spi/model/Key.java
@@ -16,12 +16,10 @@
package dagger.spi.model;
-import static dagger.internal.codegen.xprocessing.XElements.getSimpleName;
import com.google.auto.value.AutoValue;
import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Joiner;
-import dagger.internal.codegen.xprocessing.XAnnotations;
import java.util.Optional;
/**
@@ -89,10 +87,7 @@
return Joiner.on(' ')
.skipNulls()
.join(
- qualifier()
- .map(DaggerAnnotation::xprocessing)
- .map(XAnnotations::toStableString)
- .orElse(null),
+ qualifier().map(DaggerAnnotation::toString).orElse(null),
type(),
multibindingContributionIdentifier().orElse(null));
}
@@ -135,8 +130,7 @@
private static MultibindingContributionIdentifier create(
DaggerTypeElement contributingModule, DaggerExecutableElement bindingMethod) {
return new AutoValue_Key_MultibindingContributionIdentifier(
- contributingModule.xprocessing().getQualifiedName(),
- getSimpleName(bindingMethod.xprocessing()));
+ contributingModule.qualifiedName(), bindingMethod.simpleName());
}
/** Returns the module containing the multibinding method. */
@@ -152,7 +146,7 @@
* whole object.
*/
@Override
- public String toString() {
+ public final String toString() {
return String.format("%s#%s", contributingModule(), bindingMethod());
}
}
diff --git a/java/dagger/spi/model/KspUtils.kt b/java/dagger/spi/model/KspUtils.kt
new file mode 100644
index 0000000..09d8aa2
--- /dev/null
+++ b/java/dagger/spi/model/KspUtils.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.spi.model
+
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSDeclaration
+
+fun KSClassDeclaration.hasAnnotation(annotationName: String): Boolean =
+ annotations.any {
+ it.annotationType.resolve().declaration.qualifiedName?.asString().equals(annotationName)
+ }
+
+/** Returns root package name as empty string instead of <root>. */
+fun KSDeclaration.getNormalizedPackageName(): String {
+ return packageName.asString().let {
+ if (it == "<root>") {
+ ""
+ } else {
+ it
+ }
+ }
+}
diff --git a/java/dagger/spi/model/Scope.java b/java/dagger/spi/model/Scope.java
index 8e2aaf3..d1505b9 100644
--- a/java/dagger/spi/model/Scope.java
+++ b/java/dagger/spi/model/Scope.java
@@ -19,7 +19,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import com.google.auto.value.AutoValue;
-import com.squareup.javapoet.ClassName;
/** A representation of a {@link javax.inject.Scope}. */
@AutoValue
@@ -43,25 +42,23 @@
* Returns {@code true} if {@code scopeAnnotationType} is a {@link javax.inject.Scope} annotation.
*/
public static boolean isScope(DaggerTypeElement scopeAnnotationType) {
- return scopeAnnotationType.xprocessing().hasAnnotation(SCOPE)
- || scopeAnnotationType.xprocessing().hasAnnotation(SCOPE_JAVAX);
+ return scopeAnnotationType.hasAnnotation(SCOPE)
+ || scopeAnnotationType.hasAnnotation(SCOPE_JAVAX);
}
- private static final ClassName PRODUCTION_SCOPE =
- ClassName.get("dagger.producers", "ProductionScope");
- private static final ClassName SINGLETON = ClassName.get("jakarta.inject", "Singleton");
- private static final ClassName SINGLETON_JAVAX = ClassName.get("javax.inject", "Singleton");
- private static final ClassName REUSABLE = ClassName.get("dagger", "Reusable");
- private static final ClassName SCOPE = ClassName.get("jakarta.inject", "Scope");
- private static final ClassName SCOPE_JAVAX = ClassName.get("javax.inject", "Scope");
-
+ private boolean isScope(String annotationName) {
+ return scopeAnnotation().toString().equals(annotationName);
+ }
/** The {@link DaggerAnnotation} that represents the scope annotation. */
public abstract DaggerAnnotation scopeAnnotation();
- public final ClassName className() {
- return scopeAnnotation().className();
- }
+ private static final String PRODUCTION_SCOPE = "dagger.producers.ProductionScope";
+ private static final String SINGLETON = "jakarta.inject.Singleton";
+ private static final String SINGLETON_JAVAX = "javax.inject.Singleton";
+ private static final String REUSABLE = "dagger.Reusable";
+ private static final String SCOPE = "jakarta.inject.Scope";
+ private static final String SCOPE_JAVAX = "javax.inject.Scope";
/** Returns {@code true} if this scope is the {@link javax.inject.Singleton @Singleton} scope. */
public final boolean isSingleton() {
@@ -81,10 +78,6 @@
return isScope(PRODUCTION_SCOPE);
}
- private boolean isScope(ClassName annotation) {
- return scopeAnnotation().className().equals(annotation);
- }
-
/** Returns a debug representation of the scope. */
@Override
public final String toString() {
diff --git a/java/dagger/spi/model/testing/BindingGraphSubject.java b/java/dagger/spi/model/testing/BindingGraphSubject.java
index 32bf152..e206731 100644
--- a/java/dagger/spi/model/testing/BindingGraphSubject.java
+++ b/java/dagger/spi/model/testing/BindingGraphSubject.java
@@ -25,6 +25,7 @@
import com.google.common.truth.Subject;
import dagger.spi.model.Binding;
import dagger.spi.model.BindingGraph;
+import dagger.spi.model.DaggerType;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
@@ -69,7 +70,7 @@
* @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
*/
public BindingSubject bindingWithKey(String type) {
- return bindingWithKeyString(keyString(type));
+ return bindingWithKeyString(type);
}
/**
@@ -94,18 +95,30 @@
private ImmutableSet<Binding> getBindingNodes(String keyString) {
return actual.bindings().stream()
- .filter(binding -> binding.key().toString().equals(keyString))
+ .filter(binding -> keyString(binding).equals(keyString))
.collect(toImmutableSet());
}
- private static String keyString(String type) {
- return type;
+ public static String keyString(Binding binding) {
+ return binding.key().qualifier().isPresent()
+ ? keyString(binding.key().qualifier().get().toString(), formattedType(binding.key().type()))
+ : formattedType(binding.key().type());
}
private static String keyString(String qualifier, String type) {
return String.format("%s %s", qualifier, type);
}
+ private static String formattedType(DaggerType type) {
+ switch (type.backend()) {
+ case JAVAC:
+ return type.java().toString();
+ case KSP:
+ return type.ksp().getDeclaration().getQualifiedName().asString();
+ }
+ throw new AssertionError("Unsupported backend");
+ }
+
/** A Truth subject for a {@link Binding}. */
public final class BindingSubject extends Subject {
@@ -122,7 +135,7 @@
* @param type the canonical name of the type, as returned by {@link TypeMirror#toString()}
*/
public void dependsOnBindingWithKey(String type) {
- dependsOnBindingWithKeyString(keyString(type));
+ dependsOnBindingWithKeyString(type);
}
/**
@@ -138,7 +151,7 @@
private void dependsOnBindingWithKeyString(String keyString) {
if (actualBindingGraph().requestedBindings(actual).stream()
- .noneMatch(binding -> binding.key().toString().equals(keyString))) {
+ .noneMatch(binding -> keyString(binding).equals(keyString))) {
failWithActual("expected to depend on binding with key", keyString);
}
}
diff --git a/java/dagger/testing/compile/CompilerTests.java b/java/dagger/testing/compile/CompilerTests.java
index b544e5e..5557420 100644
--- a/java/dagger/testing/compile/CompilerTests.java
+++ b/java/dagger/testing/compile/CompilerTests.java
@@ -78,23 +78,25 @@
}
/** Returns a {@link Source.KotlinSource} with the given file name and content. */
- public static Source kotlinSource(String fileName, ImmutableCollection<String> srcLines) {
- return Source.Companion.kotlin(fileName, String.join("\n", srcLines));
+ public static Source.KotlinSource kotlinSource(
+ String fileName, ImmutableCollection<String> srcLines) {
+ return (Source.KotlinSource) Source.Companion.kotlin(fileName, String.join("\n", srcLines));
}
/** Returns a {@link Source.KotlinSource} with the given file name and content. */
- public static Source kotlinSource(String fileName, String... srcLines) {
- return Source.Companion.kotlin(fileName, String.join("\n", srcLines));
+ public static Source.KotlinSource kotlinSource(String fileName, String... srcLines) {
+ return (Source.KotlinSource) Source.Companion.kotlin(fileName, String.join("\n", srcLines));
}
/** Returns a {@link Source.JavaSource} with the given file name and content. */
- public static Source javaSource(String fileName, ImmutableCollection<String> srcLines) {
- return Source.Companion.java(fileName, String.join("\n", srcLines));
+ public static Source.JavaSource javaSource(
+ String fileName, ImmutableCollection<String> srcLines) {
+ return (Source.JavaSource) Source.Companion.java(fileName, String.join("\n", srcLines));
}
/** Returns a {@link Source.JavaSource} with the given file name and content. */
- public static Source javaSource(String fileName, String... srcLines) {
- return Source.Companion.java(fileName, String.join("\n", srcLines));
+ public static Source.JavaSource javaSource(String fileName, String... srcLines) {
+ return (Source.JavaSource) Source.Companion.java(fileName, String.join("\n", srcLines));
}
/** Returns a {@link Compiler} instance with the given sources. */
@@ -205,14 +207,13 @@
/* classpath= */ ImmutableList.of(),
processorOptions(),
/* javacArguments= */ ImmutableList.of(),
- /* kotlincArguments= */ ImmutableList.of(),
+ /* kotlincArguments= */ ImmutableList.of(
+ "-P", "plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true"),
/* config= */ PROCESSING_ENV_CONFIG,
- /* javacProcessors= */
- ImmutableList.of(
+ /* javacProcessors= */ ImmutableList.of(
ComponentProcessor.withTestPlugins(bindingGraphPlugins()),
new CompilerProcessors.JavacProcessor(processingSteps())),
- /* symbolProcessorProviders= */
- ImmutableList.of(
+ /* symbolProcessorProviders= */ ImmutableList.of(
KspComponentProcessor.Provider.withTestPlugins(bindingGraphPlugins()),
new CompilerProcessors.KspProcessor.Provider(processingSteps())),
result -> {
diff --git a/javatests/artifacts/dagger-ksp/build.gradle b/javatests/artifacts/dagger-ksp/build.gradle
new file mode 100644
index 0000000..9e92640
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/build.gradle
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+buildscript {
+ ext {
+ dagger_version = "LOCAL-SNAPSHOT"
+ kotlin_version = "1.8.0"
+ ksp_version = "1.8.0-1.0.9"
+ junit_version = "4.13"
+ truth_version = "1.0.1"
+ }
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+ dependencies {
+ classpath("com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:$ksp_version")
+ }
+}
+
+allprojects {
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+
+ configurations.all {
+ resolutionStrategy.eachDependency { DependencyResolveDetails details ->
+ if (details.requested.group == 'com.google.dagger'
+ && "$dagger_version" == 'LOCAL-SNAPSHOT') {
+ details.useVersion 'LOCAL-SNAPSHOT'
+ details.because 'LOCAL-SNAPSHOT should act as latest version.'
+ }
+ }
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/gradle.properties b/javatests/artifacts/dagger-ksp/gradle.properties
new file mode 100644
index 0000000..e68633c
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/gradle.properties
@@ -0,0 +1,2 @@
+org.gradle.caching=true
+org.gradle.parallel=true
\ No newline at end of file
diff --git a/javatests/artifacts/dagger-ksp/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/dagger-ksp/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..5c2d1cf
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/javatests/artifacts/dagger-ksp/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger-ksp/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..0f80bbf
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/dagger-ksp/gradlew b/javatests/artifacts/dagger-ksp/gradlew
new file mode 100755
index 0000000..b0d6d0a
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or 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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/javatests/artifacts/dagger-ksp/java-app/build.gradle b/javatests/artifacts/dagger-ksp/java-app/build.gradle
new file mode 100644
index 0000000..19383c3
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/java-app/build.gradle
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id 'application'
+ id 'org.jetbrains.kotlin.jvm'
+ id 'com.google.devtools.ksp'
+}
+
+dependencies {
+ implementation "com.google.dagger:dagger:$dagger_version"
+ ksp "com.google.dagger:dagger-compiler:$dagger_version"
+
+ testImplementation 'com.google.truth:truth:1.0.1'
+ testImplementation 'junit:junit:4.13'
+}
+
+mainClassName = 'app.SimpleApplication'
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java b/javatests/artifacts/dagger-ksp/java-app/src/main/java/app/AssistedInjectClasses.java
similarity index 78%
rename from javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java
rename to javatests/artifacts/dagger-ksp/java-app/src/main/java/app/AssistedInjectClasses.java
index 246c541..06e1c45 100644
--- a/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java
+++ b/javatests/artifacts/dagger-ksp/java-app/src/main/java/app/AssistedInjectClasses.java
@@ -24,7 +24,7 @@
// This is a regression test for https://github.com/google/dagger/issues/2309
/** A simple, skeletal application that defines an assisted inject binding. */
-public class AssistedInjects {
+public class AssistedInjectClasses {
@Component
interface MyComponent {
FooFactory fooFactory();
@@ -38,8 +38,14 @@
}
static class Foo {
+ String assistedStr;
+ Bar bar;
+
@AssistedInject
- Foo(Bar bar, @Assisted String str) {}
+ Foo(Bar bar, @Assisted String assistedStr) {
+ this.assistedStr = assistedStr;
+ this.bar = bar;
+ }
}
@AssistedFactory
@@ -48,19 +54,18 @@
}
static class ParameterizedFoo<T1, T2> {
+ T1 t1;
+ T2 assistedT2;
+
@AssistedInject
- ParameterizedFoo(T1 t1, @Assisted T2 t2) {}
+ ParameterizedFoo(T1 t1, @Assisted T2 assistedT2) {
+ this.t1 = t1;
+ this.assistedT2 = assistedT2;
+ }
}
@AssistedFactory
interface ParameterizedFooFactory<T1, T2> {
ParameterizedFoo<T1, T2> create(T2 t2);
}
-
- public static void main(String[] args) {
- Foo foo = DaggerAssistedInjects_MyComponent.create().fooFactory().create("");
-
- ParameterizedFoo<Bar, String> parameterizedFoo =
- DaggerAssistedInjects_MyComponent.create().parameterizedFooFactory().create("");
- }
}
diff --git a/javatests/artifacts/dagger-ksp/java-app/src/main/java/app/SimpleComponentClasses.java b/javatests/artifacts/dagger-ksp/java-app/src/main/java/app/SimpleComponentClasses.java
new file mode 100644
index 0000000..4e02386
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/java-app/src/main/java/app/SimpleComponentClasses.java
@@ -0,0 +1,76 @@
+/*
+ * 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 app;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+/** A simple, skeletal application that defines a simple component. */
+public class SimpleComponentClasses {
+ static final class Foo {
+ @Inject
+ Foo() {}
+ }
+
+ @Singleton
+ static final class ScopedFoo {
+ @Inject
+ ScopedFoo() {}
+ }
+
+ static final class ProvidedFoo {
+ ProvidedFoo() {}
+ }
+
+ static final class ScopedProvidedFoo {
+ ScopedProvidedFoo() {}
+ }
+
+ @Module
+ static final class SimpleModule {
+ @Provides
+ static ProvidedFoo provideFoo() {
+ return new ProvidedFoo();
+ }
+
+ @Provides
+ @Singleton
+ static ScopedProvidedFoo provideScopedFoo() {
+ return new ScopedProvidedFoo();
+ }
+ }
+
+ @Singleton
+ @Component(modules = SimpleModule.class)
+ interface SimpleComponent {
+ Foo foo();
+
+ ScopedFoo scopedFoo();
+
+ ProvidedFoo providedFoo();
+
+ ScopedProvidedFoo scopedProvidedFoo();
+
+ Provider<ScopedFoo> scopedFooProvider();
+
+ Provider<ScopedProvidedFoo> scopedProvidedFooProvider();
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/java-app/src/test/java/app/AssistedInjectTest.java b/javatests/artifacts/dagger-ksp/java-app/src/test/java/app/AssistedInjectTest.java
new file mode 100644
index 0000000..33c73a3
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/java-app/src/test/java/app/AssistedInjectTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import app.AssistedInjectClasses.Bar;
+import app.AssistedInjectClasses.Foo;
+import app.AssistedInjectClasses.MyComponent;
+import app.AssistedInjectClasses.ParameterizedFoo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AssistedInjectTest {
+ private MyComponent component;
+
+ @Before
+ public void setUp() {
+ component = DaggerAssistedInjectClasses_MyComponent.create();
+ }
+
+ @Test
+ public void testFoo() {
+ Foo foo = component.fooFactory().create("str1");
+ assertThat(foo).isNotNull();
+ assertThat(foo.bar).isNotNull();
+ assertThat(foo.assistedStr).isEqualTo("str1");
+ }
+
+ @Test
+ public void testParameterizedFoo() {
+ ParameterizedFoo<Bar, String> parameterizedFoo =
+ component.parameterizedFooFactory().create("str2");
+ assertThat(parameterizedFoo).isNotNull();
+ assertThat(parameterizedFoo.t1).isNotNull();
+ assertThat(parameterizedFoo.assistedT2).isEqualTo("str2");
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/java-app/src/test/java/app/SimpleComponentTest.java b/javatests/artifacts/dagger-ksp/java-app/src/test/java/app/SimpleComponentTest.java
new file mode 100644
index 0000000..6af89bb
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/java-app/src/test/java/app/SimpleComponentTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import app.SimpleComponentClasses.SimpleComponent;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SimpleComponentTest {
+ private SimpleComponent component;
+
+ @Before
+ public void setUp() {
+ component = DaggerSimpleComponentClasses_SimpleComponent.create();
+ }
+
+ @Test
+ public void fooTest() {
+ assertThat(component.foo()).isNotNull();
+ assertThat(component.foo()).isNotEqualTo(component.foo());
+ }
+
+ @Test
+ public void scopedFooTest() {
+ assertThat(component.scopedFoo()).isNotNull();
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFoo());
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFooProvider().get());
+ }
+
+ @Test
+ public void providedFooTest() {
+ assertThat(component.providedFoo()).isNotNull();
+ assertThat(component.providedFoo()).isNotEqualTo(component.providedFoo());
+ }
+
+ @Test
+ public void scopedProvidedFooTest() {
+ assertThat(component.scopedProvidedFoo()).isNotNull();
+ assertThat(component.scopedProvidedFoo()).isEqualTo(component.scopedProvidedFoo());
+ assertThat(component.scopedProvidedFoo())
+ .isEqualTo(component.scopedProvidedFooProvider().get());
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/kotlin-app/build.gradle b/javatests/artifacts/dagger-ksp/kotlin-app/build.gradle
new file mode 100644
index 0000000..5dc8897
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/build.gradle
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id 'application'
+ id 'org.jetbrains.kotlin.jvm'
+ id 'com.google.devtools.ksp'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 8. This can be
+ // Java 8 because this is non-Android and so isn't required to be Java 11
+ // by AGP.
+ sourceCompatibility = JavaVersion.VERSION_1_8
+}
+
+dependencies {
+ implementation project(path: ':kotlin-app:kotlin-library')
+
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "com.google.dagger:dagger:$dagger_version"
+ ksp "com.google.dagger:dagger-compiler:$dagger_version"
+
+ // This is testImplementation rather than kaptTest because we're actually
+ // testing the reference to ComponentProcessor.
+ // See https://github.com/google/dagger/issues/2765
+ testImplementation "com.google.dagger:dagger-compiler:$dagger_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+ testImplementation "junit:junit:$junit_version"
+}
+
+application {
+ mainClass = 'app.SimpleApplicationKt'
+}
\ No newline at end of file
diff --git a/javatests/artifacts/dagger-ksp/kotlin-app/kotlin-library/build.gradle b/javatests/artifacts/dagger-ksp/kotlin-app/kotlin-library/build.gradle
new file mode 100644
index 0000000..b650b5f
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/kotlin-library/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id 'org.jetbrains.kotlin.jvm'
+ id 'com.google.devtools.ksp'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 8. Test
+ sourceCompatibility = JavaVersion.VERSION_1_8
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ implementation "com.google.dagger:dagger:$dagger_version"
+ ksp "com.google.dagger:dagger-compiler:$dagger_version"
+
+ // This is testImplementation rather than kaptTest because we're actually
+ // testing the reference to ComponentProcessor.
+ // See https://github.com/google/dagger/issues/2765
+ testImplementation "com.google.dagger:dagger-compiler:$dagger_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+ testImplementation "junit:junit:$junit_version"
+}
diff --git a/javatests/artifacts/dagger-ksp/kotlin-app/kotlin-library/src/main/kotlin/library/MySubcomponent.kt b/javatests/artifacts/dagger-ksp/kotlin-app/kotlin-library/src/main/kotlin/library/MySubcomponent.kt
new file mode 100644
index 0000000..70e9d3b
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/kotlin-library/src/main/kotlin/library/MySubcomponent.kt
@@ -0,0 +1,35 @@
+/*
+ * 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 library
+
+import dagger.BindsInstance
+import dagger.Subcomponent
+
+/**
+ * This subcomponent reproduces a regression in https://github.com/google/dagger/issues/2997.
+ */
+@Subcomponent
+abstract class MySubcomponent {
+ abstract fun instance(): InstanceType
+
+ @Subcomponent.Factory
+ interface Factory {
+ fun create(@BindsInstance instance: InstanceType): MySubcomponent
+ }
+}
+
+class InstanceType
diff --git a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt b/javatests/artifacts/dagger-ksp/kotlin-app/src/main/kotlin/app/AssistedInjectClasses.kt
similarity index 74%
rename from javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt
rename to javatests/artifacts/dagger-ksp/kotlin-app/src/main/kotlin/app/AssistedInjectClasses.kt
index 0fe65fd..1a612e9 100644
--- a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/src/main/kotlin/app/AssistedInjectClasses.kt
@@ -24,7 +24,7 @@
// This is a regression test for https://github.com/google/dagger/issues/2309
/** A simple, skeletal application that defines an assisted inject binding. */
-class AssistedInjects {
+class AssistedInjectClasses {
@Component
interface MyComponent {
fun fooFactory(): FooFactory
@@ -34,27 +34,19 @@
class Bar @Inject constructor()
- class Foo @AssistedInject constructor(val bar: Bar, @Assisted val str: String)
+ class Foo @AssistedInject constructor(val bar: Bar, @Assisted val assistedStr: String)
@AssistedFactory
interface FooFactory {
fun create(str: String): Foo
}
- class ParameterizedFoo<T1, T2> @AssistedInject constructor(val t1: T1, @Assisted val t2: T2)
+ class ParameterizedFoo<T1, T2>
+ @AssistedInject
+ constructor(val t1: T1, @Assisted val assistedT2: T2)
@AssistedFactory
interface ParameterizedFooFactory<T1, T2> {
fun create(t2: T2): ParameterizedFoo<T1, T2>
}
-
- companion object {
- // Called from SimpleApplication.main()
- fun main() {
- val foo: Foo = DaggerAssistedInjects_MyComponent.create().fooFactory().create("")
-
- val parameterizedFoo: ParameterizedFoo<Bar, String> =
- DaggerAssistedInjects_MyComponent.create().parameterizedFooFactory().create("")
- }
- }
}
diff --git a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt b/javatests/artifacts/dagger-ksp/kotlin-app/src/main/kotlin/app/SimpleComponentClasses.kt
similarity index 68%
rename from javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt
rename to javatests/artifacts/dagger-ksp/kotlin-app/src/main/kotlin/app/SimpleComponentClasses.kt
index 599d703..bcdbcce 100644
--- a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/src/main/kotlin/app/SimpleComponentClasses.kt
@@ -20,38 +20,35 @@
import dagger.Module
import dagger.Provides
import javax.inject.Inject
+import javax.inject.Provider
import javax.inject.Singleton
import library.MySubcomponent
/** A simple, skeletal application that defines a simple component. */
-class SimpleApplication {
+class SimpleComponentClasses {
class Foo @Inject constructor()
+ @Singleton class ScopedFoo @Inject constructor()
+ class ProvidedFoo
+ class ScopedProvidedFoo
@Module
object SimpleModule {
- @Provides
- fun provideFoo(): Foo {
- return Foo()
- }
+ @Provides fun provideFoo(): ProvidedFoo = ProvidedFoo()
+
+ @Provides @Singleton fun provideScopedFoo(): ScopedProvidedFoo = ScopedProvidedFoo()
}
@Singleton
@Component(modules = [SimpleModule::class])
interface SimpleComponent {
fun foo(): Foo
+ fun scopedFoo(): ScopedFoo
+ fun providedFoo(): ProvidedFoo
+ fun scopedProvidedFoo(): ScopedProvidedFoo
+ fun scopedFooProvider(): Provider<ScopedFoo>
+ fun scopedProvidedFooProvider(): Provider<ScopedProvidedFoo>
// Reproduces a regression in https://github.com/google/dagger/issues/2997.
fun mySubcomponentFactory(): MySubcomponent.Factory
}
-
- companion object {
- fun main() {
- val foo: Foo = DaggerSimpleApplication_SimpleComponent.create().foo()
- }
- }
-}
-
-fun main() {
- SimpleApplication.main()
- AssistedInjects.main()
}
diff --git a/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/AssistedInjectTest.kt b/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/AssistedInjectTest.kt
new file mode 100644
index 0000000..10a14ef
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/AssistedInjectTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import app.AssistedInjectClasses.MyComponent
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class AssistedInjectTest {
+ private lateinit var component: MyComponent
+
+ @Before
+ fun setUp() {
+ component = DaggerAssistedInjectClasses_MyComponent.create()
+ }
+
+ @Test
+ fun testFoo() {
+ val foo = component.fooFactory().create("str1")
+ assertThat(foo).isNotNull()
+ assertThat(foo.bar).isNotNull()
+ assertThat(foo.assistedStr).isEqualTo("str1")
+ }
+
+ @Test
+ fun testParameterizedFoo() {
+ val parameterizedFoo = component.parameterizedFooFactory().create("str2")
+ assertThat(parameterizedFoo).isNotNull()
+ assertThat(parameterizedFoo.t1).isNotNull()
+ assertThat(parameterizedFoo.assistedT2).isEqualTo("str2")
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/ComponentProcessorBuildTest.kt b/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/ComponentProcessorBuildTest.kt
new file mode 100644
index 0000000..1b050f8
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/ComponentProcessorBuildTest.kt
@@ -0,0 +1,36 @@
+/*
+ * 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 app
+
+import com.google.common.truth.Truth.assertThat
+import dagger.internal.codegen.ComponentProcessor
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ComponentProcessorBuildTest {
+
+ // This is a regression test for https://github.com/google/dagger/issues/2765
+ // to make sure ComponentProcessor builds in kotlin.
+ @Test
+ fun testComponentProcessor() {
+ val processor = ComponentProcessor.forTesting()
+
+ assertThat(processor).isNotNull()
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/SimpleComponentTest.kt b/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/SimpleComponentTest.kt
new file mode 100644
index 0000000..7bd94fd
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/kotlin-app/src/test/kotlin/app/SimpleComponentTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import app.SimpleComponentClasses.SimpleComponent
+import com.google.common.truth.Truth.assertThat
+import library.InstanceType
+import library.MySubcomponent
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class SimpleComponentTest {
+ private lateinit var component: SimpleComponent
+
+ @Before
+ fun setUp() {
+ component = DaggerSimpleComponentClasses_SimpleComponent.create()
+ }
+
+ @Test
+ fun fooTest() {
+ assertThat(component.foo()).isNotNull()
+ assertThat(component.foo()).isNotEqualTo(component.foo())
+ }
+
+ @Test
+ fun scopedFooTest() {
+ assertThat(component.scopedFoo()).isNotNull()
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFoo())
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFooProvider().get())
+ }
+
+ @Test
+ fun providedFooTest() {
+ assertThat(component.providedFoo()).isNotNull()
+ assertThat(component.providedFoo()).isNotEqualTo(component.providedFoo())
+ }
+
+ @Test
+ fun scopedProvidedFooTest() {
+ assertThat(component.scopedProvidedFoo()).isNotNull()
+ assertThat(component.scopedProvidedFoo()).isEqualTo(component.scopedProvidedFoo())
+ assertThat(component.scopedProvidedFoo()).isEqualTo(component.scopedProvidedFooProvider().get())
+ }
+
+ @Test
+ fun subcomponentTest() {
+ val instanceType = InstanceType()
+ val subcomponent = component.mySubcomponentFactory().create(instanceType)
+ assertThat(subcomponent).isNotNull()
+ assertThat(subcomponent.instance()).isEqualTo(instanceType)
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/settings.gradle b/javatests/artifacts/dagger-ksp/settings.gradle
new file mode 100644
index 0000000..e04b31a
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/settings.gradle
@@ -0,0 +1,7 @@
+rootProject.name = 'Dagger KSP Apps'
+include ':java-app'
+include ':kotlin-app'
+include ':kotlin-app:kotlin-library'
+include ':transitive-annotation-app'
+include ':transitive-annotation-app:library1'
+include ':transitive-annotation-app:library2'
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/build.gradle b/javatests/artifacts/dagger-ksp/transitive-annotation-app/build.gradle
new file mode 100644
index 0000000..d9e8723
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/build.gradle
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id 'application'
+ id 'org.jetbrains.kotlin.jvm'
+ id 'com.google.devtools.ksp'
+}
+
+dependencies {
+ implementation project(":transitive-annotation-app:library1")
+ implementation "com.google.dagger:dagger:$dagger_version"
+ ksp "com.google.dagger:dagger-compiler:$dagger_version"
+
+ testImplementation "junit:junit:$junit_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/build.gradle b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/build.gradle
new file mode 100644
index 0000000..7cfd83f
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/build.gradle
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id 'java-library'
+ id 'org.jetbrains.kotlin.jvm'
+ id 'com.google.devtools.ksp'
+}
+
+dependencies {
+ implementation project(":transitive-annotation-app:library2")
+ implementation "com.google.dagger:dagger:$dagger_version"
+ ksp "com.google.dagger:dagger-compiler:$dagger_version"
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java
new file mode 100644
index 0000000..8377d1c
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/AssistedFoo.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+import javax.inject.Inject;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public final class AssistedFoo extends FooBase {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ @MyQualifier
+ Dep daggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ AssistedFoo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ super(nonDaggerParameter);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @AssistedInject
+ AssistedFoo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Assisted
+ int i,
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {
+ super(dep);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ void daggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @AssistedFactory
+ public interface Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ AssistedFoo create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int i);
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/Dep.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/Dep.java
new file mode 100644
index 0000000..fa64e34
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/Dep.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+public final class Dep {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/Foo.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/Foo.java
new file mode 100644
index 0000000..062acbe
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/Foo.java
@@ -0,0 +1,93 @@
+/*
+ * 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 library1;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@Singleton
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public final class Foo extends FooBase {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ @MyQualifier
+ Dep daggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Foo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ super(nonDaggerParameter);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ Foo(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {
+ super(dep);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ void daggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/FooBase.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/FooBase.java
new file mode 100644
index 0000000..ad113dd
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/FooBase.java
@@ -0,0 +1,79 @@
+/*
+ * 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 library1;
+
+import javax.inject.Inject;
+import library2.MyTransitiveBaseAnnotation;
+import library2.MyTransitiveType;
+
+/** A baseclass for {@link Foo}. */
+@MyTransitiveBaseAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public class FooBase {
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int baseNonDaggerField;
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ @MyQualifier
+ Dep baseDaggerField;
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ FooBase(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ FooBase(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ void baseNonDaggerMethod(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int i) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Inject
+ void baseDaggerMethod(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @MyQualifier
+ Dep dep) {}
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java
new file mode 100644
index 0000000..58ba4e7
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyAnnotation.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+/** An annotation that is a direct dependency of the app. */
+public @interface MyAnnotation {
+ int value();
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java
new file mode 100644
index 0000000..78221ae
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyBaseComponent.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail on unresolvable transitive types used in non-dagger
+ * related elements and annotations.
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public abstract class MyBaseComponent {
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MyComponentModule.UnscopedQualifiedBindsType unscopedQualifiedBindsTypeBase();
+
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MyComponentModule.UnscopedUnqualifiedBindsType unscopedUnqualifiedBindsTypeBase();
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract void injectFooBase(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here)
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class) Foo binding);
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract static class Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MyBaseComponent create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyComponentModule myComponentModule,
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyComponentDependency myComponentDependency);
+
+ // Non-dagger factory code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java
new file mode 100644
index 0000000..fbaf588
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependency.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail on unresolvable transitive types used in non-dagger
+ * related elements and annotations.
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+public final class MyComponentDependency {
+ private final MyComponentDependencyBinding qualifiedMyComponentDependencyBinding =
+ new MyComponentDependencyBinding();
+ private final MyComponentDependencyBinding unqualifiedMyComponentDependencyBinding =
+ new MyComponentDependencyBinding();
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentDependency() {}
+
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentDependencyBinding qualifiedMyComponentDependencyBinding() {
+ return qualifiedMyComponentDependencyBinding;
+ }
+
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentDependencyBinding unqualifiedMyComponentDependencyBinding() {
+ return unqualifiedMyComponentDependencyBinding;
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java
new file mode 100644
index 0000000..c5d6bc9
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentDependencyBinding.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+/** Used as a binding in {@link MyComponentDependency}. */
+public final class MyComponentDependencyBinding {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java
new file mode 100644
index 0000000..048ed1a
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyComponentModule.java
@@ -0,0 +1,218 @@
+/*
+ * 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 library1;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@Module(includes = {MyComponentModule.MyAbstractModule.class})
+public final class MyComponentModule {
+ // Define bindings for each configuration: Scoped/Unscoped, Qualified/UnQualified, Provides/Binds
+ public static class ScopedQualifiedBindsType {}
+ public static final class ScopedQualifiedProvidesType extends ScopedQualifiedBindsType {}
+ public static class ScopedUnqualifiedBindsType {}
+ public static final class ScopedUnqualifiedProvidesType extends ScopedUnqualifiedBindsType {}
+ public static class UnscopedQualifiedBindsType {}
+ public static final class UnscopedQualifiedProvidesType extends UnscopedQualifiedBindsType {}
+ public static class UnscopedUnqualifiedBindsType {}
+ public static final class UnscopedUnqualifiedProvidesType extends UnscopedUnqualifiedBindsType {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @Singleton
+ @MyQualifier
+ ScopedQualifiedProvidesType scopedQualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new ScopedQualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @Singleton
+ ScopedUnqualifiedProvidesType scopedUnqualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new ScopedUnqualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @MyQualifier
+ UnscopedQualifiedProvidesType unscopedQualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new UnscopedQualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ UnscopedUnqualifiedProvidesType unscopedUnqualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ return new UnscopedUnqualifiedProvidesType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Module
+ interface MyAbstractModule {
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ @Singleton
+ @MyQualifier
+ ScopedQualifiedBindsType scopedQualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ ScopedQualifiedProvidesType scopedQualifiedProvidesType);
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ @Singleton
+ ScopedUnqualifiedBindsType scopedUnqualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class)
+ ScopedUnqualifiedProvidesType scopedUnqualifiedProvidesType);
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ @MyQualifier
+ UnscopedQualifiedBindsType unscopedQualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ UnscopedQualifiedProvidesType unscopedQualifiedProvidesType);
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Binds
+ UnscopedUnqualifiedBindsType unscopedUnqualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class)
+ UnscopedUnqualifiedProvidesType unscopedUnqualifiedProvidesType);
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ @MyQualifier
+ Dep provideQualifiedDep() {
+ return new Dep();
+ }
+
+ // Provide an unqualified Dep to ensure that if we accidentally drop the qualifier
+ // we'll get a runtime exception.
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Provides
+ Dep provideDep() {
+ throw new UnsupportedOperationException();
+ }
+
+ // Non-Dagger elements
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ private Dep dep;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ private MyTransitiveType nonDaggerField;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyComponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ Dep dep) {
+ this.dep = dep;
+ this.nonDaggerField = new MyTransitiveType();
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java
new file mode 100644
index 0000000..c1cb6ae
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyOtherAnnotation.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+/** An annotation that is a direct dependency of the app. */
+public @interface MyOtherAnnotation {
+ Class<?> value();
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java
new file mode 100644
index 0000000..c08ac98
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MyQualifier.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+public @interface MyQualifier {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java
new file mode 100644
index 0000000..61bb3f7
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentBinding.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+/** A simple binding that needs to be passed in when creating this component. */
+public final class MySubcomponentBinding {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java
new file mode 100644
index 0000000..da8de7b
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentModule.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import dagger.Module;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/** A simple module that needs to be passed in when creating this component. */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@Module
+public final class MySubcomponentModule {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MySubcomponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ int i) {}
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java
new file mode 100644
index 0000000..e76b0b6
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentScope.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import javax.inject.Scope;
+
+/** A scope for {@link MySubcomponent}. */
+@Scope
+public @interface MySubcomponentScope {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java
new file mode 100644
index 0000000..27045ea
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithBuilder.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+@MySubcomponentScope // TODO(b/269172737): Fix issue that requires reordering to build successfully.
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@Subcomponent(modules = MySubcomponentModule.class)
+public abstract class MySubcomponentWithBuilder {
+ @MyQualifier
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding qualifiedMySubcomponentBinding();
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding unqualifiedMySubcomponentBinding();
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract void injectFoo(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here)
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class) Foo foo);
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Subcomponent.Builder
+ public abstract static class Builder {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract Builder mySubcomponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentModule mySubcomponentModule);
+
+ @BindsInstance
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract Builder qualifiedMySubcomponentBinding(
+ @MyQualifier
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding subcomponentBinding);
+
+ @BindsInstance
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract Builder unqualifiedMySubcomponentBinding(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding subcomponentBinding);
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentWithBuilder build();
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public String nonDaggerField = "";
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static String nonDaggerStaticField = "";
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public void nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ String str) {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static void nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ String str) {}
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java
new file mode 100644
index 0000000..9005193
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library1/src/main/java/library1/MySubcomponentWithFactory.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 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 library1;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+import library2.MyTransitiveAnnotation;
+import library2.MyTransitiveType;
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * <p>During the compilation of {@code :app}, {@link MyTransitiveAnnotation} will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+@MySubcomponentScope // TODO(b/269172737): Fix issue that requires reordering to build successfully.
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType.class)
+@Subcomponent(modules = MySubcomponentModule.class)
+public abstract class MySubcomponentWithFactory {
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding qualifiedMySubcomponentBinding();
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentBinding unqualifiedMySubcomponentBinding();
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract void injectFoo(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here)
+ @MyAnnotation(MyTransitiveType.VALUE) @MyOtherAnnotation(MyTransitiveType.class) Foo foo);
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ @Subcomponent.Factory
+ public abstract static class Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public abstract MySubcomponentWithFactory create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentModule mySubcomponentModule,
+ @BindsInstance
+ @MyQualifier
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding qualifiedSubcomponentBinding,
+ @BindsInstance
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MySubcomponentBinding unqualifiedSubcomponentBinding);
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+ }
+
+ // Non-dagger code
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticField = null;
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public MyTransitiveType nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ public static MyTransitiveType nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType.class)
+ MyTransitiveType nonDaggerParameter) {
+ return nonDaggerParameter;
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/build.gradle b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/build.gradle
new file mode 100644
index 0000000..edb5753
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/build.gradle
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id 'java-library'
+ id 'org.jetbrains.kotlin.jvm'
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java
new file mode 100644
index 0000000..5f1f4bc
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveAnnotation.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 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 library2;
+
+/** A simple annotation that is a transitive dependency of the app. */
+public @interface MyTransitiveAnnotation {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java
new file mode 100644
index 0000000..dcc6739
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveBaseAnnotation.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 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 library2;
+
+/** A simple annotation that is a transitive dependency of the app. */
+public @interface MyTransitiveBaseAnnotation {}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java
new file mode 100644
index 0000000..c6ecd5d
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/library2/src/main/java/library2/MyTransitiveType.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 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 library2;
+
+
+/** A class that is a transitive dependency of the app. */
+public final class MyTransitiveType {
+ public static final int VALUE = 3;
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/main/java/app/MyComponent.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/main/java/app/MyComponent.java
new file mode 100644
index 0000000..ee55d3a
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/main/java/app/MyComponent.java
@@ -0,0 +1,73 @@
+/*
+ * 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 app;
+
+import dagger.Component;
+import javax.inject.Singleton;
+import library1.AssistedFoo;
+import library1.Foo;
+import library1.MyBaseComponent;
+import library1.MyComponentDependency;
+import library1.MyComponentDependencyBinding;
+import library1.MyComponentModule;
+import library1.MyQualifier;
+import library1.MySubcomponentWithBuilder;
+import library1.MySubcomponentWithFactory;
+
+@Singleton
+@Component(dependencies = MyComponentDependency.class, modules = MyComponentModule.class)
+abstract class MyComponent extends MyBaseComponent {
+ abstract Foo foo();
+
+ abstract AssistedFoo.Factory assistedFooFactory();
+
+ @MyQualifier
+ abstract MyComponentModule.ScopedQualifiedBindsType scopedQualifiedBindsType();
+
+ abstract MyComponentModule.ScopedUnqualifiedBindsType scopedUnqualifiedBindsType();
+
+ @MyQualifier
+ abstract MyComponentModule.UnscopedQualifiedBindsType unscopedQualifiedBindsType();
+
+ abstract MyComponentModule.UnscopedUnqualifiedBindsType unscopedUnqualifiedBindsType();
+
+ @MyQualifier
+ abstract MyComponentModule.ScopedQualifiedProvidesType scopedQualifiedProvidesType();
+
+ abstract MyComponentModule.ScopedUnqualifiedProvidesType scopedUnqualifiedProvidesType();
+
+ @MyQualifier
+ abstract MyComponentModule.UnscopedQualifiedProvidesType unscopedQualifiedProvidesType();
+
+ abstract MyComponentModule.UnscopedUnqualifiedProvidesType unscopedUnqualifiedProvidesType();
+
+ abstract MySubcomponentWithFactory.Factory mySubcomponentWithFactory();
+
+ abstract MySubcomponentWithBuilder.Builder mySubcomponentWithBuilder();
+
+ @MyQualifier
+ abstract MyComponentDependencyBinding qualifiedMyComponentDependencyBinding();
+
+ abstract MyComponentDependencyBinding unqualifiedMyComponentDependencyBinding();
+
+ @Component.Factory
+ abstract static class Factory extends MyBaseComponent.Factory {
+ public abstract MyComponent create(
+ MyComponentModule myComponentModule,
+ MyComponentDependency myComponentDependency);
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MyComponentTest.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MyComponentTest.java
new file mode 100644
index 0000000..438d5db
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MyComponentTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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 app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import library1.Dep;
+import library1.MyComponentDependency;
+import library1.MyComponentModule;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class MyComponentTest {
+ private MyComponent component;
+
+ @Before
+ public void setup() {
+ component = DaggerMyComponent.factory()
+ .create(new MyComponentModule(new Dep()), new MyComponentDependency());
+ }
+
+ @Test
+ public void testFooIsScoped() {
+ assertThat(component.foo()).isEqualTo(component.foo());
+ }
+
+ @Test
+ public void testAssistedFoo() {
+ assertThat(component.assistedFooFactory().create(5)).isNotNull();
+ }
+
+ @Test
+ public void testScopedQualifiedBindsTypeIsScoped() {
+ assertThat(component.scopedQualifiedBindsType())
+ .isEqualTo(component.scopedQualifiedBindsType());
+ }
+
+ @Test
+ public void testScopedUnqualifiedBindsTypeIsScoped() {
+ assertThat(component.scopedUnqualifiedBindsType())
+ .isEqualTo(component.scopedUnqualifiedBindsType());
+ }
+
+ @Test
+ public void testUnscopedQualifiedBindsTypeIsNotScoped() {
+ assertThat(component.unscopedQualifiedBindsType())
+ .isNotEqualTo(component.unscopedQualifiedBindsType());
+ }
+
+ @Test
+ public void testUnscopedUnqualifiedBindsTypeIsNotScoped() {
+ assertThat(component.unscopedUnqualifiedBindsType())
+ .isNotEqualTo(component.unscopedUnqualifiedBindsType());
+ }
+
+ @Test
+ public void testScopedQualifiedProvidesTypeIsScoped() {
+ assertThat(component.scopedQualifiedProvidesType())
+ .isEqualTo(component.scopedQualifiedProvidesType());
+ }
+
+ @Test
+ public void testScopedUnqualifiedProvidesTypeIsScoped() {
+ assertThat(component.scopedUnqualifiedProvidesType())
+ .isEqualTo(component.scopedUnqualifiedProvidesType());
+ }
+
+ @Test
+ public void testUnscopedQualifiedProvidesTypeIsNotScoped() {
+ assertThat(component.unscopedQualifiedProvidesType())
+ .isNotEqualTo(component.unscopedQualifiedProvidesType());
+ }
+
+ @Test
+ public void testUnscopedUnqualifiedProvidesTypeIsNotScoped() {
+ assertThat(component.unscopedUnqualifiedProvidesType())
+ .isNotEqualTo(component.unscopedUnqualifiedProvidesType());
+ }
+
+ @Test
+ public void testMyComponentDependencyBinding() {
+ assertThat(component.qualifiedMyComponentDependencyBinding())
+ .isNotEqualTo(component.unqualifiedMyComponentDependencyBinding());
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java
new file mode 100644
index 0000000..3db241b
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MySubcomponentWithBuilderTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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 app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import library1.Dep;
+import library1.MyComponentDependency;
+import library1.MyComponentModule;
+import library1.MySubcomponentBinding;
+import library1.MySubcomponentModule;
+import library1.MySubcomponentWithBuilder;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class MySubcomponentWithBuilderTest {
+ private MySubcomponentWithBuilder subcomponentWithBuilder;
+
+ @Before
+ public void setup() {
+ subcomponentWithBuilder =
+ DaggerMyComponent.factory()
+ .create(new MyComponentModule(new Dep()), new MyComponentDependency())
+ .mySubcomponentWithBuilder()
+ .mySubcomponentModule(new MySubcomponentModule(3))
+ .qualifiedMySubcomponentBinding(new MySubcomponentBinding())
+ .unqualifiedMySubcomponentBinding(new MySubcomponentBinding())
+ .build();
+ }
+
+ // Test that the qualified and unqualified bindings are two separate objects
+ @Test
+ public void testMySubcomponentBinding() {
+ assertThat(subcomponentWithBuilder.qualifiedMySubcomponentBinding())
+ .isNotEqualTo(subcomponentWithBuilder.unqualifiedMySubcomponentBinding());
+ }
+}
diff --git a/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java
new file mode 100644
index 0000000..a45dcc7
--- /dev/null
+++ b/javatests/artifacts/dagger-ksp/transitive-annotation-app/src/test/java/app/MySubcomponentWithFactoryTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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 app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import library1.Dep;
+import library1.MyComponentDependency;
+import library1.MyComponentModule;
+import library1.MySubcomponentBinding;
+import library1.MySubcomponentModule;
+import library1.MySubcomponentWithFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class MySubcomponentWithFactoryTest {
+ private MySubcomponentWithFactory subcomponentWithFactory;
+
+ @Before
+ public void setup() {
+ subcomponentWithFactory =
+ DaggerMyComponent.factory()
+ .create(new MyComponentModule(new Dep()), new MyComponentDependency())
+ .mySubcomponentWithFactory()
+ .create(
+ new MySubcomponentModule(1),
+ new MySubcomponentBinding(),
+ new MySubcomponentBinding());
+ }
+
+ // Test that the qualified and unqualified bindings are two separate objects
+ @Test
+ public void testMySubcomponentBinding() {
+ assertThat(subcomponentWithFactory.qualifiedMySubcomponentBinding())
+ .isNotEqualTo(subcomponentWithFactory.unqualifiedMySubcomponentBinding());
+ }
+}
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java
index efadf67..d3c4683 100644
--- a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveComponentDependenciesTest.java
@@ -61,6 +61,7 @@
+ "\n "
+ "\n Dependency trace:"
+ "\n => element (CLASS): libraryB.ComponentB"
+ + "\n => annotation type: dagger.Component"
+ "\n => annotation: @dagger.Component("
+ "modules={}, dependencies={libraryA.ComponentA})"
+ "\n => annotation value (TYPE_ARRAY): dependencies={libraryA.ComponentA}"
diff --git a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java
index 4673c86..d249c68 100644
--- a/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java
+++ b/javatests/artifacts/dagger/build-tests/src/test/java/buildtests/TransitiveSubcomponentModulesTest.java
@@ -74,6 +74,7 @@
+ "\n "
+ "\n Dependency trace:"
+ "\n => element (CLASS): library1.MySubcomponent"
+ + "\n => annotation type: dagger.Subcomponent"
+ "\n => annotation: @dagger.Subcomponent(modules={library2.TransitiveModule})"
+ "\n => annotation value (TYPE_ARRAY): modules={library2.TransitiveModule}"
+ "\n => annotation value (TYPE): modules=library2.TransitiveModule";
@@ -112,6 +113,7 @@
+ "\n "
+ "\n Dependency trace:"
+ "\n => element (INTERFACE): library1.IncludesTransitiveModule"
+ + "\n => annotation type: dagger.Module"
+ "\n => annotation: "
+ "@dagger.Module(includes={library2.TransitiveModule}, subcomponents={})"
+ "\n => annotation value (TYPE_ARRAY): includes={library2.TransitiveModule}"
diff --git a/javatests/artifacts/dagger/java-app/build.gradle b/javatests/artifacts/dagger/java-app/build.gradle
index e709d7d..16c6e66 100644
--- a/javatests/artifacts/dagger/java-app/build.gradle
+++ b/javatests/artifacts/dagger/java-app/build.gradle
@@ -27,6 +27,9 @@
dependencies {
implementation "com.google.dagger:dagger:$dagger_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
+
+ testImplementation 'com.google.truth:truth:1.0.1'
+ testImplementation 'junit:junit:4.13'
}
mainClassName = 'app.SimpleApplication'
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java b/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjectClasses.java
similarity index 78%
copy from javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java
copy to javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjectClasses.java
index 246c541..06e1c45 100644
--- a/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjects.java
+++ b/javatests/artifacts/dagger/java-app/src/main/java/app/AssistedInjectClasses.java
@@ -24,7 +24,7 @@
// This is a regression test for https://github.com/google/dagger/issues/2309
/** A simple, skeletal application that defines an assisted inject binding. */
-public class AssistedInjects {
+public class AssistedInjectClasses {
@Component
interface MyComponent {
FooFactory fooFactory();
@@ -38,8 +38,14 @@
}
static class Foo {
+ String assistedStr;
+ Bar bar;
+
@AssistedInject
- Foo(Bar bar, @Assisted String str) {}
+ Foo(Bar bar, @Assisted String assistedStr) {
+ this.assistedStr = assistedStr;
+ this.bar = bar;
+ }
}
@AssistedFactory
@@ -48,19 +54,18 @@
}
static class ParameterizedFoo<T1, T2> {
+ T1 t1;
+ T2 assistedT2;
+
@AssistedInject
- ParameterizedFoo(T1 t1, @Assisted T2 t2) {}
+ ParameterizedFoo(T1 t1, @Assisted T2 assistedT2) {
+ this.t1 = t1;
+ this.assistedT2 = assistedT2;
+ }
}
@AssistedFactory
interface ParameterizedFooFactory<T1, T2> {
ParameterizedFoo<T1, T2> create(T2 t2);
}
-
- public static void main(String[] args) {
- Foo foo = DaggerAssistedInjects_MyComponent.create().fooFactory().create("");
-
- ParameterizedFoo<Bar, String> parameterizedFoo =
- DaggerAssistedInjects_MyComponent.create().parameterizedFooFactory().create("");
- }
}
diff --git a/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleApplication.java b/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleApplication.java
deleted file mode 100644
index dfe95ca..0000000
--- a/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleApplication.java
+++ /dev/null
@@ -1,51 +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 app;
-
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** A simple, skeletal application that defines a simple component. */
-public class SimpleApplication {
- static final class Foo {
- @Inject Foo() {}
- }
-
- @Module
- static final class SimpleModule {
- @Provides
- static Foo provideFoo() {
- return new Foo();
- }
- }
-
- @Singleton
- @Component(modules = { SimpleModule.class })
- interface SimpleComponent {
- Foo foo();
- }
-
- public static void main(String[] args) {
- Foo foo = DaggerSimpleApplication_SimpleComponent.create().foo();
-
- // Execute other classes
- AssistedInjects.main(args);
- }
-}
diff --git a/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleComponentClasses.java b/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleComponentClasses.java
new file mode 100644
index 0000000..4e02386
--- /dev/null
+++ b/javatests/artifacts/dagger/java-app/src/main/java/app/SimpleComponentClasses.java
@@ -0,0 +1,76 @@
+/*
+ * 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 app;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+/** A simple, skeletal application that defines a simple component. */
+public class SimpleComponentClasses {
+ static final class Foo {
+ @Inject
+ Foo() {}
+ }
+
+ @Singleton
+ static final class ScopedFoo {
+ @Inject
+ ScopedFoo() {}
+ }
+
+ static final class ProvidedFoo {
+ ProvidedFoo() {}
+ }
+
+ static final class ScopedProvidedFoo {
+ ScopedProvidedFoo() {}
+ }
+
+ @Module
+ static final class SimpleModule {
+ @Provides
+ static ProvidedFoo provideFoo() {
+ return new ProvidedFoo();
+ }
+
+ @Provides
+ @Singleton
+ static ScopedProvidedFoo provideScopedFoo() {
+ return new ScopedProvidedFoo();
+ }
+ }
+
+ @Singleton
+ @Component(modules = SimpleModule.class)
+ interface SimpleComponent {
+ Foo foo();
+
+ ScopedFoo scopedFoo();
+
+ ProvidedFoo providedFoo();
+
+ ScopedProvidedFoo scopedProvidedFoo();
+
+ Provider<ScopedFoo> scopedFooProvider();
+
+ Provider<ScopedProvidedFoo> scopedProvidedFooProvider();
+ }
+}
diff --git a/javatests/artifacts/dagger/java-app/src/test/java/app/AssistedInjectTest.java b/javatests/artifacts/dagger/java-app/src/test/java/app/AssistedInjectTest.java
new file mode 100644
index 0000000..33c73a3
--- /dev/null
+++ b/javatests/artifacts/dagger/java-app/src/test/java/app/AssistedInjectTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import app.AssistedInjectClasses.Bar;
+import app.AssistedInjectClasses.Foo;
+import app.AssistedInjectClasses.MyComponent;
+import app.AssistedInjectClasses.ParameterizedFoo;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AssistedInjectTest {
+ private MyComponent component;
+
+ @Before
+ public void setUp() {
+ component = DaggerAssistedInjectClasses_MyComponent.create();
+ }
+
+ @Test
+ public void testFoo() {
+ Foo foo = component.fooFactory().create("str1");
+ assertThat(foo).isNotNull();
+ assertThat(foo.bar).isNotNull();
+ assertThat(foo.assistedStr).isEqualTo("str1");
+ }
+
+ @Test
+ public void testParameterizedFoo() {
+ ParameterizedFoo<Bar, String> parameterizedFoo =
+ component.parameterizedFooFactory().create("str2");
+ assertThat(parameterizedFoo).isNotNull();
+ assertThat(parameterizedFoo.t1).isNotNull();
+ assertThat(parameterizedFoo.assistedT2).isEqualTo("str2");
+ }
+}
diff --git a/javatests/artifacts/dagger/java-app/src/test/java/app/SimpleComponentTest.java b/javatests/artifacts/dagger/java-app/src/test/java/app/SimpleComponentTest.java
new file mode 100644
index 0000000..6af89bb
--- /dev/null
+++ b/javatests/artifacts/dagger/java-app/src/test/java/app/SimpleComponentTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import app.SimpleComponentClasses.SimpleComponent;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class SimpleComponentTest {
+ private SimpleComponent component;
+
+ @Before
+ public void setUp() {
+ component = DaggerSimpleComponentClasses_SimpleComponent.create();
+ }
+
+ @Test
+ public void fooTest() {
+ assertThat(component.foo()).isNotNull();
+ assertThat(component.foo()).isNotEqualTo(component.foo());
+ }
+
+ @Test
+ public void scopedFooTest() {
+ assertThat(component.scopedFoo()).isNotNull();
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFoo());
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFooProvider().get());
+ }
+
+ @Test
+ public void providedFooTest() {
+ assertThat(component.providedFoo()).isNotNull();
+ assertThat(component.providedFoo()).isNotEqualTo(component.providedFoo());
+ }
+
+ @Test
+ public void scopedProvidedFooTest() {
+ assertThat(component.scopedProvidedFoo()).isNotNull();
+ assertThat(component.scopedProvidedFoo()).isEqualTo(component.scopedProvidedFoo());
+ assertThat(component.scopedProvidedFoo())
+ .isEqualTo(component.scopedProvidedFooProvider().get());
+ }
+}
diff --git a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjectClasses.kt
similarity index 74%
copy from javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt
copy to javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjectClasses.kt
index 0fe65fd..1a612e9 100644
--- a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjects.kt
+++ b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/AssistedInjectClasses.kt
@@ -24,7 +24,7 @@
// This is a regression test for https://github.com/google/dagger/issues/2309
/** A simple, skeletal application that defines an assisted inject binding. */
-class AssistedInjects {
+class AssistedInjectClasses {
@Component
interface MyComponent {
fun fooFactory(): FooFactory
@@ -34,27 +34,19 @@
class Bar @Inject constructor()
- class Foo @AssistedInject constructor(val bar: Bar, @Assisted val str: String)
+ class Foo @AssistedInject constructor(val bar: Bar, @Assisted val assistedStr: String)
@AssistedFactory
interface FooFactory {
fun create(str: String): Foo
}
- class ParameterizedFoo<T1, T2> @AssistedInject constructor(val t1: T1, @Assisted val t2: T2)
+ class ParameterizedFoo<T1, T2>
+ @AssistedInject
+ constructor(val t1: T1, @Assisted val assistedT2: T2)
@AssistedFactory
interface ParameterizedFooFactory<T1, T2> {
fun create(t2: T2): ParameterizedFoo<T1, T2>
}
-
- companion object {
- // Called from SimpleApplication.main()
- fun main() {
- val foo: Foo = DaggerAssistedInjects_MyComponent.create().fooFactory().create("")
-
- val parameterizedFoo: ParameterizedFoo<Bar, String> =
- DaggerAssistedInjects_MyComponent.create().parameterizedFooFactory().create("")
- }
- }
}
diff --git a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleComponentClasses.kt
similarity index 68%
copy from javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt
copy to javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleComponentClasses.kt
index 599d703..bcdbcce 100644
--- a/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleApplication.kt
+++ b/javatests/artifacts/dagger/kotlin-app/src/main/kotlin/app/SimpleComponentClasses.kt
@@ -20,38 +20,35 @@
import dagger.Module
import dagger.Provides
import javax.inject.Inject
+import javax.inject.Provider
import javax.inject.Singleton
import library.MySubcomponent
/** A simple, skeletal application that defines a simple component. */
-class SimpleApplication {
+class SimpleComponentClasses {
class Foo @Inject constructor()
+ @Singleton class ScopedFoo @Inject constructor()
+ class ProvidedFoo
+ class ScopedProvidedFoo
@Module
object SimpleModule {
- @Provides
- fun provideFoo(): Foo {
- return Foo()
- }
+ @Provides fun provideFoo(): ProvidedFoo = ProvidedFoo()
+
+ @Provides @Singleton fun provideScopedFoo(): ScopedProvidedFoo = ScopedProvidedFoo()
}
@Singleton
@Component(modules = [SimpleModule::class])
interface SimpleComponent {
fun foo(): Foo
+ fun scopedFoo(): ScopedFoo
+ fun providedFoo(): ProvidedFoo
+ fun scopedProvidedFoo(): ScopedProvidedFoo
+ fun scopedFooProvider(): Provider<ScopedFoo>
+ fun scopedProvidedFooProvider(): Provider<ScopedProvidedFoo>
// Reproduces a regression in https://github.com/google/dagger/issues/2997.
fun mySubcomponentFactory(): MySubcomponent.Factory
}
-
- companion object {
- fun main() {
- val foo: Foo = DaggerSimpleApplication_SimpleComponent.create().foo()
- }
- }
-}
-
-fun main() {
- SimpleApplication.main()
- AssistedInjects.main()
}
diff --git a/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/AssistedInjectTest.kt b/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/AssistedInjectTest.kt
new file mode 100644
index 0000000..10a14ef
--- /dev/null
+++ b/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/AssistedInjectTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import app.AssistedInjectClasses.MyComponent
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class AssistedInjectTest {
+ private lateinit var component: MyComponent
+
+ @Before
+ fun setUp() {
+ component = DaggerAssistedInjectClasses_MyComponent.create()
+ }
+
+ @Test
+ fun testFoo() {
+ val foo = component.fooFactory().create("str1")
+ assertThat(foo).isNotNull()
+ assertThat(foo.bar).isNotNull()
+ assertThat(foo.assistedStr).isEqualTo("str1")
+ }
+
+ @Test
+ fun testParameterizedFoo() {
+ val parameterizedFoo = component.parameterizedFooFactory().create("str2")
+ assertThat(parameterizedFoo).isNotNull()
+ assertThat(parameterizedFoo.t1).isNotNull()
+ assertThat(parameterizedFoo.assistedT2).isEqualTo("str2")
+ }
+}
diff --git a/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/SimpleComponentTest.kt b/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/SimpleComponentTest.kt
new file mode 100644
index 0000000..f111dfe
--- /dev/null
+++ b/javatests/artifacts/dagger/kotlin-app/src/test/kotlin/app/SimpleComponentTest.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import app.SimpleComponentClasses.SimpleComponent
+import com.google.common.truth.Truth.assertThat
+import library.InstanceType
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class SimpleComponentTest {
+ private lateinit var component: SimpleComponent
+
+ @Before
+ fun setUp() {
+ component = DaggerSimpleComponentClasses_SimpleComponent.create()
+ }
+
+ @Test
+ fun fooTest() {
+ assertThat(component.foo()).isNotNull()
+ assertThat(component.foo()).isNotEqualTo(component.foo())
+ }
+
+ @Test
+ fun scopedFooTest() {
+ assertThat(component.scopedFoo()).isNotNull()
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFoo())
+ assertThat(component.scopedFoo()).isEqualTo(component.scopedFooProvider().get())
+ }
+
+ @Test
+ fun providedFooTest() {
+ assertThat(component.providedFoo()).isNotNull()
+ assertThat(component.providedFoo()).isNotEqualTo(component.providedFoo())
+ }
+
+ @Test
+ fun scopedProvidedFooTest() {
+ assertThat(component.scopedProvidedFoo()).isNotNull()
+ assertThat(component.scopedProvidedFoo()).isEqualTo(component.scopedProvidedFoo())
+ assertThat(component.scopedProvidedFoo()).isEqualTo(component.scopedProvidedFooProvider().get())
+ }
+
+ @Test
+ fun subcomponentTest() {
+ val instanceType = InstanceType()
+ val subcomponent = component.mySubcomponentFactory().create(instanceType)
+ assertThat(subcomponent).isNotNull()
+ assertThat(subcomponent.instance()).isEqualTo(instanceType)
+ }
+}
diff --git a/javatests/artifacts/dagger/settings.gradle b/javatests/artifacts/dagger/settings.gradle
index 6ba1bae..89d5acc 100644
--- a/javatests/artifacts/dagger/settings.gradle
+++ b/javatests/artifacts/dagger/settings.gradle
@@ -6,3 +6,6 @@
include ':transitive-annotation-app'
include ':transitive-annotation-app:library1'
include ':transitive-annotation-app:library2'
+include ':transitive-annotation-kotlin-app'
+include ':transitive-annotation-kotlin-app:library1'
+include ':transitive-annotation-kotlin-app:library2'
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle
new file mode 100644
index 0000000..1b0c04d
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'application'
+ id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
+ id 'org.jetbrains.kotlin.kapt' version "$kotlin_version"
+}
+
+java {
+ // Make sure the generated source is compatible with Java 7.
+ sourceCompatibility = JavaVersion.VERSION_1_7
+}
+
+kapt {
+ correctErrorTypes = true
+}
+
+dependencies {
+ implementation project(":transitive-annotation-kotlin-app:library1")
+ implementation "com.google.dagger:dagger:$dagger_version"
+ kapt "com.google.dagger:dagger-compiler:$dagger_version"
+
+ testImplementation "junit:junit:$junit_version"
+ testImplementation "com.google.truth:truth:$truth_version"
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle
new file mode 100644
index 0000000..3875913
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/build.gradle
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'java-library'
+ id 'org.jetbrains.kotlin.jvm'
+ id 'org.jetbrains.kotlin.kapt'
+}
+
+java {
+ // Make sure the generated source is compatible with Java 7.
+ sourceCompatibility = JavaVersion.VERSION_1_7
+}
+
+kapt {
+ correctErrorTypes = true
+}
+
+dependencies {
+ implementation project(":transitive-annotation-kotlin-app:library2")
+ implementation "com.google.dagger:dagger:$dagger_version"
+ kapt "com.google.dagger:dagger-compiler:$dagger_version"
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/AssistedFoo.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/AssistedFoo.kt
new file mode 100644
index 0000000..69c3941
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/AssistedFoo.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import javax.inject.Inject
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ *
+ * During the compilation of `:app`, [MyTransitiveAnnotation] will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+class AssistedFoo : FooBase {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ @MyQualifier
+ lateinit var daggerField: Dep
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ internal constructor(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ) : super(nonDaggerParameter)
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @AssistedInject
+ internal constructor(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Assisted
+ i: Int,
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @MyQualifier
+ dep: Dep
+ ) : super(dep)
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ fun daggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @MyQualifier
+ dep: Dep
+ ) {}
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @AssistedFactory
+ interface Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ i: Int
+ ): AssistedFoo
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/Dep.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/Dep.kt
new file mode 100644
index 0000000..09b9795
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/Dep.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+class Dep
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/Foo.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/Foo.kt
new file mode 100644
index 0000000..3406d56
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/Foo.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import javax.inject.Inject
+import javax.inject.Singleton
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ *
+ * During the compilation of `:app`, [MyTransitiveAnnotation] will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@Singleton
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+class Foo : FooBase {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ @MyQualifier
+ lateinit var daggerField: Dep
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ internal constructor(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ) : super(nonDaggerParameter)
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ internal constructor(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @MyQualifier
+ dep: Dep
+ ) : super(dep)
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ fun daggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @MyQualifier
+ dep: Dep
+ ) {}
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/FooBase.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/FooBase.kt
new file mode 100644
index 0000000..0d5807e
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/FooBase.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import javax.inject.Inject
+import library2.MyTransitiveBaseAnnotation
+import library2.MyTransitiveType
+
+/** A baseclass for [Foo]. */
+@MyTransitiveBaseAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+open class FooBase {
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ var baseNonDaggerField = 0
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ @MyQualifier
+ lateinit var baseDaggerField: Dep
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ internal constructor(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ internal constructor(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @MyQualifier
+ dep: Dep
+ ) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun baseNonDaggerMethod(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ i: Int
+ ) {}
+
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Inject
+ fun baseDaggerMethod(
+ @MyTransitiveBaseAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @MyQualifier
+ dep: Dep
+ ) {}
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyAnnotation.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyAnnotation.kt
new file mode 100644
index 0000000..2022813
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyAnnotation.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+/** An annotation that is a direct dependency of the app. */
+annotation class MyAnnotation(val value: Int)
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyBaseComponent.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyBaseComponent.kt
new file mode 100644
index 0000000..7ee914c
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyBaseComponent.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail on unresolvable transitive types used in non-dagger
+ * related elements and annotations.
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+abstract class MyBaseComponent {
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun unscopedQualifiedBindsTypeBase(): MyComponentModule.UnscopedQualifiedBindsType
+
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun unscopedUnqualifiedBindsTypeBase(): MyComponentModule.UnscopedUnqualifiedBindsType
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun injectFooBase(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here)
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ binding: Foo
+ )
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract class Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ myComponentModule: MyComponentModule,
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ myComponentDependency: MyComponentDependency
+ ): MyBaseComponent
+
+ // Non-dagger factory code
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerStaticField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+ }
+
+ // Non-dagger code
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerStaticField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentDependency.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentDependency.kt
new file mode 100644
index 0000000..31c3296
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentDependency.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail on unresolvable transitive types used in non-dagger
+ * related elements and annotations.
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+class MyComponentDependency
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+constructor() {
+ private val qualifiedMyComponentDependencyBinding = MyComponentDependencyBinding()
+ private val unqualifiedMyComponentDependencyBinding = MyComponentDependencyBinding()
+
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun qualifiedMyComponentDependencyBinding(): MyComponentDependencyBinding {
+ return qualifiedMyComponentDependencyBinding
+ }
+
+ // @MyTransitiveAnnotation cannot be used here.
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun unqualifiedMyComponentDependencyBinding(): MyComponentDependencyBinding {
+ return unqualifiedMyComponentDependencyBinding
+ }
+
+ // Non-dagger code
+ // Note: As this is supposed to be non-dagger code we use @JvmField to avoid the getter method,
+ // otherwise, Dagger will interpret the method as contributing a binding.
+ @JvmField
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ var nonDaggerField: MyTransitiveType? = null
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerStaticField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentDependencyBinding.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentDependencyBinding.kt
new file mode 100644
index 0000000..4015f48
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentDependencyBinding.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+/** Used as a binding in [MyComponentDependency]. */
+class MyComponentDependencyBinding
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentModule.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentModule.kt
new file mode 100644
index 0000000..8ee1fd0
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyComponentModule.kt
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import javax.inject.Singleton
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ *
+ * During the compilation of `:app`, [MyTransitiveAnnotation] will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+@Module(includes = [MyComponentModule.MyAbstractModule::class])
+class MyComponentModule
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+constructor(
+ // Non-Dagger elements
+ @field:MyOtherAnnotation(MyTransitiveType::class)
+ @field:MyAnnotation(MyTransitiveType.VALUE)
+ @field:MyTransitiveAnnotation
+ @param:MyTransitiveAnnotation
+ @param:MyAnnotation(MyTransitiveType.VALUE)
+ @param:MyOtherAnnotation(MyTransitiveType::class)
+ private val dep: Dep
+) {
+ // Define bindings for each configuration: Scoped/Unscoped, Qualified/UnQualified, Provides/Binds
+ open class ScopedQualifiedBindsType
+ class ScopedQualifiedProvidesType : ScopedQualifiedBindsType()
+ open class ScopedUnqualifiedBindsType
+ class ScopedUnqualifiedProvidesType : ScopedUnqualifiedBindsType()
+ open class UnscopedQualifiedBindsType
+ class UnscopedQualifiedProvidesType : UnscopedQualifiedBindsType()
+ open class UnscopedUnqualifiedBindsType
+ class UnscopedUnqualifiedProvidesType : UnscopedUnqualifiedBindsType()
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Provides
+ @Singleton
+ @MyQualifier
+ fun scopedQualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ dep: Dep
+ ): ScopedQualifiedProvidesType = ScopedQualifiedProvidesType()
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Provides
+ @Singleton
+ fun scopedUnqualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ dep: Dep
+ ): ScopedUnqualifiedProvidesType = ScopedUnqualifiedProvidesType()
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Provides
+ @MyQualifier
+ fun unscopedQualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ dep: Dep
+ ): UnscopedQualifiedProvidesType = UnscopedQualifiedProvidesType()
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Provides
+ fun unscopedUnqualifiedProvidesType(
+ @MyQualifier
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ dep: Dep
+ ): UnscopedUnqualifiedProvidesType = UnscopedUnqualifiedProvidesType()
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Module
+ internal interface MyAbstractModule {
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Binds
+ @Singleton
+ @MyQualifier
+ fun scopedQualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ scopedQualifiedProvidesType: ScopedQualifiedProvidesType
+ ): ScopedQualifiedBindsType
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Binds
+ @Singleton
+ fun scopedUnqualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ scopedUnqualifiedProvidesType: ScopedUnqualifiedProvidesType
+ ): ScopedUnqualifiedBindsType
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Binds
+ @MyQualifier
+ fun unscopedQualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ unscopedQualifiedProvidesType: UnscopedQualifiedProvidesType
+ ): UnscopedQualifiedBindsType
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Binds
+ fun unscopedUnqualifiedBindsType(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ unscopedUnqualifiedProvidesType: UnscopedUnqualifiedProvidesType
+ ): UnscopedUnqualifiedBindsType
+ }
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Provides
+ @MyQualifier
+ fun provideQualifiedDep(): Dep = Dep()
+
+ // Provide an unqualified Dep to ensure that if we accidentally drop the qualifier
+ // we'll get a runtime exception.
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Provides
+ fun provideDep(): Dep = TODO()
+
+ // Non-Dagger elements
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ private val nonDaggerField: MyTransitiveType = MyTransitiveType()
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyOtherAnnotation.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyOtherAnnotation.kt
new file mode 100644
index 0000000..8f5a8a5
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyOtherAnnotation.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import kotlin.reflect.KClass
+
+/** An annotation that is a direct dependency of the app. */
+annotation class MyOtherAnnotation(val value: KClass<*>)
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyQualifier.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyQualifier.kt
new file mode 100644
index 0000000..0ca36f7
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MyQualifier.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import javax.inject.Qualifier
+
+@Qualifier
+annotation class MyQualifier
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentBinding.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentBinding.kt
new file mode 100644
index 0000000..620940b
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentBinding.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+/** A simple binding that needs to be passed in when creating this component. */
+class MySubcomponentBinding
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentModule.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentModule.kt
new file mode 100644
index 0000000..98aa474
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentModule.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import dagger.Module
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/** A simple module that needs to be passed in when creating this component. */
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+@Module
+class MySubcomponentModule
+@MyTransitiveAnnotation
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+constructor(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ i: Int
+)
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentScope.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentScope.kt
new file mode 100644
index 0000000..5c8a168
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentScope.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import javax.inject.Scope
+
+/** A scope for [MySubcomponentWithBuilder] and [MySubcomponentWithFactory]. */
+@Scope
+annotation class MySubcomponentScope
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentWithBuilder.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentWithBuilder.kt
new file mode 100644
index 0000000..f7c5878
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentWithBuilder.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import dagger.BindsInstance
+import dagger.Subcomponent
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * During the compilation of `:app`, [MyTransitiveAnnotation] will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+@MySubcomponentScope
+@Subcomponent(modules = [MySubcomponentModule::class])
+abstract class MySubcomponentWithBuilder {
+ @MyQualifier // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun qualifiedMySubcomponentBinding(): MySubcomponentBinding
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun unqualifiedMySubcomponentBinding(): MySubcomponentBinding
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun injectFoo(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here)
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ foo: Foo
+ )
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Subcomponent.Builder
+ abstract class Builder {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun mySubcomponentModule(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ mySubcomponentModule: MySubcomponentModule
+ ): Builder
+
+ @BindsInstance
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun qualifiedMySubcomponentBinding(
+ @MyQualifier
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ subcomponentBinding: MySubcomponentBinding
+ ): Builder
+
+ @BindsInstance
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun unqualifiedMySubcomponentBinding(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ subcomponentBinding: MySubcomponentBinding
+ ): Builder
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun build(): MySubcomponentWithBuilder
+
+ // Non-dagger code
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ var nonDaggerField = ""
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ str: String
+ ) {}
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ var nonDaggerStaticField = ""
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ str: String
+ ) {}
+ }
+ }
+
+ // Non-dagger code
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerStaticField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentWithFactory.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentWithFactory.kt
new file mode 100644
index 0000000..1ce8028
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library1/src/main/kotlin/library1/MySubcomponentWithFactory.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library1
+
+import dagger.BindsInstance
+import dagger.Subcomponent
+import library2.MyTransitiveAnnotation
+import library2.MyTransitiveType
+
+/**
+ * A class used to test that Dagger won't fail when non-dagger related annotations cannot be
+ * resolved.
+ *
+ * During the compilation of `:app`, [MyTransitiveAnnotation] will no longer be on
+ * the classpath. In most cases, Dagger shouldn't care that the annotation isn't on the classpath
+ */
+// TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+@MyAnnotation(MyTransitiveType.VALUE)
+@MyOtherAnnotation(MyTransitiveType::class)
+@MySubcomponentScope
+@Subcomponent(modules = [MySubcomponentModule::class])
+abstract class MySubcomponentWithFactory {
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyQualifier
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun qualifiedMySubcomponentBinding(): MySubcomponentBinding
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun unqualifiedMySubcomponentBinding(): MySubcomponentBinding
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun injectFoo(
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here)
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ foo: Foo
+ )
+
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (We shouldn't need scope/qualifier here).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ @Subcomponent.Factory
+ abstract class Factory {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ abstract fun create(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ mySubcomponentModule: MySubcomponentModule,
+ @BindsInstance
+ @MyQualifier
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ qualifiedSubcomponentBinding: MySubcomponentBinding,
+ @BindsInstance
+ // TODO(b/219587431): Support @MyTransitiveAnnotation (Requires generating metadata).
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ unqualifiedSubcomponentBinding: MySubcomponentBinding
+ ): MySubcomponentWithFactory
+
+ // Non-dagger code
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerStaticField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+ }
+
+ // Non-dagger code
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+
+ companion object {
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ lateinit var nonDaggerStaticField: MyTransitiveType
+
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ fun nonDaggerStaticMethod(
+ @MyTransitiveAnnotation
+ @MyAnnotation(MyTransitiveType.VALUE)
+ @MyOtherAnnotation(MyTransitiveType::class)
+ nonDaggerParameter: MyTransitiveType
+ ): MyTransitiveType = nonDaggerParameter
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle
new file mode 100644
index 0000000..9b4c087
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/build.gradle
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id 'java-library'
+ id 'org.jetbrains.kotlin.jvm'
+ id 'org.jetbrains.kotlin.kapt'
+}
+
+kapt {
+ correctErrorTypes = true
+}
+
+java {
+ // Make sure the generated source is compatible with Java 7.
+ sourceCompatibility = JavaVersion.VERSION_1_7
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveAnnotation.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveAnnotation.kt
new file mode 100644
index 0000000..531624e
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveAnnotation.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library2
+
+/** A simple annotation that is a transitive dependency of the app. */
+annotation class MyTransitiveAnnotation
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveBaseAnnotation.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveBaseAnnotation.kt
new file mode 100644
index 0000000..2791ce2
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveBaseAnnotation.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library2
+
+/** A simple annotation that is a transitive dependency of the app. */
+annotation class MyTransitiveBaseAnnotation
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveType.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveType.kt
new file mode 100644
index 0000000..213fb09
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/library2/src/main/kotlin/library2/MyTransitiveType.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package library2
+
+/** A class that is a transitive dependency of the app. */
+class MyTransitiveType {
+ companion object {
+ const val VALUE = 3
+ }
+}
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/main/kotlin/app/MyComponent.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/main/kotlin/app/MyComponent.kt
new file mode 100644
index 0000000..47b1342
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/main/kotlin/app/MyComponent.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import dagger.Component
+import library1.AssistedFoo
+import library1.Foo
+import library1.MyBaseComponent
+import library1.MyComponentDependency
+import library1.MyComponentDependencyBinding
+import library1.MyComponentModule
+import library1.MySubcomponentWithBuilder
+import library1.MySubcomponentWithFactory
+import library1.MyQualifier
+import javax.inject.Singleton
+import library1.MyComponentModule.ScopedQualifiedBindsType
+import library1.MyComponentModule.ScopedUnqualifiedBindsType
+import library1.MyComponentModule.UnscopedQualifiedBindsType
+import library1.MyComponentModule.UnscopedUnqualifiedBindsType
+import library1.MyComponentModule.ScopedQualifiedProvidesType
+import library1.MyComponentModule.ScopedUnqualifiedProvidesType
+import library1.MyComponentModule.UnscopedQualifiedProvidesType
+import library1.MyComponentModule.UnscopedUnqualifiedProvidesType
+
+@Singleton
+@Component(dependencies = [MyComponentDependency::class], modules = [MyComponentModule::class])
+internal abstract class MyComponent : MyBaseComponent() {
+ abstract fun foo(): Foo
+ @MyQualifier
+ abstract fun scopedQualifiedBindsType(): ScopedQualifiedBindsType
+ abstract fun assistedFooFactory(): AssistedFoo.Factory
+ @MyQualifier
+ abstract fun unscopedQualifiedBindsType(): UnscopedQualifiedBindsType
+ abstract fun scopedUnqualifiedBindsType(): ScopedUnqualifiedBindsType
+ @MyQualifier
+ abstract fun scopedQualifiedProvidesType(): ScopedQualifiedProvidesType
+ abstract fun unscopedUnqualifiedBindsType(): UnscopedUnqualifiedBindsType
+ @MyQualifier
+ abstract fun unscopedQualifiedProvidesType(): UnscopedQualifiedProvidesType
+ abstract fun scopedUnqualifiedProvidesType(): ScopedUnqualifiedProvidesType
+ abstract fun unscopedUnqualifiedProvidesType(): UnscopedUnqualifiedProvidesType
+ abstract fun mySubcomponentWithFactory(): MySubcomponentWithFactory.Factory
+ abstract fun mySubcomponentWithBuilder(): MySubcomponentWithBuilder.Builder
+ @MyQualifier
+ abstract fun qualifiedMyComponentDependencyBinding(): MyComponentDependencyBinding
+ abstract fun unqualifiedMyComponentDependencyBinding(): MyComponentDependencyBinding
+
+
+ @Component.Factory
+ internal abstract class Factory : MyBaseComponent.Factory() {
+ abstract override fun create(
+ myComponentModule: MyComponentModule,
+ myComponentDependency: MyComponentDependency
+ ): MyComponent
+ }
+}
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MyComponentTest.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MyComponentTest.kt
new file mode 100644
index 0000000..ae57fd1
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MyComponentTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.junit.Before
+import com.google.common.truth.Truth.assertThat
+import library1.*
+import org.junit.Test
+
+@RunWith(JUnit4::class)
+class MyComponentTest {
+ private lateinit var component: MyComponent
+
+ @Before
+ fun setup() {
+ component = DaggerMyComponent.factory()
+ .create(MyComponentModule(Dep()), MyComponentDependency())
+ }
+
+ @Test
+ fun testFooIsScoped() {
+ assertThat(component.foo()).isEqualTo(component.foo())
+ }
+
+ @Test
+ fun testAssistedFoo() {
+ assertThat(component.assistedFooFactory().create(5)).isNotNull()
+ }
+
+ @Test
+ fun testScopedQualifiedBindsTypeIsScoped() {
+ assertThat(component.scopedQualifiedBindsType())
+ .isEqualTo(component.scopedQualifiedBindsType())
+ }
+
+ @Test
+ fun testScopedUnqualifiedBindsTypeIsScoped() {
+ assertThat(component.scopedUnqualifiedBindsType())
+ .isEqualTo(component.scopedUnqualifiedBindsType())
+ }
+
+ @Test
+ fun testUnscopedQualifiedBindsTypeIsNotScoped() {
+ assertThat(component.unscopedQualifiedBindsType())
+ .isNotEqualTo(component.unscopedQualifiedBindsType())
+ }
+
+ @Test
+ fun testUnscopedUnqualifiedBindsTypeIsNotScoped() {
+ assertThat(component.unscopedUnqualifiedBindsType())
+ .isNotEqualTo(component.unscopedUnqualifiedBindsType())
+ }
+
+ @Test
+ fun testScopedQualifiedProvidesTypeIsScoped() {
+ assertThat(component.scopedQualifiedProvidesType())
+ .isEqualTo(component.scopedQualifiedProvidesType())
+ }
+
+ @Test
+ fun testScopedUnqualifiedProvidesTypeIsScoped() {
+ assertThat(component.scopedUnqualifiedProvidesType())
+ .isEqualTo(component.scopedUnqualifiedProvidesType())
+ }
+
+ @Test
+ fun testUnscopedQualifiedProvidesTypeIsNotScoped() {
+ assertThat(component.unscopedQualifiedProvidesType())
+ .isNotEqualTo(component.unscopedQualifiedProvidesType())
+ }
+
+ @Test
+ fun testUnscopedUnqualifiedProvidesTypeIsNotScoped() {
+ assertThat(component.unscopedUnqualifiedProvidesType())
+ .isNotEqualTo(component.unscopedUnqualifiedProvidesType())
+ }
+
+ @Test
+ fun testMyComponentDependencyBinding() {
+ assertThat(component.qualifiedMyComponentDependencyBinding())
+ .isNotEqualTo(component.unqualifiedMyComponentDependencyBinding())
+ }
+}
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MySubcomponentWithBuilderTest.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MySubcomponentWithBuilderTest.kt
new file mode 100644
index 0000000..72dc692
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MySubcomponentWithBuilderTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import com.google.common.truth.Truth.assertThat
+import library1.Dep
+import library1.MyComponentDependency
+import library1.MyComponentModule
+import library1.MySubcomponentBinding
+import library1.MySubcomponentModule
+import library1.MySubcomponentWithBuilder
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class MySubcomponentWithBuilderTest {
+ private lateinit var subcomponentWithBuilder: MySubcomponentWithBuilder
+
+ @Before
+ fun setup() {
+ subcomponentWithBuilder = DaggerMyComponent.factory()
+ .create(MyComponentModule(Dep()), MyComponentDependency())
+ .mySubcomponentWithBuilder()
+ .mySubcomponentModule(MySubcomponentModule(3))
+ .qualifiedMySubcomponentBinding(MySubcomponentBinding())
+ .unqualifiedMySubcomponentBinding(MySubcomponentBinding())
+ .build()
+ }
+
+ // Test that the qualified and unqualified bindings are two separate objects
+ @Test
+ fun testMySubcomponentBinding() {
+ assertThat(subcomponentWithBuilder.qualifiedMySubcomponentBinding())
+ .isNotEqualTo(subcomponentWithBuilder.unqualifiedMySubcomponentBinding())
+ }
+}
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MySubcomponentWithFactoryTest.kt b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MySubcomponentWithFactoryTest.kt
new file mode 100644
index 0000000..724254e
--- /dev/null
+++ b/javatests/artifacts/dagger/transitive-annotation-kotlin-app/src/test/kotlin/app/MySubcomponentWithFactoryTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package app
+
+import com.google.common.truth.Truth.assertThat
+import library1.Dep
+import library1.MyComponentDependency
+import library1.MyComponentModule
+import library1.MySubcomponentBinding
+import library1.MySubcomponentModule
+import library1.MySubcomponentWithFactory
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class MySubcomponentWithFactoryTest {
+ private lateinit var subcomponentWithFactory: MySubcomponentWithFactory
+
+ @Before
+ fun setup() {
+ subcomponentWithFactory = DaggerMyComponent.factory()
+ .create(MyComponentModule(Dep()), MyComponentDependency())
+ .mySubcomponentWithFactory()
+ .create(
+ MySubcomponentModule(1),
+ MySubcomponentBinding(),
+ MySubcomponentBinding()
+ )
+ }
+
+ // Test that the qualified and unqualified bindings are two separate objects
+ @Test
+ fun testMySubcomponentBinding() {
+ assertThat(subcomponentWithFactory.qualifiedMySubcomponentBinding())
+ .isNotEqualTo(subcomponentWithFactory.unqualifiedMySubcomponentBinding())
+ }
+}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
index 14364e1..3c97d6f 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
@@ -2,6 +2,7 @@
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
+ id 'com.google.devtools.ksp'
}
android {
@@ -21,7 +22,7 @@
kotlinOptions {
jvmTarget = '11'
}
- flavorDimensions "tier"
+ flavorDimensions "tier", "processorConfig"
productFlavors {
free {
dimension "tier"
@@ -29,13 +30,24 @@
premium {
dimension "tier"
}
+ withKapt {
+ dimension "processorConfig"
+ }
+ withKsp {
+ dimension "processorConfig"
+ }
}
}
+kotlin {
+ jvmToolchain(11)
+}
+
dependencies {
implementation project(':deep-android-lib')
implementation project(':deep-kotlin-lib')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kaptWithKapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kspWithKsp 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
index 646e78d..0b860af 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
@@ -18,6 +18,7 @@
apply plugin: 'kotlin-android'
apply plugin: 'com.google.dagger.hilt.android'
apply plugin: 'kotlin-kapt'
+apply plugin: 'com.google.devtools.ksp'
android {
compileSdkVersion 32
@@ -37,7 +38,7 @@
shrinkResources true
}
}
- flavorDimensions "tier"
+ flavorDimensions "tier", "processorConfig"
productFlavors {
free {
dimension "tier"
@@ -46,14 +47,17 @@
dimension "tier"
matchingFallbacks = ["free"]
}
+ withKapt {
+ dimension "processorConfig"
+ }
+ withKsp {
+ dimension "processorConfig"
+ }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
- kotlinOptions {
- jvmTarget = '11'
- }
testOptions {
unitTests.includeAndroidResources = true
}
@@ -71,6 +75,10 @@
}
}
+kotlin {
+ jvmToolchain(11)
+}
+
hilt {
enableTransformForLocalTests = true
enableAggregatingTask = true
@@ -84,7 +92,8 @@
implementation 'androidx.activity:activity-ktx:1.5.0'
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kaptWithKapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kspWithKsp 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
testImplementation 'androidx.test.ext:junit:1.1.3'
testImplementation 'androidx.test:runner:1.4.0'
@@ -95,12 +104,14 @@
// TODO(bcorso): This multidex dep shouldn't be required -- it's a dep for the generated code.
testImplementation 'androidx.multidex:multidex:2.0.0'
testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptTest 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kaptTestWithKapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kspTestWithKsp 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
androidTestImplementation 'androidx.fragment:fragment-ktx:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'com.google.truth:truth:1.0.1'
androidTestImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptAndroidTest 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kaptAndroidTestWithKapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kspAndroidTestWithKsp 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
index 8d5cdcd..eee4806 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
@@ -16,7 +16,8 @@
buildscript {
ext {
- kotlin_version = '1.8.0'
+ kotlin_version = '1.8.20'
+ ksp_version = '1.0.11'
agp_version = System.getenv('AGP_VERSION') ?: "7.1.2"
}
repositories {
@@ -27,6 +28,7 @@
dependencies {
classpath "com.android.tools.build:gradle:$agp_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:$kotlin_version-$ksp_version"
classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
}
}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
index 01662ee..b248a0b 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
@@ -2,6 +2,7 @@
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
+ id 'com.google.devtools.ksp'
id 'com.google.dagger.hilt.android'
}
@@ -27,13 +28,27 @@
lintOptions {
checkReleaseBuilds = false
}
+ flavorDimensions "processorConfig"
+ productFlavors {
+ withKapt {
+ dimension "processorConfig"
+ }
+ withKsp {
+ dimension "processorConfig"
+ }
+ }
+}
+
+kotlin {
+ jvmToolchain(11)
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kaptWithKapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
+ kspWithKsp 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
testImplementation 'androidx.test.ext:junit:1.1.3'
testImplementation 'com.google.truth:truth:1.0.1'
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle
index 38fd64b..24e7246 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle
@@ -1,16 +1,14 @@
plugins {
- id 'java-library'
id 'kotlin'
- id 'kotlin-kapt'
+ id 'com.google.devtools.ksp'
}
-java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+kotlin {
+ jvmToolchain(11)
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.google.dagger:hilt-core:LOCAL-SNAPSHOT"
- kapt "com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT"
+ ksp "com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT"
}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/build.gradle
index a7c4398..ed01615 100644
--- a/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/build.gradle
+++ b/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/build.gradle
@@ -1,17 +1,15 @@
plugins {
- id 'java-library'
id 'kotlin'
- id 'kotlin-kapt'
+ id 'com.google.devtools.ksp'
}
-java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+kotlin {
+ jvmToolchain(11)
}
dependencies {
implementation project(':deep-kotlin-lib')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.google.dagger:hilt-core:LOCAL-SNAPSHOT"
- kapt "com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT"
+ ksp "com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT"
}
\ No newline at end of file
diff --git a/javatests/dagger/functional/kotlin/ObjectModuleClasses.kt b/javatests/dagger/functional/kotlin/ObjectModuleClasses.kt
index 68acafe..5b3d15c 100644
--- a/javatests/dagger/functional/kotlin/ObjectModuleClasses.kt
+++ b/javatests/dagger/functional/kotlin/ObjectModuleClasses.kt
@@ -64,7 +64,7 @@
}
@Module
-private object NonPublicObjectModule {
+internal object NonPublicObjectModule {
@Provides
fun provideInt() = 42
}
diff --git a/javatests/dagger/functional/kotlinsrc/basic/BasicComponent.kt b/javatests/dagger/functional/kotlinsrc/basic/BasicComponent.kt
index 2ada338..fd3ef09 100644
--- a/javatests/dagger/functional/kotlinsrc/basic/BasicComponent.kt
+++ b/javatests/dagger/functional/kotlinsrc/basic/BasicComponent.kt
@@ -74,12 +74,12 @@
fun lazyInjectedThingProviderFun(): Provider<Lazy<InjectedThing>>
fun injectedThingMembersInjectorFun(): MembersInjector<InjectedThing>
- @NullableModule.Nullable fun nullObjectFun(): Any
+ fun nullObjectFun(): Any?
fun nullObjectProviderFun(): Provider<Any>
fun lazyNullObjectFun(): Lazy<Any>
fun typeWithInheritedMembersInjectionFun(): TypeWithInheritedMembersInjection
fun typeWithInheritedMembersInjectionMembersInjectorFun():
- MembersInjector<TypeWithInheritedMembersInjection>
+ MembersInjector<TypeWithInheritedMembersInjection>
val byteVal: Byte
val charVal: Char
@@ -124,11 +124,10 @@
val lazyInjectedThingProviderVal: Provider<Lazy<InjectedThing>>
val injectedThingMembersInjectorVal: MembersInjector<InjectedThing>
- // TODO(b/261506732): Support nullable and qualifiers on properties without using @get:
- @get:NullableModule.Nullable val nullObjectVal: Any
+ val nullObjectVal: Any?
val nullObjectProviderVal: Provider<Any>
val lazyNullObjectVal: Lazy<Any>
val typeWithInheritedMembersInjectionVal: TypeWithInheritedMembersInjection
val typeWithInheritedMembersInjectionMembersInjectorVal:
- MembersInjector<TypeWithInheritedMembersInjection>
+ MembersInjector<TypeWithInheritedMembersInjection>
}
diff --git a/javatests/dagger/functional/kotlinsrc/basic/NullableModule.kt b/javatests/dagger/functional/kotlinsrc/basic/NullableModule.kt
index f2381af..e8f8963 100644
--- a/javatests/dagger/functional/kotlinsrc/basic/NullableModule.kt
+++ b/javatests/dagger/functional/kotlinsrc/basic/NullableModule.kt
@@ -21,11 +21,5 @@
@Module
internal object NullableModule {
- @Provides @Nullable fun nullObject(): Any? = null
-
- /**
- * A `Nullable` that isn't [javax.annotation.Nullable], to ensure that Dagger can be built without
- * depending on JSR-305.
- */
- internal annotation class Nullable
+ @Provides fun nullObject(): Any? = null
}
diff --git a/javatests/dagger/functional/kotlinsrc/builderbinds/TestComponent.kt b/javatests/dagger/functional/kotlinsrc/builderbinds/TestComponent.kt
index 81769d5..100d823 100644
--- a/javatests/dagger/functional/kotlinsrc/builderbinds/TestComponent.kt
+++ b/javatests/dagger/functional/kotlinsrc/builderbinds/TestComponent.kt
@@ -27,7 +27,7 @@
@Named("input") fun input(): String
- @Nullable @Named("nullable input") fun nullableInput(): String
+ @Named("nullable input") fun nullableInput(): String?
fun listOfString(): List<String>
@@ -41,8 +41,7 @@
@BindsInstance fun input(@Named("input") input: String): Builder
- @BindsInstance
- fun nullableInput(@Nullable @Named("nullable input") nullableInput: String?): Builder
+ @BindsInstance fun nullableInput(@Named("nullable input") nullableInput: String?): Builder
@BindsInstance fun listOfString(listOfString: List<String>): Builder
diff --git a/javatests/dagger/functional/kotlinsrc/factory/FactoryBindsInstanceTest.kt b/javatests/dagger/functional/kotlinsrc/factory/FactoryBindsInstanceTest.kt
index 9e82292..cfbfeac 100644
--- a/javatests/dagger/functional/kotlinsrc/factory/FactoryBindsInstanceTest.kt
+++ b/javatests/dagger/functional/kotlinsrc/factory/FactoryBindsInstanceTest.kt
@@ -42,17 +42,13 @@
assertThat(component.string()).isEqualTo("baz")
}
- @Target(AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
- @Retention(AnnotationRetention.BINARY)
- internal annotation class Nullable
-
@Component
internal interface NullableBindsInstanceComponent {
- @Nullable fun string(): String?
+ fun string(): String?
@Component.Factory
interface Factory {
- fun create(@BindsInstance @Nullable string: String?): NullableBindsInstanceComponent
+ fun create(@BindsInstance string: String?): NullableBindsInstanceComponent
}
}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/BUILD b/javatests/dagger/functional/kotlinsrc/membersinject/BUILD
new file mode 100644
index 0000000..8124e3e
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/BUILD
@@ -0,0 +1,48 @@
+# Copyright (C) 2022 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:
+# Functional tests for Dagger members inject usages.
+
+load(
+ "//:build_defs.bzl",
+ "DOCLINT_HTML_AND_SYNTAX",
+ "DOCLINT_REFERENCES",
+)
+load("//:test_defs.bzl", "GenKtTests")
+
+package(default_visibility = ["//:src"])
+
+GenKtTests(
+ name = "membersinject",
+ srcs = glob(["*.kt"]),
+ gen_library_deps = [
+ "//javatests/dagger/functional/kotlinsrc/membersinject/subpackage",
+ "//javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a:grandchild",
+ "//javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a:parent",
+ "//javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b:child",
+ ],
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ deps = [
+ "//:dagger_with_compiler",
+ "//third_party/java/auto:factory",
+ "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
+ "//third_party/java/guava/util/concurrent",
+ "//third_party/java/jsr305_annotations",
+ "//third_party/java/jsr330_inject",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+)
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfArrayOfParentOfStringArray.kt b/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfArrayOfParentOfStringArray.kt
new file mode 100644
index 0000000..34bde49
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfArrayOfParentOfStringArray.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+class ChildOfArrayOfParentOfStringArray :
+ MembersInjectGenericParent<Array<MembersInjectGenericParent<Array<String>>>>()
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfPrimitiveIntArray.kt b/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfPrimitiveIntArray.kt
new file mode 100644
index 0000000..174d0ce
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfPrimitiveIntArray.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+class ChildOfPrimitiveIntArray : MembersInjectGenericParent<IntArray>()
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfStringArray.kt b/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfStringArray.kt
new file mode 100644
index 0000000..0f6ab4b
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/ChildOfStringArray.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+class ChildOfStringArray : MembersInjectGenericParent<Array<String>>()
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectComponent.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectComponent.kt
new file mode 100644
index 0000000..08a3fbf
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectComponent.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.Component
+
+@Component(modules = [MembersInjectModule::class])
+interface MembersInjectComponent {
+ fun inject(subfoo: ChildOfStringArray)
+ fun inject(subfoo: ChildOfArrayOfParentOfStringArray)
+ fun inject(subfoo: ChildOfPrimitiveIntArray)
+ fun inject(rawFrameworkTypes: RawFrameworkTypes)
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectGenericParent.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectGenericParent.kt
new file mode 100644
index 0000000..7110f61
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectGenericParent.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import javax.inject.Inject
+
+open class MembersInjectGenericParent<T : Any> {
+ @Inject lateinit var t: T
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectModule.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectModule.kt
new file mode 100644
index 0000000..db3a007
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectModule.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.Module
+import dagger.Provides
+
+@Module
+internal class MembersInjectModule {
+ @Provides fun provideStringArray(): Array<String> = arrayOf()
+
+ @Provides fun provideIntArray(): IntArray = intArrayOf()
+
+ @Provides
+ fun provideFooArrayOfStringArray(): Array<MembersInjectGenericParent<Array<String>>> = arrayOf()
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectTest.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectTest.kt
new file mode 100644
index 0000000..2fc4425
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectTest.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
+import dagger.MembersInjector
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.AGrandchild
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.AParent
+import dagger.functional.kotlinsrc.membersinject.subpackage.b.BChild
+import javax.inject.Inject
+import javax.inject.Provider
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class MembersInjectTest {
+ @Test
+ fun testMembersInject_arrays() {
+ val component = DaggerMembersInjectComponent.builder().build()
+ val childOfStringArray = ChildOfStringArray()
+ component.inject(childOfStringArray)
+ }
+
+ @Test
+ fun testMembersInject_nestedArrays() {
+ val component = DaggerMembersInjectComponent.builder().build()
+ val childOfArrayOfParentOfStringArray = ChildOfArrayOfParentOfStringArray()
+ component.inject(childOfArrayOfParentOfStringArray)
+ }
+
+ @Test
+ fun testMembersInject_primitives() {
+ val component = DaggerMembersInjectComponent.builder().build()
+ val childOfPrimitiveIntArray = ChildOfPrimitiveIntArray()
+ component.inject(childOfPrimitiveIntArray)
+ }
+
+ @Test
+ fun testMembersInject_overrides() {
+ val component = DaggerMembersInjectionVisibilityComponent.create()
+ val aParent = AParent()
+ component.inject(aParent)
+ assertThat(aParent.aParentField()).isNotNull()
+ assertThat(aParent.aParentMethod()).isNotNull()
+ val aChild = BChild()
+ component.inject(aChild)
+ assertThat(aChild.aParentField()).isNotNull()
+ assertThat(aChild.aParentMethod()).isNull()
+ assertThat(aChild.aChildField()).isNotNull()
+ assertThat(aChild.aChildMethod()).isNotNull()
+ val aGrandchild = AGrandchild()
+ component.inject(aGrandchild)
+ assertThat(aGrandchild.aParentField()).isNotNull()
+ assertThat(aGrandchild.aParentMethod()).isNotNull()
+ assertThat(aGrandchild.aChildField()).isNotNull()
+ assertThat(aGrandchild.aChildMethod()).isNull()
+ assertThat(aGrandchild.aGrandchildField()).isNotNull()
+ assertThat(aGrandchild.aGrandchildMethod()).isNotNull()
+ }
+
+ @Test
+ fun testNonRequestedMembersInjector() {
+ val child = NonRequestedChild()
+ val provider = Provider { "field!" }
+ val injector = NonRequestedChild_MembersInjector(provider)
+ injector.injectMembers(child)
+ assertThat(child.t).isEqualTo("field!")
+ }
+
+ class A : B() // No injected members
+ open class B : C() // No injected members
+ open class C {
+ @Inject lateinit var value: String
+ }
+
+ @Component
+ internal interface NonLocalMembersComponent {
+ fun aMembersInjector(): MembersInjector<A>
+
+ @Component.Factory
+ interface Factory {
+ fun create(@BindsInstance value: String): NonLocalMembersComponent
+ }
+ }
+
+ @Test
+ fun testNonLocalMembersInjection() {
+ val membersInjector =
+ DaggerMembersInjectTest_NonLocalMembersComponent.factory().create("test").aMembersInjector()
+ val testA = A()
+ membersInjector.injectMembers(testA)
+ assertThat(testA.value).isEqualTo("test")
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionOrdering.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionOrdering.kt
new file mode 100644
index 0000000..203935d
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionOrdering.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+
+/**
+ * This exhibits a regression case, that albeit weird, is valid according to the JSR 330 spec. JSR
+ * 330 specifies a rough ordering by which members should be injected, and it is possible to rely on
+ * such ordering. When members injecting [Subtype], field injection is guaranteed to be performed on
+ * [Base] first. The binding for `@FirstToString` in [ ][OrderingModule.provideToString] relies on
+ * this ordering, and thus uses the value in [ ][Base.first] to satisfy the binding.
+ */
+class MembersInjectionOrdering {
+ open class Base {
+ @Inject lateinit var first: First
+ }
+
+ class Subtype : Base() {
+ @Inject lateinit var firstToString: String
+ }
+
+ @Module
+ class OrderingModule(private val subtype: Subtype) {
+ @Provides fun provideToString(): String = subtype.first.toString()
+ }
+
+ @Component(modules = [OrderingModule::class])
+ interface TestComponent {
+ fun inject(subtype: Subtype)
+ }
+
+ class First @Inject constructor()
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionOrderingTest.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionOrderingTest.kt
new file mode 100644
index 0000000..58644b5
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionOrderingTest.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.functional.kotlinsrc.membersinject.MembersInjectionOrdering.OrderingModule
+import dagger.functional.kotlinsrc.membersinject.MembersInjectionOrdering.Subtype
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class MembersInjectionOrderingTest {
+ @Test
+ fun indirection() {
+ val toInject = Subtype()
+ DaggerMembersInjectionOrdering_TestComponent.builder()
+ .orderingModule(OrderingModule(toInject))
+ .build()
+ .inject(toInject)
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionVisibilityComponent.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionVisibilityComponent.kt
new file mode 100644
index 0000000..57210c7
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersInjectionVisibilityComponent.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.Component
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.AGrandchild
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.AParent
+import dagger.functional.kotlinsrc.membersinject.subpackage.b.BChild
+
+/** A component that tests members injection across packages and subclasses. */
+@Component
+interface MembersInjectionVisibilityComponent {
+ fun inject(aParent: AParent)
+ fun inject(aChild: BChild)
+ fun inject(aGrandchild: AGrandchild)
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithInstanceNameTest.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithInstanceNameTest.kt
new file mode 100644
index 0000000..4c2085b
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithInstanceNameTest.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import com.google.common.truth.Truth.assertThat
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class MembersWithInstanceNameTest {
+ @Suppress("BadInject") // This is intentional for testing purposes.
+ internal class Foo @Inject constructor() {
+ // Checks that member injection fields can use "instance" as a name (b/175818837).
+ @Inject lateinit var instance: String
+ }
+
+ @Module
+ internal interface TestModule {
+ companion object {
+ @Provides fun provideString(): String = "test"
+ }
+ }
+
+ @Component(modules = [TestModule::class])
+ internal interface TestComponent {
+ fun foo(): Foo
+ }
+
+ @Test
+ fun testMemberWithInstanceName() {
+ val component = DaggerMembersWithInstanceNameTest_TestComponent.create()
+ val foo = component.foo()
+ assertThat(foo).isNotNull()
+ assertThat(foo.instance).isEqualTo("test")
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithSameNameChild.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithSameNameChild.kt
new file mode 100644
index 0000000..680acc6
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithSameNameChild.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.functional.kotlinsrc.membersinject.subpackage.MembersWithSameNameParent
+import javax.inject.Inject
+
+// https://github.com/google/dagger/issues/755
+class MembersWithSameNameChild : MembersWithSameNameParent() {
+ @Inject internal lateinit var sameName: String
+ internal var sameNameStringWasInvoked = false
+ internal var sameNameObjectWasInvoked = false
+
+ @Inject
+ internal fun sameName(@Suppress("UNUSED_PARAMETER") sameName: String) {
+ sameNameStringWasInvoked = true
+ }
+
+ @Inject
+ internal fun sameName(@Suppress("UNUSED_PARAMETER") sameName: Any) {
+ sameNameObjectWasInvoked = true
+ }
+
+ fun childSameName(): String {
+ return sameName
+ }
+
+ fun childSameNameStringWasInvoked(): Boolean {
+ return sameNameStringWasInvoked
+ }
+
+ fun childSameNameObjectWasInvoked(): Boolean {
+ return sameNameObjectWasInvoked
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithSameNameTest.kt b/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithSameNameTest.kt
new file mode 100644
index 0000000..4ea92b1
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/MembersWithSameNameTest.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import com.google.common.truth.Truth.assertThat
+import dagger.Binds
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+import dagger.functional.kotlinsrc.membersinject.subpackage.MembersWithSameNameParent
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+// https://github.com/google/dagger/issues/755
+@RunWith(JUnit4::class)
+class MembersWithSameNameTest {
+ @Test
+ fun parentInjectsMaskedMembers() {
+ val parent = MembersWithSameNameParent()
+ val component = DaggerMembersWithSameNameTest_TestComponent.create()
+ component.injectParent(parent)
+ assertThat(parent.parentSameName()).isNotNull()
+ assertThat(parent.parentSameNameStringWasInvoked()).isTrue()
+ assertThat(parent.parentSameNameObjectWasInvoked()).isTrue()
+ }
+
+ @Test
+ fun childInjectsMaskedMembers() {
+ val child = MembersWithSameNameChild()
+ val component = DaggerMembersWithSameNameTest_TestComponent.create()
+ component.injectChild(child)
+ assertThat(child.parentSameName()).isNotNull()
+ assertThat(child.parentSameNameStringWasInvoked()).isTrue()
+ assertThat(child.parentSameNameObjectWasInvoked()).isTrue()
+ assertThat(child.childSameName()).isNotNull()
+ assertThat(child.childSameNameStringWasInvoked()).isTrue()
+ assertThat(child.childSameNameObjectWasInvoked()).isTrue()
+ }
+
+ @Module
+ internal abstract class TestModule {
+ @Binds abstract fun bindObject(string: String): Any
+
+ companion object {
+ @Provides fun provideString(): String = ""
+ }
+ }
+
+ @Component(modules = [TestModule::class])
+ internal interface TestComponent {
+ fun injectParent(parent: MembersWithSameNameParent)
+ fun injectChild(child: MembersWithSameNameChild)
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/NonRequestedChild.kt b/javatests/dagger/functional/kotlinsrc/membersinject/NonRequestedChild.kt
new file mode 100644
index 0000000..f8a8644
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/NonRequestedChild.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import javax.inject.Inject
+
+/**
+ * A class that should not be requested by any component, to ensure that we still generate a members
+ * injector for it.
+ */
+class NonRequestedChild @Inject constructor() : MembersInjectGenericParent<String>()
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/RawFrameworkTypes.kt b/javatests/dagger/functional/kotlinsrc/membersinject/RawFrameworkTypes.kt
new file mode 100644
index 0000000..32a7bcd
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/RawFrameworkTypes.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject
+
+import dagger.Lazy
+import dagger.MembersInjector
+import javax.inject.Provider
+
+// https://github.com/google/dagger/issues/419
+// Note: This is converted from its associate java test in dagger/function/membersinject, but given
+// that there isn't actually raw types in kotlin I'm not sure how useful it is to keep it. For the
+// time being, I've decided to leave this as it tests the next closest thing, which is star types.
+class RawFrameworkTypes {
+ fun nonInjectMethodWithARawProvider(@Suppress("UNUSED_PARAMETER") rawProvider: Provider<*>) {}
+ fun nonInjectMethodWithARawLazy(@Suppress("UNUSED_PARAMETER") rawLazy: Lazy<*>) {}
+ fun nonInjectMethodWithARawMembersInjector(
+ @Suppress("UNUSED_PARAMETER") rawMembersInjector: MembersInjector<*>
+ ) {}
+}
diff --git a/javatests/dagger/functional/kotlinsrc/variance/BUILD b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/BUILD
similarity index 76%
rename from javatests/dagger/functional/kotlinsrc/variance/BUILD
rename to javatests/dagger/functional/kotlinsrc/membersinject/subpackage/BUILD
index 0d4b884..5fc9da9 100644
--- a/javatests/dagger/functional/kotlinsrc/variance/BUILD
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 The Dagger Authors.
+# Copyright (C) 2022 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.
@@ -13,24 +13,22 @@
# limitations under the License.
# Description:
-# Functional tests for Dagger with static @Provides usages.
+# Functional tests for Dagger members inject usages.
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
)
-load("//:test_defs.bzl", "GenKtTests")
+load("//:test_defs.bzl", "GenKtLibrary")
package(default_visibility = ["//:src"])
-GenKtTests(
- name = "variance",
+GenKtLibrary(
+ name = "subpackage",
srcs = glob(["*.kt"]),
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//:dagger_with_compiler",
- "//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/MembersWithSameNameParent.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/MembersWithSameNameParent.kt
new file mode 100644
index 0000000..a5e56f3
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/MembersWithSameNameParent.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject.subpackage
+
+import javax.inject.Inject
+
+// https://github.com/google/dagger/issues/755
+open class MembersWithSameNameParent {
+ // Note: This field is purposely non-public so that MembersWithSameNameChild#sameName hides
+ // this field rather than overrides it.
+ @Inject internal lateinit var sameName: String
+ internal var sameNameStringWasInvoked = false
+ internal var sameNameObjectWasInvoked = false
+
+ // Note: This method is purposely non-public so that MembersWithSameNameChild#sameName(String)
+ // hides this method rather than overrides it.
+ @Inject
+ internal fun sameName(@Suppress("UNUSED_PARAMETER") sameName: String) {
+ sameNameStringWasInvoked = true
+ }
+
+ // Note: This method is purposely non-public so that MembersWithSameNameChild#sameName(Object)
+ // hides this method rather than overrides it.
+ @Inject
+ internal fun sameName(@Suppress("UNUSED_PARAMETER") sameName: Any) {
+ sameNameObjectWasInvoked = true
+ }
+
+ fun parentSameName(): String {
+ return sameName
+ }
+
+ fun parentSameNameStringWasInvoked(): Boolean {
+ return sameNameStringWasInvoked
+ }
+
+ fun parentSameNameObjectWasInvoked(): Boolean {
+ return sameNameObjectWasInvoked
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AGrandchild.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AGrandchild.kt
new file mode 100644
index 0000000..044d34c
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AGrandchild.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject.subpackage.a
+
+import dagger.functional.kotlinsrc.membersinject.subpackage.b.BChild
+import javax.inject.Inject
+
+class AGrandchild : BChild() {
+ @Inject internal lateinit var aGrandchildField: APublicObject
+ private lateinit var aGrandchildMethod: APublicObject
+
+ @Inject
+ fun aGrandchildMethod(aGrandchildMethod: APublicObject) {
+ this.aGrandchildMethod = aGrandchildMethod
+ }
+
+ @Inject
+ protected override fun aParentMethod(aParentMethod: APublicObject) {
+ super.aParentMethod(aParentMethod)
+ }
+
+ protected override fun aChildMethod(aChildMethod: APublicObject) {
+ super.aChildMethod(aChildMethod)
+ }
+
+ fun aGrandchildField(): APublicObject = aGrandchildField
+
+ fun aGrandchildMethod(): APublicObject = aGrandchildMethod
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AInternalObject.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AInternalObject.kt
new file mode 100644
index 0000000..366c60c
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AInternalObject.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.kotlinsrc.membersinject.subpackage.a
+
+import javax.inject.Inject
+
+internal class AInternalObject @Inject constructor() : APublicObject()
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AParent.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AParent.kt
new file mode 100644
index 0000000..d11137d
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/AParent.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject.subpackage.a
+
+import javax.inject.Inject
+
+open class AParent {
+ @Inject internal lateinit var aParentField: AInternalObject
+ private var aParentMethod: APublicObject? = null
+
+ @Inject
+ protected open fun aParentMethod(aParentMethod: APublicObject) {
+ this.aParentMethod = aParentMethod
+ }
+
+ fun aParentField(): APublicObject {
+ return aParentField
+ }
+
+ fun aParentMethod(): APublicObject? {
+ return aParentMethod
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/APublicObject.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/APublicObject.kt
new file mode 100644
index 0000000..87b06b4
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/APublicObject.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject.subpackage.a
+
+import javax.inject.Inject
+
+open class APublicObject @Inject constructor()
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/BUILD b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/BUILD
new file mode 100644
index 0000000..cd2b55b
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a/BUILD
@@ -0,0 +1,51 @@
+# Copyright (C) 2022 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:
+# Functional tests for Dagger members inject usages.
+
+load(
+ "//:build_defs.bzl",
+ "DOCLINT_HTML_AND_SYNTAX",
+ "DOCLINT_REFERENCES",
+)
+load("//:test_defs.bzl", "GenKtLibrary")
+
+package(default_visibility = ["//:src"])
+
+GenKtLibrary(
+ name = "grandchild",
+ srcs = ["AGrandchild.kt"],
+ gen_library_deps = [
+ ":parent",
+ "//javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b:child",
+ ],
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ deps = [
+ "//:dagger_with_compiler",
+ ],
+)
+
+GenKtLibrary(
+ name = "parent",
+ srcs = [
+ "AInternalObject.kt",
+ "AParent.kt",
+ "APublicObject.kt",
+ ],
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ deps = [
+ "//:dagger_with_compiler",
+ ],
+)
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BChild.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BChild.kt
new file mode 100644
index 0000000..b16705e
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BChild.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject.subpackage.b
+
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.AParent
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.APublicObject
+import javax.inject.Inject
+
+open class BChild : AParent() {
+ @Inject internal lateinit var aChildField: BInternalObject
+ private var aChildMethod: APublicObject? = null
+
+ @Inject
+ protected open fun aChildMethod(aChildMethod: APublicObject) {
+ this.aChildMethod = aChildMethod
+ }
+
+ protected override fun aParentMethod(aParentMethod: APublicObject) {
+ super.aParentMethod(aParentMethod)
+ }
+
+ fun aChildField(): APublicObject {
+ return aChildField
+ }
+
+ fun aChildMethod(): APublicObject? {
+ return aChildMethod
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BInternalObject.kt b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BInternalObject.kt
new file mode 100644
index 0000000..cc96eec
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BInternalObject.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 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.functional.kotlinsrc.membersinject.subpackage.b
+
+import dagger.functional.kotlinsrc.membersinject.subpackage.a.APublicObject
+import javax.inject.Inject
+
+internal class BInternalObject @Inject constructor() : APublicObject()
diff --git a/javatests/dagger/functional/kotlinsrc/variance/BUILD b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BUILD
similarity index 69%
copy from javatests/dagger/functional/kotlinsrc/variance/BUILD
copy to javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BUILD
index 0d4b884..4afa314 100644
--- a/javatests/dagger/functional/kotlinsrc/variance/BUILD
+++ b/javatests/dagger/functional/kotlinsrc/membersinject/subpackage/b/BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 The Dagger Authors.
+# Copyright (C) 2022 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.
@@ -13,24 +13,28 @@
# limitations under the License.
# Description:
-# Functional tests for Dagger with static @Provides usages.
+# Functional tests for Dagger members inject usages.
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
)
-load("//:test_defs.bzl", "GenKtTests")
+load("//:test_defs.bzl", "GenKtLibrary")
package(default_visibility = ["//:src"])
-GenKtTests(
- name = "variance",
- srcs = glob(["*.kt"]),
+GenKtLibrary(
+ name = "child",
+ srcs = [
+ "BChild.kt",
+ "BInternalObject.kt",
+ ],
+ gen_library_deps = [
+ "//javatests/dagger/functional/kotlinsrc/membersinject/subpackage/a:parent",
+ ],
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//:dagger_with_compiler",
- "//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/functional/kotlinsrc/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.kt b/javatests/dagger/functional/kotlinsrc/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.kt
index 45aa1ef..b33b730 100644
--- a/javatests/dagger/functional/kotlinsrc/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.kt
+++ b/javatests/dagger/functional/kotlinsrc/multipackage/moduleconstructor/ModuleWithInaccessibleConstructor.kt
@@ -27,4 +27,9 @@
private val i: Int = Random.nextInt()
@Provides fun i(): Int = i
+
+ // This is a regression test for b/283164293
+ private companion object {
+ fun someMethod(): String = "someString"
+ }
}
diff --git a/javatests/dagger/functional/kotlinsrc/nullables/BUILD b/javatests/dagger/functional/kotlinsrc/nullables/BUILD
index 062f46b..e9db7a7 100644
--- a/javatests/dagger/functional/kotlinsrc/nullables/BUILD
+++ b/javatests/dagger/functional/kotlinsrc/nullables/BUILD
@@ -34,3 +34,14 @@
"//third_party/java/truth",
],
)
+
+GenKtTests(
+ name = "NullabilityInteroptTest",
+ srcs = ["NullabilityInteroptTest.kt"],
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ deps = [
+ "//:dagger_with_compiler",
+ "//third_party/java/junit",
+ "//third_party/java/truth",
+ ],
+)
diff --git a/javatests/dagger/functional/kotlinsrc/nullables/NullabilityInteroptTest.kt b/javatests/dagger/functional/kotlinsrc/nullables/NullabilityInteroptTest.kt
new file mode 100644
index 0000000..27dd43f
--- /dev/null
+++ b/javatests/dagger/functional/kotlinsrc/nullables/NullabilityInteroptTest.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.functional.kotlinsrc.nullables
+
+import com.google.common.truth.Truth.assertThat
+import dagger.Component
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import javax.inject.Qualifier
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/**
+ * A test that ensures nullable bindings created using an {@code @Nullable} annotation are
+ * interoperable with nullable bindings created using {@code T?} types in kotlin source.
+ */
+@RunWith(JUnit4::class)
+class NullabilityInteroptTest {
+ annotation class Nullable
+
+ @Qualifier annotation class ProvidedWithNullable
+
+ @Qualifier annotation class ProvidedWithNullType
+
+ @Component(modules = [TestModule::class])
+ interface TestComponent {
+ fun providesUsage(): ProvidesUsage
+
+ fun injectUsage(): InjectUsage
+
+ @ProvidedWithNullable @Nullable fun nullableWithNullable(): String
+
+ @ProvidedWithNullable fun nullableWithNullType(): String?
+
+ @ProvidedWithNullType @Nullable fun nullTypeWithNullable(): String
+
+ @ProvidedWithNullType fun nullTypeWithNullType(): String?
+ }
+
+ @Module
+ object TestModule {
+ @Provides
+ @ProvidedWithNullable
+ @Nullable
+ fun providedWithNullable(): String = PROVIDED_WITH_NULLABLE
+
+ @Provides @ProvidedWithNullType fun providedWithNullType(): String? = PROVIDED_WITH_NULL_TYPE
+
+ @Provides
+ fun providesUsage(
+ @ProvidedWithNullable nullableWithNullType: String?,
+ @ProvidedWithNullable @Nullable nullableWithNullable: String,
+ @ProvidedWithNullType nullTypeWithNullType: String?,
+ @ProvidedWithNullType @Nullable nullTypeWithNullable: String,
+ ): ProvidesUsage {
+ return ProvidesUsage(
+ nullableWithNullType,
+ nullableWithNullable,
+ nullTypeWithNullType,
+ nullTypeWithNullable,
+ )
+ }
+ }
+
+ class ProvidesUsage
+ constructor(
+ val nullableWithNullType: String?,
+ val nullableWithNullable: String,
+ val nullTypeWithNullType: String?,
+ val nullTypeWithNullable: String,
+ )
+
+ class InjectUsage
+ @Inject
+ constructor(
+ @ProvidedWithNullable val nullableWithNullType: String?,
+ @ProvidedWithNullable @Nullable val nullableWithNullable: String,
+ @ProvidedWithNullType val nullTypeWithNullType: String?,
+ @ProvidedWithNullType @Nullable val nullTypeWithNullable: String,
+ )
+
+ @Test
+ fun testEntryPoints() {
+ val component = DaggerNullabilityInteroptTest_TestComponent.create()
+ assertThat(component.nullableWithNullable()).isEqualTo(PROVIDED_WITH_NULLABLE)
+ assertThat(component.nullableWithNullType()).isEqualTo(PROVIDED_WITH_NULLABLE)
+ assertThat(component.nullTypeWithNullable()).isEqualTo(PROVIDED_WITH_NULL_TYPE)
+ assertThat(component.nullTypeWithNullType()).isEqualTo(PROVIDED_WITH_NULL_TYPE)
+ }
+
+ @Test
+ fun testInjectUsage() {
+ val injectUsage = DaggerNullabilityInteroptTest_TestComponent.create().injectUsage()
+ assertThat(injectUsage.nullableWithNullable).isEqualTo(PROVIDED_WITH_NULLABLE)
+ assertThat(injectUsage.nullableWithNullType).isEqualTo(PROVIDED_WITH_NULLABLE)
+ assertThat(injectUsage.nullTypeWithNullable).isEqualTo(PROVIDED_WITH_NULL_TYPE)
+ assertThat(injectUsage.nullTypeWithNullType).isEqualTo(PROVIDED_WITH_NULL_TYPE)
+ }
+
+ @Test
+ fun testProvidesUsage() {
+ val providesUsage = DaggerNullabilityInteroptTest_TestComponent.create().providesUsage()
+ assertThat(providesUsage.nullableWithNullable).isEqualTo(PROVIDED_WITH_NULLABLE)
+ assertThat(providesUsage.nullableWithNullType).isEqualTo(PROVIDED_WITH_NULLABLE)
+ assertThat(providesUsage.nullTypeWithNullable).isEqualTo(PROVIDED_WITH_NULL_TYPE)
+ assertThat(providesUsage.nullTypeWithNullType).isEqualTo(PROVIDED_WITH_NULL_TYPE)
+ }
+
+ companion object {
+ const val PROVIDED_WITH_NULLABLE: String = "ProvidedWithNullable"
+ const val PROVIDED_WITH_NULL_TYPE: String = "ProvidedWithNullType"
+ }
+}
diff --git a/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt b/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt
index 998b337..c790a66 100644
--- a/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt
+++ b/javatests/dagger/functional/kotlinsrc/nullables/NullabilityTest.kt
@@ -31,11 +31,9 @@
@RunWith(JUnit4::class)
class NullabilityTest {
- internal annotation class Nullable
-
@Component(dependencies = [NullComponent::class])
internal interface NullComponentWithDependency {
- @Nullable fun string(): String?
+ fun string(): String?
fun number(): Number
fun stringProvider(): Provider<String>
fun numberProvider(): Provider<Number>
@@ -43,8 +41,8 @@
@Component(modules = [NullModule::class])
internal interface NullComponent {
- @Nullable fun string(): String?
- @Nullable fun integer(): Int?
+ fun string(): String?
+ fun integer(): Int?
fun nullFoo(): NullFoo
fun number(): Number
fun stringProvider(): Provider<String>
@@ -56,11 +54,10 @@
var numberValue: Number? = null
var integerCallCount = 0
- @Nullable @Provides fun provideNullableString(): String? = null
+ @Provides fun provideNullableString(): String? = null
@Provides fun provideNumber(): Number = numberValue!!
- @Nullable
@Provides
@Reusable
fun provideNullReusableInteger(): Int? {
@@ -73,7 +70,7 @@
internal class NullFoo
@Inject
constructor(
- @param:Nullable val string: String?,
+ val string: String?,
val number: Number,
val stringProvider: Provider<String>,
val numberProvider: Provider<Number>
@@ -85,7 +82,7 @@
@Inject
fun inject(
- @Nullable string: String?,
+ string: String?,
number: Number,
stringProvider: Provider<String>,
numberProvider: Provider<Number>
@@ -96,7 +93,7 @@
methodInjectedNumberProvider = numberProvider
}
- @JvmField @Nullable @Inject var fieldInjectedString: String? = null
+ @JvmField @Inject var fieldInjectedString: String? = null
@Inject lateinit var fieldInjectedNumber: Number
@Inject lateinit var fieldInjectedStringProvider: Provider<String>
@Inject lateinit var fieldInjectedNumberProvider: Provider<Number>
diff --git a/javatests/dagger/functional/kotlinsrc/variance/DeclarationVarianceTest.kt b/javatests/dagger/functional/kotlinsrc/variance/DeclarationVarianceTest.kt
deleted file mode 100644
index 61615af..0000000
--- a/javatests/dagger/functional/kotlinsrc/variance/DeclarationVarianceTest.kt
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2023 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.functional.kotlinsrc.variance
-
-import com.google.common.truth.Truth.assertThat
-import dagger.Component
-import dagger.Module
-import dagger.Provides
-import javax.inject.Inject
-import javax.inject.Singleton
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-// This class tests some usages of the declaration-site variance defined in the declaration of the
-// List class, i.e. List<out T>. In these tests, I'm only using @JvmWildcard and
-// @JvmSuppressWildcards when it's required for correctness, which depends on:
-//
-// 1) Where the type is used
-// 2) If the type argument is an open or final class
-//
-// This isn't an exhaustive list, but covers some of the common cases and we can add more as we find
-// them.
-@RunWith(JUnit4::class)
-class DeclarationVarianceTest {
-
- @Singleton
- @Component(modules = [BarModule::class])
- interface BarComponent {
- fun listBar(): List<Bar>
- fun listOutBar(): List<@JvmWildcard Bar>
- fun barUsage(): BarUsage
- }
-
- @Module
- object BarModule {
- @Singleton
- @Provides
- fun provideListBar(): List<Bar> = listOf(Bar("provideListBar"))
-
- @Singleton
- @Provides
- fun provideListOutBar(): List<@JvmWildcard Bar> = listOf(Bar("provideListOutBar"))
- }
-
- @Suppress("BadInject") // We're using constructor and members injection on purpose for this test.
- class BarUsage @Inject constructor(
- val listBar1: List<Bar>,
- val listOutBar1: List<@JvmWildcard Bar>,
- ) {
- @Inject lateinit var listBar2: List<Bar>
- @Inject lateinit var listOutBar2: List<@JvmWildcard Bar>
- lateinit var listBar3: List<Bar>
- lateinit var listOutBar3: List<Bar>
-
- @Inject
- fun injectMethod(
- listBar3: List<Bar>,
- listOutBar3: List<@JvmWildcard Bar>,
- ) {
- this.listBar3 = listBar3
- this.listOutBar3 = listOutBar3
- }
- }
-
- class Bar(val providesMethod: String) {
- override fun toString(): String = providesMethod
- }
-
- @Test
- fun testFinalClassBarUsedAsTypeArgument() {
- val component = DaggerDeclarationVarianceTest_BarComponent.create()
- val listBar = component.listBar()
- val listOutBar = component.listOutBar()
- val barUsage = component.barUsage()
-
- assertThat(listBar).isNotNull()
- assertThat(listOutBar).isNotNull()
- assertThat(listBar).isNotEqualTo(listOutBar)
-
- assertThat(barUsage.listBar1).isEqualTo(listBar)
- assertThat(barUsage.listBar2).isEqualTo(listBar)
- assertThat(barUsage.listBar3).isEqualTo(listBar)
-
- assertThat(barUsage.listOutBar1).isEqualTo(listOutBar)
- assertThat(barUsage.listOutBar2).isEqualTo(listOutBar)
- assertThat(barUsage.listOutBar3).isEqualTo(listOutBar)
- }
-
- @Singleton
- @Component(modules = [FooModule::class])
- interface FooComponent {
- fun listFoo(): List<Foo>
- fun listOutFoo(): List<@JvmWildcard Foo>
- fun fooUsage(): FooUsage
- }
-
- @Module
- object FooModule {
- @Singleton
- @Provides
- fun provideListFoo(): List<Foo> = listOf(Foo("provideListFoo"))
-
- @Singleton
- @Provides
- fun provideListOutFoo(): List<@JvmWildcard Foo> = listOf(Foo("provideListOutFoo"))
- }
-
- @Suppress("BadInject") // We're using constructor and members injection on purpose for this test.
- class FooUsage @Inject constructor(
- val listFoo1: List<@JvmSuppressWildcards Foo>,
- val listOutFoo1: List<Foo>,
- ) {
- @Inject lateinit var listFoo2: List<@JvmSuppressWildcards Foo>
- @Inject lateinit var listOutFoo2: List<@JvmWildcard Foo>
- lateinit var listFoo3: List<Foo>
- lateinit var listOutFoo3: List<Foo>
-
- @Inject
- fun injectMethod(
- listFoo3: List<@JvmSuppressWildcards Foo>,
- listOutFoo3: List<Foo>,
- ) {
- this.listFoo3 = listFoo3
- this.listOutFoo3 = listOutFoo3
- }
- }
-
- open class Foo(val providesMethod: String) {
- override fun toString(): String = providesMethod
- }
-
- @Test
- fun testOpenClassFooUsedAsTypeArgument() {
- val component = DaggerDeclarationVarianceTest_FooComponent.create()
- val listFoo = component.listFoo()
- val listOutFoo = component.listOutFoo()
- val fooUsage = component.fooUsage()
-
- assertThat(listFoo).isNotNull()
- assertThat(listOutFoo).isNotNull()
- assertThat(listFoo).isNotEqualTo(listOutFoo)
-
- assertThat(fooUsage.listFoo1).isEqualTo(listFoo)
- assertThat(fooUsage.listFoo2).isEqualTo(listFoo)
- assertThat(fooUsage.listFoo3).isEqualTo(listFoo)
-
- assertThat(fooUsage.listOutFoo1).isEqualTo(listOutFoo)
- assertThat(fooUsage.listOutFoo2).isEqualTo(listOutFoo)
- assertThat(fooUsage.listOutFoo3).isEqualTo(listOutFoo)
- }
-}
diff --git a/javatests/dagger/hilt/android/BUILD b/javatests/dagger/hilt/android/BUILD
index 97798ea..8f927fb 100644
--- a/javatests/dagger/hilt/android/BUILD
+++ b/javatests/dagger/hilt/android/BUILD
@@ -14,7 +14,7 @@
# Description:
# Tests for internal code for implementing Hilt processors.
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_android_library")
+load("//third_party/kotlin/build_extensions:rules.bzl", "kt_android_library")
package(default_visibility = ["//:src"])
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
index 1a4d0c5..146f537 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
@@ -34,9 +34,9 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/compile_testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
@@ -53,9 +53,8 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java
index b39cd6b..1a36c71 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/EarlyEntryPointProcessorTest.java
@@ -16,12 +16,8 @@
package dagger.hilt.android.processor.internal.aggregateddeps;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
+import androidx.room.compiler.processing.util.Source;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -31,8 +27,8 @@
@Test
public void testUsedWithEntryPoint_fails() {
- JavaFileObject entryPoint =
- JavaFileObjects.forSourceLines(
+ Source entryPoint =
+ HiltCompilerTests.javaSource(
"test.UsedWithEntryPoint",
"package test;",
"",
@@ -45,21 +41,24 @@
"@EntryPoint",
"@InstallIn(SingletonComponent.class)",
"public interface UsedWithEntryPoint {}");
- Compilation compilation = compiler().compile(entryPoint);
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "Only one of the following annotations can be used on test.UsedWithEntryPoint: "
- + "[dagger.hilt.EntryPoint, dagger.hilt.android.EarlyEntryPoint]")
- .inFile(entryPoint)
- .onLine(11);
+ HiltCompilerTests.hiltCompiler(entryPoint)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "Only one of the following annotations can be used on"
+ + " test.UsedWithEntryPoint: [dagger.hilt.EntryPoint,"
+ + " dagger.hilt.android.EarlyEntryPoint]")
+ .onSource(entryPoint)
+ .onLine(11);
+ });
}
@Test
public void testNotSingletonComponent_fails() {
- JavaFileObject entryPoint =
- JavaFileObjects.forSourceLines(
+ Source entryPoint =
+ HiltCompilerTests.javaSource(
"test.NotSingletonComponent",
"package test;",
"",
@@ -72,21 +71,23 @@
"@InstallIn(ActivityComponent.class)",
"public interface NotSingletonComponent {}");
- Compilation compilation = compiler().compile(entryPoint);
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@EarlyEntryPoint can only be installed into the SingletonComponent. "
- + "Found: [dagger.hilt.android.components.ActivityComponent]")
- .inFile(entryPoint)
- .onLine(10);
+ HiltCompilerTests.hiltCompiler(entryPoint)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@EarlyEntryPoint can only be installed into the SingletonComponent. "
+ + "Found: [dagger.hilt.android.components.ActivityComponent]")
+ .onSource(entryPoint)
+ .onLine(10);
+ });
}
@Test
public void testThatTestInstallInCannotOriginateFromTest() {
- JavaFileObject test =
- JavaFileObjects.forSourceLines(
+ Source test =
+ HiltCompilerTests.javaSource(
"test.MyTest",
"package test;",
"",
@@ -102,15 +103,17 @@
" @InstallIn(SingletonComponent.class)",
" interface NestedEarlyEntryPoint {}",
"}");
- Compilation compilation = compiler().compile(test);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@EarlyEntryPoint-annotated entry point, test.MyTest.NestedEarlyEntryPoint, cannot "
- + "be nested in (or originate from) a @HiltAndroidTest-annotated class, "
- + "test.MyTest.")
- .inFile(test)
- .onLine(13);
+ HiltCompilerTests.hiltCompiler(test)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@EarlyEntryPoint-annotated entry point, test.MyTest.NestedEarlyEntryPoint,"
+ + " cannot be nested in (or originate from) a @HiltAndroidTest-annotated"
+ + " class, test.MyTest.")
+ .onSource(test)
+ .onLine(13);
+ });
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
index e4e9f67..390af9a 100644
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
@@ -19,8 +19,10 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
+import androidx.room.compiler.processing.util.Source;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,6 +31,7 @@
@RunWith(JUnit4.class)
public class TestInstallInTest {
+ // TODO(danysantiago): Migrate to hiltCompiler() after b/288893275 is fixed.
@Test
public void testMissingValues() {
JavaFileObject testInstallInModule =
@@ -55,8 +58,8 @@
@Test
public void testEmptyComponentValues() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
+ Source installInModule =
+ HiltCompilerTests.javaSource(
"test.InstallInModule",
"package test;",
"",
@@ -67,8 +70,8 @@
"@Module",
"@InstallIn(SingletonComponent.class)",
"interface InstallInModule {}");
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
+ Source testInstallInModule =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -78,21 +81,23 @@
"@Module",
"@TestInstallIn(components = {}, replaces = InstallInModule.class)",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(installInModule, testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- // TODO(bcorso): Add inFile().onLine() whenever we've fixed Processors.getAnnotationClassValues
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn, 'components' class is invalid or missing: "
- + "@dagger.hilt.testing.TestInstallIn("
- + "components={}, replaces={test.InstallInModule.class})");
+ HiltCompilerTests.hiltCompiler(installInModule, testInstallInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ // TODO(bcorso): Add inFile().onLine() whenever we've fixed
+ // Processors.getAnnotationClassValues
+ subject.hasErrorContaining(
+ "@TestInstallIn, 'components' class is invalid or missing: "
+ + "@dagger.hilt.testing.TestInstallIn("
+ + "components={}, replaces={test.InstallInModule})");
+ });
}
@Test
public void testEmptyReplacesValues() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
+ Source testInstallInModule =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -103,21 +108,23 @@
"@Module",
"@TestInstallIn(components = SingletonComponent.class, replaces = {})",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- // TODO(bcorso): Add inFile().onLine() whenever we've fixed Processors.getAnnotationClassValues
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn, 'replaces' class is invalid or missing: "
- + "@dagger.hilt.testing.TestInstallIn("
- + "components={dagger.hilt.components.SingletonComponent.class}, replaces={})");
+ HiltCompilerTests.hiltCompiler(testInstallInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ // TODO(bcorso): Add inFile().onLine() whenever we've fixed
+ // Processors.getAnnotationClassValues
+ subject.hasErrorContaining(
+ "@TestInstallIn, 'replaces' class is invalid or missing: "
+ + "@dagger.hilt.testing.TestInstallIn("
+ + "components={dagger.hilt.components.SingletonComponent}, replaces={})");
+ });
}
@Test
public void testMissingModuleAnnotation() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
+ Source installInModule =
+ HiltCompilerTests.javaSource(
"test.InstallInModule",
"package test;",
"",
@@ -128,8 +135,8 @@
"@Module",
"@InstallIn(SingletonComponent.class)",
"interface InstallInModule {}");
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
+ Source testInstallInModule =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -141,21 +148,23 @@
" components = SingletonComponent.class,",
" replaces = InstallInModule.class)",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(installInModule, testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn-annotated classes must also be annotated with @Module or @EntryPoint: "
- + "test.TestInstallInModule")
- .inFile(testInstallInModule)
- .onLine(10);
+ HiltCompilerTests.hiltCompiler(installInModule, testInstallInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@TestInstallIn-annotated classes must also be annotated with @Module or"
+ + " @EntryPoint: test.TestInstallInModule")
+ .onSource(testInstallInModule)
+ .onLine(10);
+ });
}
@Test
public void testInvalidUsageOnEntryPoint() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
+ Source installInModule =
+ HiltCompilerTests.javaSource(
"test.InstallInModule",
"package test;",
"",
@@ -166,8 +175,8 @@
"@Module",
"@InstallIn(SingletonComponent.class)",
"interface InstallInModule {}");
- JavaFileObject testInstallInEntryPoint =
- JavaFileObjects.forSourceLines(
+ Source testInstallInEntryPoint =
+ HiltCompilerTests.javaSource(
"test.TestInstallInEntryPoint",
"package test;",
"",
@@ -180,21 +189,22 @@
" components = SingletonComponent.class,",
" replaces = InstallInModule.class)",
"interface TestInstallInEntryPoint {}");
- Compilation compilation = compiler().compile(installInModule, testInstallInEntryPoint);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("@TestInstallIn can only be used with modules")
- .inFile(testInstallInEntryPoint)
- .onLine(11);
+ HiltCompilerTests.hiltCompiler(installInModule, testInstallInEntryPoint)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("@TestInstallIn can only be used with modules")
+ .onSource(testInstallInEntryPoint)
+ .onLine(11);
+ });
}
@Test
public void testInvalidReplaceModules() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "class Foo {}");
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
+ Source foo = HiltCompilerTests.javaSource("test.Foo", "package test;", "", "class Foo {}");
+ Source testInstallInModule =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -207,20 +217,23 @@
" components = SingletonComponent.class,",
" replaces = Foo.class)",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(foo, testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn#replaces() can only contain @InstallIn modules, but found: [test.Foo]")
- .inFile(testInstallInModule)
- .onLine(11);
+ HiltCompilerTests.hiltCompiler(foo, testInstallInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@TestInstallIn#replaces() can only contain @InstallIn modules, but found:"
+ + " [test.Foo]")
+ .onSource(testInstallInModule)
+ .onLine(11);
+ });
}
@Test
public void testInternalDaggerReplaceModules() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
+ Source testInstallInModule =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -233,21 +246,23 @@
" components = SingletonComponent.class,",
" replaces = dagger.hilt.android.internal.modules.ApplicationContextModule.class)",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn#replaces() cannot contain internal Hilt modules, but found: "
- + "[dagger.hilt.android.internal.modules.ApplicationContextModule]")
- .inFile(testInstallInModule)
- .onLine(11);
+ HiltCompilerTests.hiltCompiler(testInstallInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@TestInstallIn#replaces() cannot contain internal Hilt modules, but found: "
+ + "[dagger.hilt.android.internal.modules.ApplicationContextModule]")
+ .onSource(testInstallInModule)
+ .onLine(11);
+ });
}
@Test
public void testHiltWrapperDaggerReplaceModules() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
+ Source testInstallInModule =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -264,22 +279,25 @@
// handle modules generated in the same round.
" replaces = HiltWrapper_InstallInModule.class)",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn#replaces() cannot contain Hilt generated public wrapper modules, "
- + "but found: [dagger.hilt.android.processor.internal.aggregateddeps."
- + "HiltWrapper_InstallInModule]")
- .inFile(testInstallInModule)
- .onLine(12);
+ HiltCompilerTests.hiltCompiler(testInstallInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@TestInstallIn#replaces() cannot contain Hilt generated public wrapper"
+ + " modules, but found:"
+ + " [dagger.hilt.android.processor.internal.aggregateddeps."
+ + "HiltWrapper_InstallInModule]")
+ .onSource(testInstallInModule)
+ .onLine(12);
+ });
}
@Test
public void testCannotReplaceLocalInstallInModule() {
- JavaFileObject test =
- JavaFileObjects.forSourceLines(
+ Source test =
+ HiltCompilerTests.javaSource(
"test.MyTest",
"package test;",
"",
@@ -295,8 +313,8 @@
" @InstallIn(SingletonComponent.class)",
" interface LocalInstallInModule {}",
"}");
- JavaFileObject testInstallIn =
- JavaFileObjects.forSourceLines(
+ Source testInstallIn =
+ HiltCompilerTests.javaSource(
"test.TestInstallInModule",
"package test;",
"",
@@ -309,21 +327,23 @@
" components = SingletonComponent.class,",
" replaces = MyTest.LocalInstallInModule.class)",
"interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(test, testInstallIn);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "TestInstallIn#replaces() cannot replace test specific @InstallIn modules, but found: "
- + "[test.MyTest.LocalInstallInModule].")
- .inFile(testInstallIn)
- .onLine(11);
+ HiltCompilerTests.hiltCompiler(test, testInstallIn)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "TestInstallIn#replaces() cannot replace test specific @InstallIn modules,"
+ + " but found: [test.MyTest.LocalInstallInModule].")
+ .onSource(testInstallIn)
+ .onLine(11);
+ });
}
@Test
public void testThatTestInstallInCannotOriginateFromTest() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
+ Source installInModule =
+ HiltCompilerTests.javaSource(
"test.InstallInModule",
"package test;",
"",
@@ -334,8 +354,8 @@
"@Module",
"@InstallIn(SingletonComponent.class)",
"interface InstallInModule {}");
- JavaFileObject test =
- JavaFileObjects.forSourceLines(
+ Source test =
+ HiltCompilerTests.javaSource(
"test.MyTest",
"package test;",
"",
@@ -352,14 +372,16 @@
" replaces = InstallInModule.class)",
" interface TestInstallInModule {}",
"}");
- Compilation compilation = compiler().compile(test, installInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@TestInstallIn modules cannot be nested in (or originate from) a "
- + "@HiltAndroidTest-annotated class: test.MyTest")
- .inFile(test)
- .onLine(14);
+ HiltCompilerTests.hiltCompiler(test, installInModule)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@TestInstallIn modules cannot be nested in (or originate from) a "
+ + "@HiltAndroidTest-annotated class: test.MyTest")
+ .onSource(test)
+ .onLine(14);
+ });
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
index b6674d4..b58c355 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
@@ -16,23 +16,22 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
+import androidx.room.compiler.processing.util.Source;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
+import dagger.testing.golden.GoldenFileRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ActivityGeneratorTest {
+ @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule();
@Test
public void generate_componentActivity() {
- JavaFileObject myActivity =
- JavaFileObjects.forSourceLines(
+ Source myActivity =
+ HiltCompilerTests.javaSource(
"test.MyActivity",
"package test;",
"",
@@ -42,14 +41,13 @@
"@AndroidEntryPoint(ComponentActivity.class)",
"public class MyActivity extends Hilt_MyActivity {",
"}");
- Compilation compilation = compiler().compile(myActivity);
- assertThat(compilation).succeeded();
+ HiltCompilerTests.hiltCompiler(myActivity).compile(subject -> subject.hasErrorCount(0));
}
@Test
public void generate_baseHiltComponentActivity() {
- JavaFileObject baseActivity =
- JavaFileObjects.forSourceLines(
+ Source baseActivity =
+ HiltCompilerTests.javaSource(
"test.BaseActivity",
"package test;",
"",
@@ -59,8 +57,8 @@
"@AndroidEntryPoint(ComponentActivity.class)",
"public class BaseActivity extends Hilt_BaseActivity {",
"}");
- JavaFileObject myActivity =
- JavaFileObjects.forSourceLines(
+ Source myActivity =
+ HiltCompilerTests.javaSource(
"test.MyActivity",
"package test;",
"",
@@ -70,7 +68,7 @@
"@AndroidEntryPoint(BaseActivity.class)",
"public class MyActivity extends Hilt_MyActivity {",
"}");
- Compilation compilation = compiler().compile(baseActivity, myActivity);
- assertThat(compilation).succeeded();
+ HiltCompilerTests.hiltCompiler(baseActivity, myActivity)
+ .compile(subject -> subject.hasErrorCount(0));
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
index a5f85a2..f39d897 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
@@ -19,8 +19,12 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.util.CompilationResultSubject;
+import androidx.room.compiler.processing.util.Source;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -28,11 +32,31 @@
@RunWith(JUnit4.class)
public class AndroidEntryPointProcessorTest {
+ @Test
+ public void testAndroidEntryPoint() {
+ Source testActivity =
+ HiltCompilerTests.javaSource(
+ "test.MyActivity",
+ "package test;",
+ "",
+ "import androidx.activity.ComponentActivity;",
+ "import dagger.hilt.android.AndroidEntryPoint;",
+ "",
+ "@AndroidEntryPoint(ComponentActivity.class)",
+ "public class MyActivity extends Hilt_MyActivity {}");
+
+ HiltCompilerTests.hiltCompiler(testActivity)
+ .compile(
+ (CompilationResultSubject subject) -> {
+ subject.hasErrorCount(0);
+ subject.generatedSourceFileWithPath("test/Hilt_MyActivity.java");
+ });
+ }
@Test
public void missingBaseClass() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
+ Source testActivity =
+ HiltCompilerTests.javaSource(
"test.MyActivity",
"package test;",
"",
@@ -41,17 +65,20 @@
"",
"@AndroidEntryPoint",
"public class MyActivity extends ComponentActivity { }");
- Compilation compilation = compiler().compile(testActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Expected @AndroidEntryPoint to have a value.")
- ;
+ HiltCompilerTests.hiltCompiler(testActivity)
+ .compile(
+ (CompilationResultSubject subject) -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Expected @AndroidEntryPoint to have a value.")
+ ;
+ });
}
@Test
public void incorrectSuperclass() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
+ Source testActivity =
+ HiltCompilerTests.javaSource(
"test.MyActivity",
"package test;",
"",
@@ -60,13 +87,21 @@
"",
"@AndroidEntryPoint(ComponentActivity.class)",
"public class MyActivity extends ComponentActivity { }");
- Compilation compilation = compiler().compile(testActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@AndroidEntryPoint class expected to extend Hilt_MyActivity. "
- + "Found: ComponentActivity")
- ;
+ HiltCompilerTests.hiltCompiler(testActivity)
+ .compile(
+ (CompilationResultSubject subject) -> {
+ // TODO(b/288210593): Add this check back to KSP once this bug is fixed.
+ if (HiltCompilerTests.backend(subject) == XProcessingEnv.Backend.KSP) {
+ subject.hasErrorCount(0);
+ } else {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining(
+ "@AndroidEntryPoint class expected to extend Hilt_MyActivity. "
+ + "Found: ComponentActivity")
+ ;
+ }
+ });
}
@Test
@@ -150,8 +185,8 @@
@Test
public void checkAndroidEntryPointOnApplicationRecommendsHiltAndroidApp() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
+ Source testActivity =
+ HiltCompilerTests.javaSource(
"test.MyApplication",
"package test;",
"",
@@ -160,10 +195,20 @@
"",
"@AndroidEntryPoint(Application.class)",
"public class MyApplication extends Hilt_MyApplication { }");
- Compilation compilation = compiler().compile(testActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("@AndroidEntryPoint cannot be used on an Application. "
- + "Use @HiltAndroidApp instead.");
+ HiltCompilerTests.hiltCompiler(testActivity)
+ .compile(
+ (CompilationResultSubject subject) -> {
+ if (HiltCompilerTests.backend(subject) == XProcessingEnv.Backend.KSP) {
+ subject.hasErrorCount(1);
+ } else {
+ // Javac has an extra error due to the missing symbol.
+ subject.hasErrorCount(2);
+ subject.hasErrorContaining(
+ "cannot find symbol\n symbol: class Hilt_MyApplication");
+ }
+ subject.hasErrorContaining(
+ "@AndroidEntryPoint cannot be used on an Application. "
+ + "Use @HiltAndroidApp instead.");
+ });
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
index c823542..10be147 100644
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
@@ -25,11 +25,14 @@
"//java/dagger/hilt/android:android_entry_point",
"@androidsdk//:platforms/android-32/android.jar",
],
+ resources = glob([
+ "goldens/ActivityGeneratorTest_*",
+ ]),
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
+ "//java/dagger/testing/golden",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
@@ -42,10 +45,12 @@
"@androidsdk//:platforms/android-32/android.jar",
],
deps = [
+ "//java/dagger/hilt/android:android_entry_point",
"//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/compile_testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
index 7525833..a8d2cb9 100644
--- a/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/customtestapplication/BUILD
@@ -29,7 +29,7 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
+ "//third_party/java/guava/collect",
"//third_party/java/junit",
"//third_party/java/truth",
],
diff --git a/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java
index beadecf..215296f 100644
--- a/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java
+++ b/javatests/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessorTest.java
@@ -16,23 +16,27 @@
package dagger.hilt.android.processor.internal.customtestapplication;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
+import static com.google.common.truth.Truth.assertThat;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
+import com.google.common.collect.ImmutableList;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class CustomTestApplicationProcessorTest {
+ @Rule public TemporaryFolder tempFolderRule = new TemporaryFolder();
+
@Test
public void validBaseClass_succeeds() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
+ HiltCompilerTests.compileWithKapt(
+ ImmutableList.of(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
@@ -42,41 +46,35 @@
"",
"@CustomTestApplication(Application.class)",
"@HiltAndroidTest",
- "public class HiltTest {}"));
-
- assertThat(compilation).succeeded();
+ "public class HiltTest {}")),
+ tempFolderRule,
+ result -> assertThat(result.getSuccess()).isTrue());
}
@Test
public void incorrectBaseType_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "public class Foo {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource("test.Foo", "package test;", "", "public class Foo {}"),
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(Foo.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication value should be an instance of android.app.Application. "
- + "Found: test.Foo");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication value should be an instance of android.app.Application. "
+ + "Found: test.Foo");
+ });
}
@Test
public void baseWithHiltAndroidApp_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -85,27 +83,26 @@
"",
"@HiltAndroidApp(Application.class)",
"public class BaseApplication extends Hilt_BaseApplication {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(BaseApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication value cannot be annotated with @HiltAndroidApp. "
- + "Found: test.BaseApplication");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication value cannot be annotated with @HiltAndroidApp. "
+ + "Found: test.BaseApplication");
+ });
}
@Test
public void superclassWithHiltAndroidApp_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -114,32 +111,31 @@
"",
"@HiltAndroidApp(Application.class)",
"public class BaseApplication extends Hilt_BaseApplication {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.ParentApplication",
"package test;",
"",
"public class ParentApplication extends BaseApplication {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(ParentApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication value cannot be annotated with @HiltAndroidApp. "
- + "Found: test.BaseApplication");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication value cannot be annotated with @HiltAndroidApp. "
+ + "Found: test.BaseApplication");
+ });
}
@Test
public void withInjectField_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -149,27 +145,27 @@
"public class BaseApplication extends Application {",
" @Inject String str;",
"}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(BaseApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication does not support application classes (or super classes) with "
- + "@Inject fields. Found test.BaseApplication with @Inject fields [str]");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication does not support application classes (or super classes)"
+ + " with @Inject fields. Found test.BaseApplication with @Inject fields"
+ + " [str]");
+ });
}
@Test
public void withSuperclassInjectField_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -179,32 +175,32 @@
"public class BaseApplication extends Application {",
" @Inject String str;",
"}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.ParentApplication",
"package test;",
"",
"public class ParentApplication extends BaseApplication {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(ParentApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication does not support application classes (or super classes) with "
- + "@Inject fields. Found test.BaseApplication with @Inject fields [str]");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication does not support application classes (or super classes)"
+ + " with @Inject fields. Found test.BaseApplication with @Inject fields"
+ + " [str]");
+ });
}
@Test
public void withInjectMethod_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -214,27 +210,27 @@
"public class BaseApplication extends Application {",
" @Inject String str() { return null; }",
"}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(BaseApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication does not support application classes (or super classes) with "
- + "@Inject methods. Found test.BaseApplication with @Inject methods [str()]");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication does not support application classes (or super classes)"
+ + " with @Inject methods. Found test.BaseApplication with @Inject methods"
+ + " [str()]");
+ });
}
@Test
public void withSuperclassInjectMethod_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -244,32 +240,32 @@
"public class BaseApplication extends Application {",
" @Inject String str() { return null; }",
"}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.ParentApplication",
"package test;",
"",
"public class ParentApplication extends BaseApplication {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(ParentApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication does not support application classes (or super classes) with "
- + "@Inject methods. Found test.BaseApplication with @Inject methods [str()]");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication does not support application classes (or super classes)"
+ + " with @Inject methods. Found test.BaseApplication with @Inject methods"
+ + " [str()]");
+ });
}
@Test
public void withInjectConstructor_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -279,28 +275,27 @@
"public class BaseApplication extends Application {",
" @Inject BaseApplication() {}",
"}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(BaseApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication does not support application classes (or super classes) with "
- + "@Inject constructors. Found test.BaseApplication with @Inject constructors "
- + "[BaseApplication()]");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication does not support application classes (or super classes)"
+ + " with @Inject constructors. Found test.BaseApplication with @Inject"
+ + " constructors [BaseApplication()]");
+ });
}
@Test
public void withSuperclassInjectConstructor_fails() {
- Compilation compilation =
- compiler().compile(
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
"test.BaseApplication",
"package test;",
"",
@@ -310,25 +305,25 @@
"public class BaseApplication extends Application {",
" @Inject BaseApplication() {}",
"}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.ParentApplication",
"package test;",
"",
"public class ParentApplication extends BaseApplication {}"),
- JavaFileObjects.forSourceLines(
+ HiltCompilerTests.javaSource(
"test.HiltTest",
"package test;",
"",
"import dagger.hilt.android.testing.CustomTestApplication;",
"",
"@CustomTestApplication(ParentApplication.class)",
- "public class HiltTest {}"));
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@CustomTestApplication does not support application classes (or super classes) with "
- + "@Inject constructors. Found test.BaseApplication with @Inject constructors "
- + "[BaseApplication()]");
+ "public class HiltTest {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorContaining(
+ "@CustomTestApplication does not support application classes (or super classes)"
+ + " with @Inject constructors. Found test.BaseApplication with @Inject"
+ + " constructors [BaseApplication()]");
+ });
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
index 99d00dc..79d7cbe 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
@@ -20,30 +20,20 @@
package(default_visibility = ["//:src"])
-java_test(
+kt_compiler_test(
name = "ViewModelProcessorTest",
- runtime_deps = [
- ":ViewModelProcessorTestLib",
- "//java/dagger/hilt/android/lifecycle:hilt_view_model",
- "//third_party/java/compile_testing",
- "//third_party/java/truth",
+ srcs = ["ViewModelProcessorTest.kt"],
+ compiler_deps = [
+ "//java/dagger/hilt/android:hilt_android_app",
"@androidsdk//:platforms/android-32/android.jar",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- ],
-)
-
-kt_jvm_library(
- name = "ViewModelProcessorTestLib",
- srcs = [
- "ViewModelProcessorTest.kt",
+ "//java/dagger/hilt/android/lifecycle:hilt_view_model",
],
deps = [
- ":test_utils",
"//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "//third_party/java/compile_testing",
+ "//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt
index b3eaeab..b35aed2 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt
@@ -16,20 +16,22 @@
package dagger.hilt.android.processor.internal.viewmodel
-import com.google.testing.compile.CompilationSubject.assertThat
-import com.google.testing.compile.Compiler
+import androidx.room.compiler.processing.ExperimentalProcessingApi
+import androidx.room.compiler.processing.util.Source
+import dagger.hilt.android.testing.compile.HiltCompilerTests
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+@OptIn(ExperimentalProcessingApi::class)
@RunWith(JUnit4::class)
class ViewModelProcessorTest {
-
- private fun compiler(): Compiler = Compiler.javac().withProcessors(ViewModelProcessor())
-
@Test
fun validViewModel() {
- val myViewModel = """
+ val myViewModel =
+ Source.java(
+ "dagger.hilt.android.test.MyViewModel",
+ """
package dagger.hilt.android.test;
import androidx.lifecycle.ViewModel;
@@ -40,15 +42,21 @@
class MyViewModel extends ViewModel {
@Inject MyViewModel() { }
}
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).succeeded()
+ """
+ .trimIndent()
+ )
+ HiltCompilerTests.hiltCompiler(myViewModel)
+ .withAdditionalJavacProcessors(ViewModelProcessor())
+ .withAdditionalKspProcessors(KspViewModelProcessor.Provider())
+ .compile { subject -> subject.hasErrorCount(0) }
}
@Test
fun verifyEnclosingElementExtendsViewModel() {
- val myViewModel = """
+ val myViewModel =
+ Source.java(
+ "dagger.hilt.android.test.MyViewModel",
+ """
package dagger.hilt.android.test;
import dagger.hilt.android.lifecycle.HiltViewModel;
@@ -59,21 +67,28 @@
@Inject
MyViewModel() { }
}
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "@HiltViewModel is only supported on types that subclass androidx.lifecycle.ViewModel."
+ """
+ .trimIndent()
)
- }
+
+ HiltCompilerTests.hiltCompiler(myViewModel)
+ .withAdditionalJavacProcessors(ViewModelProcessor())
+ .withAdditionalKspProcessors(KspViewModelProcessor.Provider())
+ .compile { subject ->
+ subject.compilationDidFail()
+ subject.hasErrorCount(1)
+ subject.hasErrorContainingMatch(
+ "@HiltViewModel is only supported on types that subclass androidx.lifecycle.ViewModel."
+ )
+ }
}
@Test
fun verifySingleAnnotatedConstructor() {
- val myViewModel = """
+ val myViewModel =
+ Source.java(
+ "dagger.hilt.android.test.MyViewModel",
+ """
package dagger.hilt.android.test;
import androidx.lifecycle.ViewModel;
@@ -88,21 +103,31 @@
@Inject
MyViewModel(String s) { }
}
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "@HiltViewModel annotated class should contain exactly one @Inject annotated constructor."
+ """
+ .trimIndent()
)
- }
+
+ HiltCompilerTests.hiltCompiler(myViewModel)
+ .withAdditionalJavacProcessors(ViewModelProcessor())
+ .withAdditionalKspProcessors(KspViewModelProcessor.Provider())
+ .compile { subject ->
+ subject.compilationDidFail()
+ subject.hasErrorCount(2)
+ subject.hasErrorContaining(
+ "Type dagger.hilt.android.test.MyViewModel may only contain one injected constructor. Found: [@Inject dagger.hilt.android.test.MyViewModel(), @Inject dagger.hilt.android.test.MyViewModel(String)]"
+ )
+ subject.hasErrorContaining(
+ "@HiltViewModel annotated class should contain exactly one @Inject annotated constructor."
+ )
+ }
}
@Test
fun verifyNonPrivateConstructor() {
- val myViewModel = """
+ val myViewModel =
+ Source.java(
+ "dagger.hilt.android.test.MyViewModel",
+ """
package dagger.hilt.android.test;
import androidx.lifecycle.ViewModel;
@@ -114,22 +139,27 @@
@Inject
private MyViewModel() { }
}
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "@Inject annotated constructors must not be " +
- "private."
+ """
+ .trimIndent()
)
- }
+
+ HiltCompilerTests.hiltCompiler(myViewModel)
+ .withAdditionalJavacProcessors(ViewModelProcessor())
+ .withAdditionalKspProcessors(KspViewModelProcessor.Provider())
+ .compile { subject ->
+ subject.compilationDidFail()
+ subject.hasErrorCount(2)
+ subject.hasErrorContaining("Dagger does not support injection into private constructors")
+ subject.hasErrorContaining("@Inject annotated constructors must not be private.")
+ }
}
@Test
fun verifyInnerClassIsStatic() {
- val myViewModel = """
+ val myViewModel =
+ Source.java(
+ "dagger.hilt.android.test.Outer",
+ """
package dagger.hilt.android.test;
import androidx.lifecycle.ViewModel;
@@ -143,21 +173,31 @@
MyViewModel() { }
}
}
- """.toJFO("dagger.hilt.android.test.Outer")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "@HiltViewModel may only be used on inner classes if they are static."
+ """
+ .trimIndent()
)
- }
+
+ HiltCompilerTests.hiltCompiler(myViewModel)
+ .withAdditionalJavacProcessors(ViewModelProcessor())
+ .withAdditionalKspProcessors(KspViewModelProcessor.Provider())
+ .compile { subject ->
+ subject.compilationDidFail()
+ subject.hasErrorCount(2)
+ subject.hasErrorContaining(
+ "@Inject constructors are invalid on inner classes. Did you mean to make the class static?"
+ )
+ subject.hasErrorContaining(
+ "@HiltViewModel may only be used on inner classes if they are static."
+ )
+ }
}
@Test
fun verifyNoScopeAnnotation() {
- val myViewModel = """
+ val myViewModel =
+ Source.java(
+ "dagger.hilt.android.test.MyViewModel",
+ """
package dagger.hilt.android.test;
import androidx.lifecycle.ViewModel;
@@ -170,15 +210,19 @@
class MyViewModel extends ViewModel {
@Inject MyViewModel() { }
}
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "@HiltViewModel classes should not be scoped. Found: @javax.inject.Singleton"
+ """
+ .trimIndent()
)
- }
+
+ HiltCompilerTests.hiltCompiler(myViewModel)
+ .withAdditionalJavacProcessors(ViewModelProcessor())
+ .withAdditionalKspProcessors(KspViewModelProcessor.Provider())
+ .compile { subject ->
+ subject.compilationDidFail()
+ subject.hasErrorCount(1)
+ subject.hasErrorContainingMatch(
+ "@HiltViewModel classes should not be scoped. Found: @javax.inject.Singleton"
+ )
+ }
}
}
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
index 5fe40dd..89a79bb 100644
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
+++ b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
@@ -28,8 +28,7 @@
class ViewModelValidationPluginTest {
private fun testCompiler(): Compiler = compiler(
- ComponentProcessor.forTesting(ViewModelValidationPlugin()),
- ViewModelProcessor()
+ ComponentProcessor.withTestPlugins(ViewModelValidationPlugin()), ViewModelProcessor()
)
private val hiltAndroidApp = """
diff --git a/javatests/dagger/hilt/android/testing/BindValueInKotlinValTest.kt b/javatests/dagger/hilt/android/testing/BindValueInKotlinValTest.kt
index 6338ecf..15ecda0 100644
--- a/javatests/dagger/hilt/android/testing/BindValueInKotlinValTest.kt
+++ b/javatests/dagger/hilt/android/testing/BindValueInKotlinValTest.kt
@@ -30,6 +30,9 @@
@Named(TEST_QUALIFIER)
fun bindValueString2(): String
+
+ @Named(TEST_QUALIFIER_INTERNAL)
+ fun bindValueString3(): String
}
@get:Rule
@@ -42,6 +45,10 @@
@Named(TEST_QUALIFIER)
val bindValueString2 = BIND_VALUE_STRING2
+ @BindValue
+ @Named(TEST_QUALIFIER_INTERNAL)
+ internal val bindValueString3 = BIND_VALUE_STRING3
+
@BindValueIntoMap
@MyMapKey(BIND_VALUE_MAP_KEY_STRING)
val mapContribution = BIND_VALUE_MAP_VALUE_STRING
@@ -54,6 +61,10 @@
lateinit var string2: String
@Inject
+ @Named(TEST_QUALIFIER_INTERNAL)
+ lateinit var string3: String
+
+ @Inject
lateinit var map: Map<String, String>
@Test
@@ -61,6 +72,7 @@
rule.inject()
assertThat(string1).isEqualTo(BIND_VALUE_STRING1)
assertThat(string2).isEqualTo(BIND_VALUE_STRING2)
+ assertThat(string3).isEqualTo(BIND_VALUE_STRING3)
assertThat(map).containsExactlyEntriesIn(
mapOf(BIND_VALUE_MAP_KEY_STRING to BIND_VALUE_MAP_VALUE_STRING))
}
@@ -68,8 +80,10 @@
companion object {
private const val BIND_VALUE_STRING1 = "BIND_VALUE_STRING1"
private const val BIND_VALUE_STRING2 = "BIND_VALUE_STRING2"
+ private const val BIND_VALUE_STRING3 = "BIND_VALUE_STRING3"
private const val BIND_VALUE_MAP_KEY_STRING = "BIND_VALUE_MAP_KEY_STRING"
private const val BIND_VALUE_MAP_VALUE_STRING = "BIND_VALUE_MAP_VALUE_STRING"
private const val TEST_QUALIFIER = "TEST_QUALIFIER"
+ private const val TEST_QUALIFIER_INTERNAL = "TEST_QUALIFIER_INTERNAL"
}
}
diff --git a/javatests/dagger/hilt/processor/internal/BUILD b/javatests/dagger/hilt/processor/internal/BUILD
index d3fe2ac..3dfe1ea 100644
--- a/javatests/dagger/hilt/processor/internal/BUILD
+++ b/javatests/dagger/hilt/processor/internal/BUILD
@@ -18,18 +18,6 @@
package(default_visibility = ["//:src"])
java_test(
- name = "ElementDescriptorsTest",
- size = "small",
- srcs = ["ElementDescriptorsTest.java"],
- deps = [
- "//java/dagger/hilt/processor/internal:element_descriptors",
- "//third_party/java/compile_testing",
- "//third_party/java/junit",
- "//third_party/java/truth",
- ],
-)
-
-java_test(
name = "ProcessorsTest",
size = "small",
srcs = ["ProcessorsTest.java"],
diff --git a/javatests/dagger/hilt/processor/internal/ElementDescriptorsTest.java b/javatests/dagger/hilt/processor/internal/ElementDescriptorsTest.java
deleted file mode 100644
index a84bad9..0000000
--- a/javatests/dagger/hilt/processor/internal/ElementDescriptorsTest.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2019 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 com.google.common.truth.Truth.assertThat;
-
-import com.google.testing.compile.CompilationRule;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.ElementFilter;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ElementDescriptorsTest {
-
- @Rule public CompilationRule compilation = new CompilationRule();
-
- static class TestClassA<T> {
- int field1;
- String field2;
- T field3;
- List<String> field4;
- }
-
- @Test
- public void fieldDescriptor() {
- assertThat(getFieldDescriptors(TestClassA.class.getCanonicalName()))
- .containsExactly(
- "field1:I",
- "field2:Ljava/lang/String;",
- "field3:Ljava/lang/Object;",
- "field4:Ljava/util/List;");
- }
-
- static class TestClassB<T> {
- void method1(boolean yesOrNo, int number) {}
-
- byte method2(char letter) {
- return 0;
- }
-
- void method3(double realNumber1, float realNummber2) {}
-
- void method4(long bigNumber, short littlerNumber) {}
- }
-
- @Test
- public void methodDescriptor_primitives() {
- assertThat(getMethodDescriptors(TestClassB.class.getCanonicalName()))
- .containsExactly("method1(ZI)V", "method2(C)B", "method3(DF)V", "method4(JS)V");
- }
-
- static class TestClassC<T> {
- void method1(Object something) {}
-
- Object method2() {
- return null;
- }
-
- List<String> method3(ArrayList<Integer> list) {
- return null;
- }
-
- Map<String, Object> method4() {
- return null;
- }
- }
-
- @Test
- public void methodDescriptor_javaTypes() {
- assertThat(getMethodDescriptors(TestClassC.class.getCanonicalName()))
- .containsExactly(
- "method1(Ljava/lang/Object;)V",
- "method2()Ljava/lang/Object;",
- "method3(Ljava/util/ArrayList;)Ljava/util/List;",
- "method4()Ljava/util/Map;");
- }
-
- static class TestClassD<T> {
- void method1(TestDataClass data) {}
-
- TestDataClass method2() {
- return null;
- }
- }
-
- @Test
- public void methodDescriptor_testTypes() {
- assertThat(getMethodDescriptors(TestClassD.class.getCanonicalName()))
- .containsExactly(
- "method1(Ldagger/hilt/processor/internal/TestDataClass;)V",
- "method2()Ldagger/hilt/processor/internal/TestDataClass;");
- }
-
- static class TestClassE<T> {
- void method1(TestDataClass[] data) {}
-
- TestDataClass[] method2() {
- return null;
- }
-
- void method3(int[] array) {}
-
- void method4(int... array) {}
- }
-
- @Test
- public void methodDescriptor_arrays() {
- assertThat(getMethodDescriptors(TestClassE.class.getCanonicalName()))
- .containsExactly(
- "method1([Ldagger/hilt/processor/internal/TestDataClass;)V",
- "method2()[Ldagger/hilt/processor/internal/TestDataClass;",
- "method3([I)V",
- "method4([I)V");
- }
-
- static class TestClassF<T> {
- void method1(TestDataClass.MemberInnerData data) {}
-
- void method2(TestDataClass.StaticInnerData data) {}
-
- void method3(TestDataClass.EnumData enumData) {}
-
- TestDataClass.StaticInnerData method4() {
- return null;
- }
- }
-
- @Test
- public void methodDescriptor_innerTestType() {
- assertThat(getMethodDescriptors(TestClassF.class.getCanonicalName()))
- .containsExactly(
- "method1(Ldagger/hilt/processor/internal/TestDataClass$MemberInnerData;)V",
- "method2(Ldagger/hilt/processor/internal/TestDataClass$StaticInnerData;)V",
- "method3(Ldagger/hilt/processor/internal/TestDataClass$EnumData;)V",
- "method4()Ldagger/hilt/processor/internal/TestDataClass$StaticInnerData;");
- }
-
- @SuppressWarnings("TypeParameterUnusedInFormals")
- static class TestClassG<T> {
- void method1(T something) {}
-
- T method2() {
- return null;
- }
-
- List<? extends String> method3() {
- return null;
- }
-
- Map<T, String> method4() {
- return null;
- }
-
- ArrayList<Map<T, String>> method5() {
- return null;
- }
-
- static <I, O extends I> O method6(I input) {
- return null;
- }
-
- static <I, O extends String> O method7(I input) {
- return null;
- }
-
- static <P extends Collection<String> & Comparable<String>> P method8() {
- return null;
- }
-
- static <P extends String & List<Character>> P method9() {
- return null;
- }
- }
-
- @Test
- public void methodDescriptor_erasure() {
- assertThat(getMethodDescriptors(TestClassG.class.getCanonicalName()))
- .containsExactly(
- "method1(Ljava/lang/Object;)V",
- "method2()Ljava/lang/Object;",
- "method3()Ljava/util/List;",
- "method4()Ljava/util/Map;",
- "method5()Ljava/util/ArrayList;",
- "method6(Ljava/lang/Object;)Ljava/lang/Object;",
- "method7(Ljava/lang/Object;)Ljava/lang/String;",
- "method8()Ljava/util/Collection;",
- "method9()Ljava/lang/String;");
- }
-
- private Set<String> getFieldDescriptors(String className) {
- TypeElement testElement = compilation.getElements().getTypeElement(className);
- return ElementFilter.fieldsIn(testElement.getEnclosedElements()).stream()
- .map(ElementDescriptors::getFieldDescriptor)
- .collect(Collectors.toSet());
- }
-
- private Set<String> getMethodDescriptors(String className) {
- TypeElement testElement = compilation.getElements().getTypeElement(className);
- return ElementFilter.methodsIn(testElement.getEnclosedElements()).stream()
- .map(ElementDescriptors::getMethodDescriptor)
- .collect(Collectors.toSet());
- }
-}
-
-@SuppressWarnings("ClassCanBeStatic")
-class TestDataClass {
- class MemberInnerData {}
-
- static class StaticInnerData {}
-
- enum EnumData {
- VALUE1,
- VALUE2
- }
-}
diff --git a/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java b/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java
index b36a71d..71bdfdc 100644
--- a/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java
+++ b/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java
@@ -16,271 +16,286 @@
package dagger.hilt.processor.internal.aggregateddeps;
-import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.common.truth.Truth.assertThat;
-import com.google.common.base.Joiner;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
+import androidx.room.compiler.processing.util.Source;
+import com.google.common.collect.ImmutableList;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import dagger.hilt.processor.internal.GeneratedImport;
-import dagger.testing.compile.CompilerTests;
-import javax.tools.JavaFileObject;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for errors generated by {@link AggregatedDepsProcessor} */
@RunWith(JUnit4.class)
public class AggregatedDepsProcessorErrorsTest {
- private static final Joiner LINES = Joiner.on("\n");
+
+ @Rule public TemporaryFolder tempFolderRule = new TemporaryFolder();
@Test
public void reportMultipleAnnotationTypeKindErrors() {
- JavaFileObject source =
- JavaFileObjects.forSourceString(
+ Source source =
+ HiltCompilerTests.javaSource(
"foo.bar.AnnotationsOnWrongTypeKind",
- LINES.join(
- "package foo.bar;",
- "",
- "import dagger.hilt.EntryPoint;",
- "import dagger.hilt.InstallIn;",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.internal.ComponentEntryPoint;",
- "import dagger.hilt.internal.GeneratedEntryPoint;",
- "",
- "@InstallIn(SingletonComponent.class)",
- "@Module",
- "enum FooModule { VALUE }",
- "",
- "@InstallIn(SingletonComponent.class)",
- "@EntryPoint",
- "final class BarEntryPoint {}",
- "",
- "@InstallIn(SingletonComponent.class)",
- "@ComponentEntryPoint",
- "final class BazComponentEntryPoint {}",
- "",
- "@EntryPoint",
- "interface QuxEntryPoint {}",
- "",
- "@EntryPoint",
- "@Module",
- "interface DontMix{}",
- ""));
+ "package foo.bar;",
+ "",
+ "import dagger.hilt.EntryPoint;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.Module;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "import dagger.hilt.internal.ComponentEntryPoint;",
+ "import dagger.hilt.internal.GeneratedEntryPoint;",
+ "",
+ "@InstallIn(SingletonComponent.class)",
+ "@Module",
+ "enum FooModule { VALUE }",
+ "",
+ "@InstallIn(SingletonComponent.class)",
+ "@EntryPoint",
+ "final class BarEntryPoint {}",
+ "",
+ "@InstallIn(SingletonComponent.class)",
+ "@ComponentEntryPoint",
+ "final class BazComponentEntryPoint {}",
+ "",
+ "@EntryPoint",
+ "interface QuxEntryPoint {}",
+ "",
+ "@EntryPoint",
+ "@Module",
+ "interface DontMix{}",
+ "");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Only classes and interfaces can be annotated with @Module")
- .inFile(source)
- .onLine(12);
- assertThat(compilation)
- .hadErrorContaining("Only interfaces can be annotated with @EntryPoint")
- .inFile(source)
- .onLine(16);
- assertThat(compilation)
- .hadErrorContaining("Only interfaces can be annotated with @ComponentEntryPoint")
- .inFile(source)
- .onLine(20);
- assertThat(compilation)
- .hadErrorContaining(
- "@EntryPoint foo.bar.QuxEntryPoint must also be annotated with @InstallIn")
- .inFile(source)
- .onLine(23);
- assertThat(compilation)
- .hadErrorContaining("@Module and @EntryPoint cannot be used on the same interface")
- .inFile(source)
- .onLine(27);
+ HiltCompilerTests.hiltCompiler(source)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject
+ .hasErrorContaining("Only classes and interfaces can be annotated with @Module")
+ .onSource(source)
+ .onLine(12);
+ subject
+ .hasErrorContaining("Only interfaces can be annotated with @EntryPoint")
+ .onSource(source)
+ .onLine(16);
+ subject
+ .hasErrorContaining("Only interfaces can be annotated with @ComponentEntryPoint")
+ .onSource(source)
+ .onLine(20);
+ subject
+ .hasErrorContaining(
+ "@EntryPoint foo.bar.QuxEntryPoint must also be annotated with @InstallIn")
+ .onSource(source)
+ .onLine(23);
+ subject
+ .hasErrorContaining(
+ "@Module and @EntryPoint cannot be used on the same interface")
+ .onSource(source)
+ .onLine(27);
+ });
}
@Test
public void testInvalidComponentInInstallInAnnotation() {
- JavaFileObject module = JavaFileObjects.forSourceLines(
- "test.FooModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.android.qualifiers.ApplicationContext;",
- "",
- "@InstallIn(ApplicationContext.class)", // Error: Not a Hilt component
- "@Module",
- "final class FooModule {}");
+ Source module =
+ HiltCompilerTests.javaSource(
+ "test.FooModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.android.qualifiers.ApplicationContext;",
+ "",
+ "@InstallIn(ApplicationContext.class)", // Error: Not a Hilt component
+ "@Module",
+ "final class FooModule {}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(module);
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@InstallIn, can only be used with @DefineComponent-annotated classes, but found: "
- + "[dagger.hilt.android.qualifiers.ApplicationContext]")
- .inFile(module)
- .onLine(9);
+ HiltCompilerTests.hiltCompiler(module)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject
+ .hasErrorContaining(
+ "@InstallIn, can only be used with @DefineComponent-annotated classes, but"
+ + " found: [dagger.hilt.android.qualifiers.ApplicationContext]")
+ .onSource(module)
+ .onLine(9);
+ });
}
@Test
public void testMissingInstallInAnnotation() {
- JavaFileObject source = JavaFileObjects.forSourceString(
- "foo.bar.AnnotationsOnWrongTypeKind",
- LINES.join(
+ Source source =
+ HiltCompilerTests.javaSource(
+ "foo.bar.AnnotationsOnWrongTypeKind",
"package foo.bar;",
"",
"import dagger.Module;",
"",
- "@Module", // Error: Doesn't have InstallIn annotation
- "final class FooModule {}"));
+ "@Module", // Error: Doesn't have InstallIn annotation
+ "final class FooModule {}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("foo.bar.FooModule is missing an @InstallIn annotation")
- .inFile(source)
- .onLine(6);
+ HiltCompilerTests.hiltCompiler(source)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject
+ .hasErrorContaining("foo.bar.FooModule is missing an @InstallIn annotation")
+ .onSource(source)
+ .onLine(6);
+ });
}
@Test
public void testNoErrorOnDaggerGeneratedModules() {
- JavaFileObject source =
- JavaFileObjects.forSourceString(
- "foo.bar",
- LINES.join(
- "package foo.bar;",
- "",
- GeneratedImport.IMPORT_GENERATED_ANNOTATION,
- "import dagger.Module;",
- "",
- "@Module",
- "@Generated(value = \"something\")", // Error: Isn't Dagger-generated but missing
- // InstallIn
- "final class FooModule {}",
- "",
- "@Module",
- "@Generated(value = \"dagger\")", // No error because the module is dagger generated
- "final class BarModule {}"));
+ Source source =
+ HiltCompilerTests.javaSource(
+ "foo.bar.BarModule",
+ "package foo.bar;",
+ "",
+ GeneratedImport.IMPORT_GENERATED_ANNOTATION,
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "@Generated(value = \"something\")", // Error: Isn't Dagger-generated but missing
+ // InstallIn
+ "final class FooModule {}",
+ "",
+ "@Module",
+ "@Generated(value = \"dagger\")", // No error because the module is dagger generated
+ "final class BarModule {}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("foo.bar.FooModule is missing an @InstallIn annotation")
- .inFile(source)
- .onLine(8);
+ HiltCompilerTests.hiltCompiler(source)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("foo.bar.FooModule is missing an @InstallIn annotation")
+ .onSource(source)
+ .onLine(8);
+ });
}
@Test
public void testModuleWithOnlyParamConstructor_fails() {
- JavaFileObject source = JavaFileObjects.forSourceString("foo.bar", LINES.join(
- "package foo.bar;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@Module",
- "@InstallIn(SingletonComponent.class)",
- "final class FooModule {",
- " FooModule(String arg) {}",
- "",
- " @Provides",
- " String provideString() {",
- " return \"\";",
- " }",
- "}"));
+ Source source =
+ HiltCompilerTests.javaSource(
+ "foo.bar.FooModule",
+ "package foo.bar;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "",
+ "@Module",
+ "@InstallIn(SingletonComponent.class)",
+ "final class FooModule {",
+ " FooModule(String arg) {}",
+ "",
+ " @Provides",
+ " String provideString() {",
+ " return \"\";",
+ " }",
+ "}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Modules that need to be instantiated by Hilt must have a visible, empty constructor.");
+ HiltCompilerTests.hiltCompiler(source)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "Modules that need to be instantiated by Hilt must have a visible, empty"
+ + " constructor.");
+ });
}
@Test
public void testInnerModule() {
- JavaFileObject source = JavaFileObjects.forSourceString("foo.bar", LINES.join(
- "package foo.bar;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "final class Outer {",
- " @Module",
- " @InstallIn(SingletonComponent.class)",
- " final class InnerModule {}",
- "}"));
+ Source source =
+ HiltCompilerTests.javaSource(
+ "foo.bar.Outer",
+ "package foo.bar;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "",
+ "final class Outer {",
+ " @Module",
+ " @InstallIn(SingletonComponent.class)",
+ " final class InnerModule {}",
+ "}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Nested @InstallIn modules must be static unless they are directly nested within a "
- + "test. Found: foo.bar.Outer.InnerModule");
+ HiltCompilerTests.hiltCompiler(source)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "Nested @InstallIn modules must be static unless they are directly nested within"
+ + " a test. Found: foo.bar.Outer.InnerModule");
+ });
}
@Test
public void testInnerModuleInTest() {
- JavaFileObject source = JavaFileObjects.forSourceString("foo.bar", LINES.join(
- "package foo.bar;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "",
- "@HiltAndroidTest",
- "final class Outer {",
- " static class Nested {",
- " @Module",
- " @InstallIn(SingletonComponent.class)",
- " final class InnerModule {}",
- " }",
- "}"));
+ Source source =
+ HiltCompilerTests.javaSource(
+ "foo.bar.Outer",
+ "package foo.bar;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "import dagger.hilt.android.testing.HiltAndroidTest;",
+ "",
+ "@HiltAndroidTest",
+ "final class Outer {",
+ " static class Nested {",
+ " @Module",
+ " @InstallIn(SingletonComponent.class)",
+ " final class InnerModule {}",
+ " }",
+ "}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Nested @InstallIn modules must be static unless they are directly nested within a "
- + "test. Found: foo.bar.Outer.Nested.InnerModule");
+ HiltCompilerTests.hiltCompiler(source)
+ .compile(
+ subject -> {
+ subject.compilationDidFail();
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "Nested @InstallIn modules must be static unless they are directly nested within"
+ + " a test. Found: foo.bar.Outer.Nested.InnerModule");
+ });
}
@Test
public void testInnerModuleInTest_succeeds() {
- JavaFileObject source = JavaFileObjects.forSourceString("foo.bar", LINES.join(
- "package foo.bar;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "",
- "@HiltAndroidTest",
- "final class Outer {",
- " @Module",
- " @InstallIn(SingletonComponent.class)",
- " final class InnerModule {}",
- "}"));
+ Source source =
+ HiltCompilerTests.javaSource(
+ "foo.bar.Outer",
+ "package foo.bar;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "import dagger.hilt.android.testing.HiltAndroidTest;",
+ "",
+ "@HiltAndroidTest",
+ "public final class Outer {",
+ " @Module",
+ " @InstallIn(SingletonComponent.class)",
+ " static final class InnerModule {}",
+ "}");
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).succeeded();
+ // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
+ HiltCompilerTests.compileWithKapt(
+ ImmutableList.of(source),
+ tempFolderRule,
+ result -> assertThat(result.getSuccess()).isTrue());
}
}
diff --git a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
index 180bba1..9ddf52a 100644
--- a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
@@ -32,12 +32,13 @@
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/testing:hilt_android_test",
"//java/dagger/hilt/android/components",
+ "@androidsdk//:platforms/android-32/android.jar",
],
deps = [
- "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
+ "//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//javatests/dagger/hilt/processor/internal:generated_import",
- "//third_party/java/compile_testing",
- "//third_party/java/guava/base",
+ "//third_party/java/guava/collect",
"//third_party/java/junit",
"//third_party/java/truth",
],
diff --git a/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java b/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java
index f04dc76..0654e34 100644
--- a/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/aliasof/AliasOfProcessorTest.java
@@ -19,8 +19,10 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
+import androidx.room.compiler.processing.util.Source;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,8 +75,6 @@
.compile(root, defineComponent, scope);
assertThat(compilation).failed();
- // One extra error for the missing Hilt_MyApp reference
- assertThat(compilation).hadErrorCount(2);
assertThat(compilation)
.hadErrorContaining(
"@DefineComponent test.ChildComponent, references invalid scope(s) annotated with"
@@ -83,6 +83,30 @@
}
@Test
+ public void fails_alisOfOnNonScope() {
+ Source scope =
+ HiltCompilerTests.javaSource(
+ "test.AliasScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "import javax.inject.Singleton;",
+ "import dagger.hilt.migration.AliasOf;",
+ "",
+ "@AliasOf(Singleton.class)",
+ "public @interface AliasScope{}");
+
+ HiltCompilerTests.hiltCompiler(scope)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "AliasOf should only be used on scopes. However, it was found "
+ + "annotating test.AliasScope");
+ });
+ }
+
+ @Test
public void fails_conflictingAliasScope() {
JavaFileObject scope =
JavaFileObjects.forSourceLines(
diff --git a/javatests/dagger/hilt/processor/internal/aliasof/BUILD b/javatests/dagger/hilt/processor/internal/aliasof/BUILD
index 4dcd003..bc7874f 100644
--- a/javatests/dagger/hilt/processor/internal/aliasof/BUILD
+++ b/javatests/dagger/hilt/processor/internal/aliasof/BUILD
@@ -33,8 +33,8 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/compile_testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/definecomponent/BUILD b/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
index 9de94ba..ee8e066 100644
--- a/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
+++ b/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
@@ -15,28 +15,23 @@
# Description:
# Tests for Hilt's DefineComponentProcessor
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
+load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
package(default_visibility = ["//:src"])
-GenJavaTests(
- name = "hilt_processor_tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//:dagger_with_compiler",
+compiler_test(
+ name = "DefineComponentProcessorTest",
+ srcs = ["DefineComponentProcessorTest.java"],
+ compiler_deps = [
"//java/dagger/hilt:entry_point",
"//java/dagger/hilt:install_in",
"//java/dagger/hilt/android/components",
"//java/dagger/hilt/android/qualifiers",
- "//java/dagger/hilt/processor/internal/definecomponent:define_components",
- "//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
- "//javatests/dagger/hilt/processor/internal:generated_import",
- "//third_party/java/compile_testing",
+ ],
+ deps = [
+ "//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java b/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
index 373061c..33510ab 100644
--- a/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
@@ -16,13 +16,8 @@
package dagger.hilt.processor.internal.definecomponent;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
+import androidx.room.compiler.processing.util.Source;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -32,8 +27,8 @@
@Test
public void testDefineComponentOutput() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -46,8 +41,8 @@
" static int staticMethod() { return staticField; }",
"}");
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
+ Source builder =
+ HiltCompilerTests.javaSource(
"test.FooComponentBuilder",
"package test;",
"",
@@ -61,42 +56,57 @@
" FooComponent create();",
"}");
- JavaFileObject componentOutput =
- JavaFileObjects.forSourceLines(
+ Source componentOutput =
+ HiltCompilerTests.javaSource(
"dagger.hilt.processor.internal.definecomponent.codegen._test_FooComponent",
"package dagger.hilt.processor.internal.definecomponent.codegen;",
"",
- "@DefineComponentClasses(component = \"test.FooComponent\")",
- "@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
- "public class _test_FooComponent {}");
+ "import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
+ "import javax.annotation.processing.Generated;",
+ "",
+ "/**",
+ " * This class should only be referenced by generated code! This class aggregates "
+ + "information across multiple compilations.",
+ " */",
+ "@DefineComponentClasses(",
+ " component = \"test.FooComponent\"",
+ ")",
+ "@Generated(\"dagger.hilt.processor.internal.definecomponent.DefineComponentProcessingStep\")",
+ "public class _test_FooComponent {",
+ "}");
- JavaFileObject builderOutput =
- JavaFileObjects.forSourceLines(
+ Source builderOutput =
+ HiltCompilerTests.javaSource(
"dagger.hilt.processor.internal.definecomponent.codegen._test_FooComponentBuilder",
"package dagger.hilt.processor.internal.definecomponent.codegen;",
"",
- "@DefineComponentClasses(builder = \"test.FooComponentBuilder\")",
- "@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
- "public class _test_FooComponentBuilder {}");
+ "import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
+ "import javax.annotation.processing.Generated;",
+ "",
+ "/**",
+ " * This class should only be referenced by generated code! This class aggregates "
+ + "information across multiple compilations.",
+ " */",
+ "@DefineComponentClasses(",
+ " builder = \"test.FooComponentBuilder\"",
+ ")",
+ "@Generated(\"dagger.hilt.processor.internal.definecomponent.DefineComponentProcessingStep\")",
+ "public class _test_FooComponentBuilder {",
+ "}");
- Compilation compilation = compiler().compile(component, builder);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile(sourceName(componentOutput))
- .containsElementsIn(componentOutput);
- assertThat(compilation)
- .generatedSourceFile(sourceName(builderOutput))
- .containsElementsIn(builderOutput);
- }
-
- private static String sourceName(JavaFileObject fileObject) {
- return fileObject.getName().replace(".java", "").replace('.', '/');
+ HiltCompilerTests.hiltCompiler(component, builder)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(0);
+ subject.generatedSource(componentOutput);
+ subject.generatedSource(builderOutput);
+ });
}
@Test
public void testDefineComponentClass_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -106,18 +116,19 @@
"@DefineComponent( parent = SingletonComponent.class )",
"abstract class FooComponent {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent is only allowed on interfaces. Found: test.FooComponent");
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent is only allowed on interfaces. Found: test.FooComponent");
+ });
}
@Test
public void testDefineComponentWithTypeParameters_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -127,17 +138,19 @@
"@DefineComponent( parent = SingletonComponent.class )",
"interface FooComponent<T> {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("@DefineComponent test.FooComponent<T>, cannot have type parameters.");
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent test.FooComponent<T>, cannot have type parameters.");
+ });
}
@Test
public void testDefineComponentWithInvalidComponent_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -147,20 +160,21 @@
"@DefineComponent( parent = ApplicationContext.class )",
"interface FooComponent {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent test.FooComponent, references a type not annotated with "
- + "@DefineComponent: dagger.hilt.android.qualifiers.ApplicationContext")
- .inFile(component);
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent test.FooComponent, references a type not annotated with "
+ + "@DefineComponent: dagger.hilt.android.qualifiers.ApplicationContext")
+ .onSource(component);
+ });
}
@Test
public void testDefineComponentExtendsInterface_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -172,19 +186,20 @@
"@DefineComponent( parent = SingletonComponent.class )",
"interface FooComponent extends Foo {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent test.FooComponent, cannot extend a super class or interface."
- + " Found: test.Foo");
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent test.FooComponent, cannot extend a super class or interface."
+ + " Found: [test.Foo]");
+ });
}
@Test
public void testDefineComponentNonStaticMethod_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -196,19 +211,20 @@
" int nonStaticMethod();",
"}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent test.FooComponent, cannot have non-static methods. "
- + "Found: [nonStaticMethod()]");
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent test.FooComponent, cannot have non-static methods. "
+ + "Found: [nonStaticMethod()]");
+ });
}
@Test
public void testDefineComponentDependencyCycle_fails() {
- JavaFileObject component1 =
- JavaFileObjects.forSourceLines(
+ Source component1 =
+ HiltCompilerTests.javaSource(
"test.Component1",
"package test;",
"",
@@ -217,8 +233,8 @@
"@DefineComponent(parent = Component2.class)",
"interface Component1 {}");
- JavaFileObject component2 =
- JavaFileObjects.forSourceLines(
+ Source component2 =
+ HiltCompilerTests.javaSource(
"test.Component2",
"package test;",
"",
@@ -227,21 +243,21 @@
"@DefineComponent(parent = Component1.class)",
"interface Component2 {}");
- Compilation compilation = compiler().compile(component1, component2);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent cycle: test.Component1 -> test.Component2 -> test.Component1");
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent cycle: test.Component2 -> test.Component1 -> test.Component2");
+ HiltCompilerTests.hiltCompiler(component1, component2)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(2);
+ subject.hasErrorContaining(
+ "@DefineComponent cycle: test.Component1 -> test.Component2 -> test.Component1");
+ subject.hasErrorContaining(
+ "@DefineComponent cycle: test.Component2 -> test.Component1 -> test.Component2");
+ });
}
@Test
public void testDefineComponentNoParent_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -249,15 +265,20 @@
"",
"@DefineComponent",
"interface FooComponent {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation)
- .hadErrorContaining("@DefineComponent test.FooComponent is missing a parent declaration.");
+
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent test.FooComponent is missing a parent declaration.");
+ });
}
@Test
public void testDefineComponentBuilderClass_fails() {
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
+ Source builder =
+ HiltCompilerTests.javaSource(
"test.FooComponentBuilder",
"package test;",
"",
@@ -266,19 +287,20 @@
"@DefineComponent.Builder",
"abstract class FooComponentBuilder {}");
- Compilation compilation = compiler().compile(builder);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent.Builder is only allowed on interfaces. "
- + "Found: test.FooComponentBuilder");
+ HiltCompilerTests.hiltCompiler(builder)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent.Builder is only allowed on interfaces. "
+ + "Found: test.FooComponentBuilder");
+ });
}
@Test
public void testDefineComponentBuilderWithTypeParameters_fails() {
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
+ Source builder =
+ HiltCompilerTests.javaSource(
"test.FooComponentBuilder",
"package test;",
"",
@@ -287,19 +309,20 @@
"@DefineComponent.Builder",
"interface FooComponentBuilder<T> {}");
- Compilation compilation = compiler().compile(builder);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent.Builder test.FooComponentBuilder<T>, cannot have type "
- + "parameters.");
+ HiltCompilerTests.hiltCompiler(builder)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent.Builder test.FooComponentBuilder<T>, cannot have type "
+ + "parameters.");
+ });
}
@Test
public void testDefineComponentBuilderExtendsInterface_fails() {
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
+ Source builder =
+ HiltCompilerTests.javaSource(
"test.FooComponentBuilder",
"package test;",
"",
@@ -310,19 +333,20 @@
"@DefineComponent.Builder",
"interface FooComponentBuilder extends Foo {}");
- Compilation compilation = compiler().compile(builder);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent.Builder test.FooComponentBuilder, cannot extend a super class "
- + "or interface. Found: test.Foo");
+ HiltCompilerTests.hiltCompiler(builder)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent.Builder test.FooComponentBuilder, cannot extend a super class "
+ + "or interface. Found: [test.Foo]");
+ });
}
@Test
public void testDefineComponentBuilderNoBuilderMethod_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -331,19 +355,20 @@
"@DefineComponent.Builder",
"interface FooComponentBuilder {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent.Builder test.FooComponentBuilder, must have exactly 1 build "
- + "method that takes no parameters. Found: []");
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent.Builder test.FooComponentBuilder, must have exactly 1 build "
+ + "method that takes no parameters. Found: []");
+ });
}
@Test
public void testDefineComponentBuilderPrimitiveReturnType_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -354,19 +379,20 @@
" int nonStaticMethod();",
"}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent.Builder method, test.FooComponentBuilder#nonStaticMethod(), "
- + "must return a @DefineComponent type. Found: int");
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent.Builder method, test.FooComponentBuilder#nonStaticMethod(), "
+ + "must return a @DefineComponent type. Found: int");
+ });
}
@Test
public void testDefineComponentBuilderWrongReturnType_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ HiltCompilerTests.javaSource(
"test.FooComponent",
"package test;",
"",
@@ -379,16 +405,13 @@
" Foo build();",
"}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@DefineComponent.Builder method, test.FooComponentBuilder#build(), must return "
- + "a @DefineComponent type. Found: test.Foo");
- }
-
- private static Compiler compiler() {
- return javac().withProcessors(new DefineComponentProcessor());
+ HiltCompilerTests.hiltCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@DefineComponent.Builder method, test.FooComponentBuilder#build(), must return "
+ + "a @DefineComponent type. Found: test.Foo");
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
index 11252a6..2e88642 100644
--- a/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ b/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
@@ -28,12 +28,15 @@
"//:dagger_with_compiler",
"//third_party/java/jsr250_annotations",
"//java/dagger/hilt:entry_point",
+ "//java/dagger/hilt:install_in",
+ "//java/dagger/hilt/android/components",
],
deps = [
+ "//java/dagger/hilt/android/testing/compile",
"//java/dagger/hilt/processor/internal/disableinstallincheck:processor_lib",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java b/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java
index 8ea715d..0031736 100644
--- a/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java
+++ b/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java
@@ -16,12 +16,9 @@
package dagger.hilt.processor.internal.disableinstallincheck;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
+import androidx.room.compiler.processing.util.Source;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import dagger.testing.compile.CompilerTests;
-import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -32,38 +29,49 @@
@Test
public void testIllegalCombinationInstallIn() {
- JavaFileObject source =
- JavaFileObjects.forSourceLines(
- "foo.bar",
+ Source module =
+ CompilerTests.javaSource(
+ "foo.bar.NotModule",
"package foo.bar;",
"",
"import dagger.hilt.migration.DisableInstallInCheck;",
- "import dagger.hilt.EntryPoint;",
"",
"@DisableInstallInCheck",
- "final class NotModule {}",
+ "final class NotModule {}");
+
+ Source entryPoint =
+ CompilerTests.javaSource(
+ "foo.bar.FooEntryPoint",
+ "package foo.bar;",
+ "",
+ "import dagger.hilt.components.SingletonComponent;",
+ "import dagger.hilt.migration.DisableInstallInCheck;",
+ "import dagger.hilt.EntryPoint;",
+ "import dagger.hilt.InstallIn;",
"",
"@DisableInstallInCheck",
"@EntryPoint",
+ "@InstallIn(SingletonComponent.class)",
"interface FooEntryPoint {}");
- Compilation compilation =
- CompilerTests.compiler()
- .withProcessors(new DisableInstallInCheckProcessor())
- .compile(source);
-
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@DisableInstallInCheck should only be used on modules. However, it was found"
- + " annotating foo.bar.NotModule")
- .inFile(source)
- .onLine(7);
- assertThat(compilation)
- .hadErrorContaining(
- "@DisableInstallInCheck should only be used on modules. However, it was found"
- + " annotating foo.bar.FooEntryPoint")
- .inFile(source)
- .onLine(11);
+ HiltCompilerTests.hiltCompiler(module, entryPoint)
+ .withAdditionalJavacProcessors(new DisableInstallInCheckProcessor())
+ .withAdditionalKspProcessors(new KspDisableInstallInCheckProcessor.Provider())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(2);
+ subject
+ .hasErrorContaining(
+ "@DisableInstallInCheck should only be used on modules. However, it was found"
+ + " annotating foo.bar.NotModule")
+ .onSource(module)
+ .onLine(6);
+ subject
+ .hasErrorContaining(
+ "@DisableInstallInCheck should only be used on modules. However, it was found"
+ + " annotating foo.bar.FooEntryPoint")
+ .onSource(entryPoint)
+ .onLine(11);
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
index a815ecd..ad919f5 100644
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
@@ -15,24 +15,25 @@
# Description:
# Tests the functionality of GeneratesRootInputProcessor.
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
+load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
package(default_visibility = ["//:src"])
-GenJavaTests(
+compiler_test(
name = "GeneratesRootInputProcessorTest",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//:dagger_with_compiler",
+ srcs = ["GeneratesRootInputProcessorTest.java"],
+ compiler_deps = [
"//java/dagger/hilt:generates_root_input",
+ "@androidsdk//:platforms/android-32/android.jar",
+ "@maven//:androidx_annotation_annotation",
+ ],
+ deps = [
+ "//java/dagger/hilt:generates_root_input",
+ "//java/dagger/hilt/android/testing/compile",
"//java/dagger/hilt/processor/internal:base_processor",
"//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "//third_party/java/auto:common",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/javapoet",
"//third_party/java/junit",
"//third_party/java/truth",
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java b/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
index 48818d4..195b5fe 100644
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
@@ -17,24 +17,22 @@
package dagger.hilt.processor.internal.generatesrootinput;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-import com.google.auto.common.MoreElements;
+import androidx.room.compiler.processing.XElement;
+import androidx.room.compiler.processing.XFiler.Mode;
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.XRoundEnv;
+import androidx.room.compiler.processing.util.Source;
import com.google.common.truth.Correspondence;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.BaseProcessor;
+import dagger.hilt.GeneratesRootInput;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
+import dagger.hilt.processor.internal.BaseProcessingStep;
+import dagger.internal.codegen.xprocessing.XElements;
import java.util.ArrayList;
import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.lang.model.element.Element;
-import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -45,55 +43,55 @@
private static final int GENERATED_CLASSES = 5;
private static final ClassName TEST_ANNOTATION = ClassName.get("test", "TestAnnotation");
- private final List<Element> elementsToWaitFor = new ArrayList<>();
+ private final List<XElement> elementsToWaitFor = new ArrayList<>();
private int generatedClasses = 0;
- @SupportedAnnotationTypes("*")
- public final class TestAnnotationProcessor extends BaseProcessor {
+ public final class TestAnnotationStep extends BaseProcessingStep {
private GeneratesRootInputs generatesRootInputs;
- @Override
- public synchronized void init(ProcessingEnvironment processingEnv) {
- super.init(processingEnv);
- generatesRootInputs = new GeneratesRootInputs(processingEnv);
+ public TestAnnotationStep(XProcessingEnv env) {
+ super(env);
+ generatesRootInputs = new GeneratesRootInputs(env);
}
@Override
- protected void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
+ public void postProcess(XProcessingEnv processingEnv, XRoundEnv round) {
if (generatedClasses > 0) {
- elementsToWaitFor.addAll(generatesRootInputs.getElementsToWaitFor(roundEnv));
+ elementsToWaitFor.addAll(generatesRootInputs.getElementsToWaitFor(round));
}
if (generatedClasses < GENERATED_CLASSES) {
TypeSpec typeSpec =
TypeSpec.classBuilder("Foo" + generatedClasses++)
.addAnnotation(TEST_ANNOTATION)
.build();
- JavaFile.builder("foo", typeSpec).build().writeTo(processingEnv.getFiler());
+ processingEnv.getFiler().write(JavaFile.builder("foo", typeSpec).build(), Mode.Isolating);
}
}
}
@Test
public void succeeds_ComponentProcessorWaitsForAnnotationsWithGeneratesRootInput() {
- JavaFileObject testAnnotation =
- JavaFileObjects.forSourceLines(
+ Source testAnnotation =
+ HiltCompilerTests.javaSource(
"test.TestAnnotation",
"package test;",
- "@dagger.hilt.GeneratesRootInput",
+ "@" + GeneratesRootInput.class.getCanonicalName(),
"public @interface TestAnnotation {}");
- Compilation compilation =
- javac()
- .withProcessors(new TestAnnotationProcessor(), new GeneratesRootInputProcessor())
- .compile(testAnnotation);
-
- assertThat(compilation).succeeded();
- assertThat(elementsToWaitFor)
- .comparingElementsUsing(
- Correspondence.<Element, String>transforming(
- element -> MoreElements.asType(element).getQualifiedName().toString(),
- "has qualified name of"))
- .containsExactly("foo.Foo0", "foo.Foo1", "foo.Foo2", "foo.Foo3", "foo.Foo4")
- .inOrder();
+ HiltCompilerTests.hiltCompiler(testAnnotation)
+ .withProcessingSteps(TestAnnotationStep::new)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(0);
+ assertThat(elementsToWaitFor)
+ .comparingElementsUsing(
+ Correspondence.<XElement, String>transforming(
+ element -> XElements.asTypeElement(element).getQualifiedName(),
+ "has qualified name of"))
+ .containsExactly("foo.Foo0", "foo.Foo1", "foo.Foo2", "foo.Foo3", "foo.Foo4")
+ .inOrder();
+ elementsToWaitFor.clear();
+ generatedClasses = 0;
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/originatingelement/BUILD b/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
index 96fdab6..75f56ff 100644
--- a/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
+++ b/javatests/dagger/hilt/processor/internal/originatingelement/BUILD
@@ -29,6 +29,7 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/compile_testing",
"//third_party/java/junit",
"//third_party/java/truth",
diff --git a/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java b/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java
index 5dc7a11..813fbef 100644
--- a/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessorTest.java
@@ -16,12 +16,10 @@
package dagger.hilt.processor.internal.originatingelement;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.hiltCompiler;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
+import androidx.room.compiler.processing.util.Source;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -31,14 +29,10 @@
@Test
public void originatingElementOnInnerClass_fails() {
- JavaFileObject outer1 =
- JavaFileObjects.forSourceLines(
- "test.Outer1",
- "package test;",
- "",
- "class Outer1 {}");
- JavaFileObject outer2 =
- JavaFileObjects.forSourceLines(
+ Source outer1 =
+ HiltCompilerTests.javaSource("test.Outer1", "package test;", "", "class Outer1 {}");
+ Source outer2 =
+ HiltCompilerTests.javaSource(
"test.Outer2",
"package test;",
"",
@@ -48,26 +42,23 @@
" @OriginatingElement(topLevelClass = Outer1.class)",
" static class Inner {}",
"}");
- Compilation compilation = compiler().compile(outer1, outer2);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "@OriginatingElement should only be used to annotate top-level types, but found: "
- + "test.Outer2.Inner");
+ hiltCompiler(outer1, outer2)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@OriginatingElement should only be used to annotate top-level types, but found: "
+ + "test.Outer2.Inner");
+ });
}
@Test
public void originatingElementValueWithInnerClass_fails() {
- JavaFileObject outer1 =
- JavaFileObjects.forSourceLines(
- "test.Outer1",
- "package test;",
- "",
- "class Outer1 {",
- " static class Inner {}",
- "}");
- JavaFileObject outer2 =
- JavaFileObjects.forSourceLines(
+ Source outer1 =
+ HiltCompilerTests.javaSource(
+ "test.Outer1", "package test;", "", "class Outer1 {", " static class Inner {}", "}");
+ Source outer2 =
+ HiltCompilerTests.javaSource(
"test.Outer2",
"package test;",
"",
@@ -75,11 +66,13 @@
"",
"@OriginatingElement(topLevelClass = Outer1.Inner.class)",
"class Outer2 {}");
- Compilation compilation = compiler().compile(outer1, outer2);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- "OriginatingElement.topLevelClass value should be a top-level class, but found: "
- + "test.Outer1.Inner");
+ hiltCompiler(outer1, outer2)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "OriginatingElement.topLevelClass value should be a top-level class, but found: "
+ + "test.Outer1.Inner");
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/root/BUILD b/javatests/dagger/hilt/processor/internal/root/BUILD
index ab85f60..0da11f1 100644
--- a/javatests/dagger/hilt/processor/internal/root/BUILD
+++ b/javatests/dagger/hilt/processor/internal/root/BUILD
@@ -42,7 +42,7 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/guava/collect",
"//third_party/java/junit",
"//third_party/java/truth",
@@ -73,7 +73,7 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/guava/collect",
"//third_party/java/junit",
"//third_party/java/truth",
@@ -94,10 +94,9 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
+ "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//third_party/java/guava/collect",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java b/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
index e4aa5ab..f7e9b3d 100644
--- a/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
@@ -16,16 +16,20 @@
package dagger.hilt.processor.internal.root;
-import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compileWithKapt;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.javaSource;
+import androidx.room.compiler.processing.util.DiagnosticMessage;
+import androidx.room.compiler.processing.util.Source;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.android.testing.compile.HiltCompilerTests;
-import javax.tools.JavaFileObject;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import javax.tools.Diagnostic.Kind;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -38,24 +42,24 @@
return ImmutableList.copyOf(new Object[][] {{true}, {false}});
}
+ @Rule public TemporaryFolder tempFolderRule = new TemporaryFolder();
+
private final boolean disableCrossCompilationRootValidation;
public MyAppPreviousCompilationTest(boolean disableCrossCompilationRootValidation) {
this.disableCrossCompilationRootValidation = disableCrossCompilationRootValidation;
}
- private Compiler compiler() {
- return HiltCompilerTests.compiler()
- .withOptions(
- String.format(
- "-Adagger.hilt.disableCrossCompilationRootValidation=%s",
- disableCrossCompilationRootValidation));
+ private ImmutableMap<String, String> processorOptions() {
+ return ImmutableMap.of(
+ "dagger.hilt.disableCrossCompilationRootValidation",
+ Boolean.toString(disableCrossCompilationRootValidation));
}
@Test
public void testRootTest() {
- JavaFileObject testRoot =
- JavaFileObjects.forSourceLines(
+ Source testRoot =
+ javaSource(
"test.TestRoot",
"package test;",
"",
@@ -64,15 +68,19 @@
"@HiltAndroidTest",
"public class TestRoot {}");
+ // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
// This test case should succeed independent of disableCrossCompilationRootValidation.
- Compilation compilation = compiler().compile(testRoot);
- assertThat(compilation).succeeded();
+ compileWithKapt(
+ ImmutableList.of(testRoot),
+ processorOptions(),
+ tempFolderRule,
+ result -> assertThat(result.getSuccess()).isTrue());
}
@Test
public void appRootTest() {
- JavaFileObject appRoot =
- JavaFileObjects.forSourceLines(
+ Source appRoot =
+ javaSource(
"test.AppRoot",
"package test;",
"",
@@ -82,19 +90,25 @@
"@HiltAndroidApp(Application.class)",
"public class AppRoot extends Hilt_AppRoot {}");
- Compilation compilation = compiler().compile(appRoot);
- if (disableCrossCompilationRootValidation) {
- assertThat(compilation).succeeded();
- } else {
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot process new app roots when there are app roots from a "
- + "previous compilation unit:"
- + "\n App roots in previous compilation unit: "
- + "dagger.hilt.processor.internal.root.MyAppPreviousCompilation.MyApp"
- + "\n App roots in this compilation unit: test.AppRoot");
- }
+ // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
+ compileWithKapt(
+ ImmutableList.of(appRoot),
+ processorOptions(),
+ tempFolderRule,
+ result -> {
+ if (disableCrossCompilationRootValidation) {
+ assertThat(result.getSuccess()).isTrue();
+ } else {
+ List<DiagnosticMessage> errors = result.getDiagnostics().get(Kind.ERROR);
+ assertThat(errors).hasSize(1);
+ assertThat(errors.get(0).getMsg())
+ .contains(
+ "Cannot process new app roots when there are app roots from a "
+ + "previous compilation unit:"
+ + "\n App roots in previous compilation unit: "
+ + "dagger.hilt.processor.internal.root.MyAppPreviousCompilation.MyApp"
+ + "\n App roots in this compilation unit: test.AppRoot");
+ }
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java b/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java
index 82251bd..795a4ea 100644
--- a/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/MyTestPreviousCompilationTest.java
@@ -16,16 +16,20 @@
package dagger.hilt.processor.internal.root;
-import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.compileWithKapt;
+import static dagger.hilt.android.testing.compile.HiltCompilerTests.javaSource;
+import androidx.room.compiler.processing.util.DiagnosticMessage;
+import androidx.room.compiler.processing.util.Source;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.android.testing.compile.HiltCompilerTests;
-import javax.tools.JavaFileObject;
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import javax.tools.Diagnostic.Kind;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -38,24 +42,24 @@
return ImmutableList.copyOf(new Object[][] {{true}, {false}});
}
+ @Rule public TemporaryFolder tempFolderRule = new TemporaryFolder();
+
private final boolean disableCrossCompilationRootValidation;
public MyTestPreviousCompilationTest(boolean disableCrossCompilationRootValidation) {
this.disableCrossCompilationRootValidation = disableCrossCompilationRootValidation;
}
- private Compiler compiler() {
- return HiltCompilerTests.compiler()
- .withOptions(
- String.format(
- "-Adagger.hilt.disableCrossCompilationRootValidation=%s",
- disableCrossCompilationRootValidation));
+ private ImmutableMap<String, String> processorOptions() {
+ return ImmutableMap.of(
+ "dagger.hilt.disableCrossCompilationRootValidation",
+ Boolean.toString(disableCrossCompilationRootValidation));
}
@Test
public void testRootTest() {
- JavaFileObject testRoot =
- JavaFileObjects.forSourceLines(
+ Source testRoot =
+ javaSource(
"test.TestRoot",
"package test;",
"",
@@ -64,25 +68,32 @@
"@HiltAndroidTest",
"public class TestRoot {}");
- Compilation compilation = compiler().compile(testRoot);
- if (disableCrossCompilationRootValidation) {
- assertThat(compilation).succeeded();
- } else {
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot process new roots when there are test roots from a previous compilation unit:"
- + "\n Test roots from previous compilation unit: "
- + "dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest"
- + "\n All roots from this compilation unit: test.TestRoot");
- }
+ // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
+ compileWithKapt(
+ ImmutableList.of(testRoot),
+ processorOptions(),
+ tempFolderRule,
+ result -> {
+ if (disableCrossCompilationRootValidation) {
+ assertThat(result.getSuccess()).isTrue();
+ } else {
+ List<DiagnosticMessage> errors = result.getDiagnostics().get(Kind.ERROR);
+ assertThat(errors).hasSize(1);
+ assertThat(errors.get(0).getMsg())
+ .contains(
+ "Cannot process new roots when there are test roots from a previous "
+ + "compilation unit:\n"
+ + " Test roots from previous compilation unit: "
+ + "dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest\n"
+ + " All roots from this compilation unit: test.TestRoot");
+ }
+ });
}
@Test
public void appRootTest() {
- JavaFileObject appRoot =
- JavaFileObjects.forSourceLines(
+ Source appRoot =
+ javaSource(
"test.AppRoot",
"package test;",
"",
@@ -92,18 +103,25 @@
"@HiltAndroidApp(Application.class)",
"public class AppRoot extends Hilt_AppRoot {}");
- Compilation compilation = compiler().compile(appRoot);
- if (disableCrossCompilationRootValidation) {
- assertThat(compilation).succeeded();
- } else {
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot process new roots when there are test roots from a previous compilation unit:"
- + "\n Test roots from previous compilation unit: "
- + "dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest"
- + "\n All roots from this compilation unit: test.AppRoot");
- }
+ // TODO(danysantiago): Add KSP test once b/288966076 is resolved.
+ compileWithKapt(
+ ImmutableList.of(appRoot),
+ processorOptions(),
+ tempFolderRule,
+ result -> {
+ if (disableCrossCompilationRootValidation) {
+ assertThat(result.getSuccess()).isTrue();
+ } else {
+ List<DiagnosticMessage> errors = result.getDiagnostics().get(Kind.ERROR);
+ assertThat(errors).hasSize(1);
+ assertThat(errors.get(0).getMsg())
+ .contains(
+ "Cannot process new roots when there are test roots from a previous "
+ + "compilation unit:\n"
+ + " Test roots from previous compilation unit: "
+ + "dagger.hilt.processor.internal.root.MyTestPreviousCompilation.MyTest\n"
+ + " All roots from this compilation unit: test.AppRoot");
+ }
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java b/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java
index c07ee53..4d634cb 100644
--- a/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/RootProcessorErrorsTest.java
@@ -16,15 +16,11 @@
package dagger.hilt.processor.internal.root;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-
+import androidx.room.compiler.processing.util.Source;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
+import com.google.common.collect.ImmutableMap;
import dagger.hilt.android.testing.compile.HiltCompilerTests;
-import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -44,18 +40,16 @@
this.disableCrossCompilationRootValidation = disableCrossCompilationRootValidation;
}
- private Compiler compiler() {
- return HiltCompilerTests.compiler()
- .withOptions(
- String.format(
- "-Adagger.hilt.disableCrossCompilationRootValidation=%s",
- disableCrossCompilationRootValidation));
+ private ImmutableMap<String, String> processorOptions() {
+ return ImmutableMap.of(
+ "dagger.hilt.disableCrossCompilationRootValidation",
+ Boolean.toString(disableCrossCompilationRootValidation));
}
@Test
public void multipleAppRootsTest() {
- JavaFileObject appRoot1 =
- JavaFileObjects.forSourceLines(
+ Source appRoot1 =
+ HiltCompilerTests.javaSource(
"test.AppRoot1",
"package test;",
"",
@@ -65,8 +59,8 @@
"@HiltAndroidApp(Application.class)",
"public class AppRoot1 extends Hilt_AppRoot1 {}");
- JavaFileObject appRoot2 =
- JavaFileObjects.forSourceLines(
+ Source appRoot2 =
+ HiltCompilerTests.javaSource(
"test.AppRoot2",
"package test;",
"",
@@ -76,20 +70,22 @@
"@HiltAndroidApp(Application.class)",
"public class AppRoot2 extends Hilt_AppRoot2 {}");
- // This test case should fail independent of disableCrossCompilationRootValidation.
- Compilation compilation = compiler().compile(appRoot1, appRoot2);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot process multiple app roots in the same compilation unit: "
- + "test.AppRoot1, test.AppRoot2");
+ HiltCompilerTests.hiltCompiler(appRoot1, appRoot2)
+ .withProcessorOptions(processorOptions())
+ .compile(
+ subject -> {
+ // This test case should fail independent of disableCrossCompilationRootValidation.
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "Cannot process multiple app roots in the same compilation unit: "
+ + "test.AppRoot1, test.AppRoot2");
+ });
}
@Test
public void appRootWithTestRootTest() {
- JavaFileObject appRoot =
- JavaFileObjects.forSourceLines(
+ Source appRoot =
+ HiltCompilerTests.javaSource(
"test.AppRoot",
"package test;",
"",
@@ -99,8 +95,8 @@
"@HiltAndroidApp(Application.class)",
"public class AppRoot extends Hilt_AppRoot {}");
- JavaFileObject testRoot =
- JavaFileObjects.forSourceLines(
+ Source testRoot =
+ HiltCompilerTests.javaSource(
"test.TestRoot",
"package test;",
"",
@@ -109,14 +105,16 @@
"@HiltAndroidTest",
"public class TestRoot {}");
- // This test case should fail independent of disableCrossCompilationRootValidation.
- Compilation compilation = compiler().compile(appRoot, testRoot);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Cannot process test roots and app roots in the same compilation unit:"
- + "\n App root in this compilation unit: test.AppRoot"
- + "\n Test roots in this compilation unit: test.TestRoot");
+ HiltCompilerTests.hiltCompiler(appRoot, testRoot)
+ .withProcessorOptions(processorOptions())
+ .compile(
+ subject -> {
+ // This test case should fail independent of disableCrossCompilationRootValidation.
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "Cannot process test roots and app roots in the same compilation unit:"
+ + "\n App root in this compilation unit: test.AppRoot"
+ + "\n Test roots in this compilation unit: test.TestRoot");
+ });
}
}
diff --git a/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD b/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
index 0436f99..50ffd2e 100644
--- a/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
+++ b/javatests/dagger/hilt/processor/internal/uninstallmodules/BUILD
@@ -32,9 +32,7 @@
],
deps = [
"//java/dagger/hilt/android/testing/compile",
- "//third_party/java/compile_testing",
"//third_party/java/junit",
- "//third_party/java/truth",
],
)
diff --git a/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java b/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java
index 04b5a24..de2c367 100644
--- a/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java
+++ b/javatests/dagger/hilt/processor/internal/uninstallmodules/UninstallModulesProcessorTest.java
@@ -16,11 +16,7 @@
package dagger.hilt.processor.internal.uninstallmodules;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.testing.compile.HiltCompilerTests.compiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
+import dagger.hilt.android.testing.compile.HiltCompilerTests;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -30,133 +26,125 @@
@Test
public void testInvalidModuleNoInstallIn_fails() {
- Compilation compilation =
- compiler()
- .compile(
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "import dagger.hilt.android.testing.UninstallModules;",
- "",
- "@UninstallModules(InvalidModule.class)",
- "@HiltAndroidTest",
- "public class MyTest {}"),
- JavaFileObjects.forSourceLines(
- "test.InvalidModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.migration.DisableInstallInCheck;",
- "",
- "@DisableInstallInCheck",
- "@Module",
- "public class InvalidModule {}"));
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@UninstallModules should only include modules annotated with both @Module and "
- + "@InstallIn, but found: [test.InvalidModule].");
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
+ "test.MyTest",
+ "package test;",
+ "",
+ "import dagger.hilt.android.testing.HiltAndroidTest;",
+ "import dagger.hilt.android.testing.UninstallModules;",
+ "",
+ "@UninstallModules(InvalidModule.class)",
+ "@HiltAndroidTest",
+ "public class MyTest {}"),
+ HiltCompilerTests.javaSource(
+ "test.InvalidModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.migration.DisableInstallInCheck;",
+ "",
+ "@DisableInstallInCheck",
+ "@Module",
+ "public class InvalidModule {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@UninstallModules should only include modules annotated with both @Module and "
+ + "@InstallIn, but found: [test.InvalidModule].");
+ });
}
@Test
public void testInvalidModuleNoModule_fails() {
- Compilation compilation =
- compiler()
- .compile(
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "import dagger.hilt.android.testing.UninstallModules;",
- "",
- "@UninstallModules(InvalidModule.class)",
- "@HiltAndroidTest",
- "public class MyTest {}"),
- JavaFileObjects.forSourceLines(
- "test.InvalidModule",
- "package test;",
- "",
- "public class InvalidModule {",
- "}"));
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@UninstallModules should only include modules annotated with both @Module and "
- + "@InstallIn, but found: [test.InvalidModule].");
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
+ "test.MyTest",
+ "package test;",
+ "",
+ "import dagger.hilt.android.testing.HiltAndroidTest;",
+ "import dagger.hilt.android.testing.UninstallModules;",
+ "",
+ "@UninstallModules(InvalidModule.class)",
+ "@HiltAndroidTest",
+ "public class MyTest {}"),
+ HiltCompilerTests.javaSource(
+ "test.InvalidModule", "package test;", "", "public class InvalidModule {", "}"))
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@UninstallModules should only include modules annotated with both @Module and "
+ + "@InstallIn, but found: [test.InvalidModule].");
+ });
}
@Test
public void testInvalidTest_fails() {
- Compilation compilation =
- compiler()
- .compile(
- JavaFileObjects.forSourceLines(
- "test.InvalidTest",
- "package test;",
- "",
- "import dagger.hilt.android.testing.UninstallModules;",
- "",
- "@UninstallModules(ValidModule.class)",
- "public class InvalidTest {}"),
- JavaFileObjects.forSourceLines(
- "test.ValidModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@Module",
- "@InstallIn(SingletonComponent.class)",
- "public class ValidModule {}"));
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@UninstallModules should only be used on test classes annotated with @HiltAndroidTest,"
- + " but found: test.InvalidTest");
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
+ "test.InvalidTest",
+ "package test;",
+ "",
+ "import dagger.hilt.android.testing.UninstallModules;",
+ "",
+ "@UninstallModules(ValidModule.class)",
+ "public class InvalidTest {}"),
+ HiltCompilerTests.javaSource(
+ "test.ValidModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "",
+ "@Module",
+ "@InstallIn(SingletonComponent.class)",
+ "public class ValidModule {}"))
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ "@UninstallModules should only be used on test classes annotated with"
+ + " @HiltAndroidTest, but found: test.InvalidTest");
+ });
}
@Test
public void testInvalidTestModule_fails() {
- Compilation compilation =
- compiler()
- .compile(
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "import dagger.hilt.android.testing.UninstallModules;",
- "",
- "@UninstallModules({",
- " MyTest.PkgPrivateInvalidModule.class,",
- " MyTest.PublicInvalidModule.class,",
- "})",
- "@HiltAndroidTest",
- "public class MyTest {",
- " @Module",
- " @InstallIn(SingletonComponent.class)",
- " interface PkgPrivateInvalidModule {}",
- "",
- " @Module",
- " @InstallIn(SingletonComponent.class)",
- " public interface PublicInvalidModule {}",
- "}"));
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- // TODO(bcorso): Consider unwrapping pkg-private modules before reporting the error.
- assertThat(compilation)
- .hadErrorContaining(
- "@UninstallModules should not contain test modules, but found: "
- + "[test.MyTest.PkgPrivateInvalidModule, test.MyTest.PublicInvalidModule]");
+ HiltCompilerTests.hiltCompiler(
+ HiltCompilerTests.javaSource(
+ "test.MyTest",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.hilt.InstallIn;",
+ "import dagger.hilt.components.SingletonComponent;",
+ "import dagger.hilt.android.testing.HiltAndroidTest;",
+ "import dagger.hilt.android.testing.UninstallModules;",
+ "",
+ "@UninstallModules({",
+ " MyTest.PkgPrivateInvalidModule.class,",
+ " MyTest.PublicInvalidModule.class,",
+ "})",
+ "@HiltAndroidTest",
+ "public class MyTest {",
+ " @Module",
+ " @InstallIn(SingletonComponent.class)",
+ " interface PkgPrivateInvalidModule {}",
+ "",
+ " @Module",
+ " @InstallIn(SingletonComponent.class)",
+ " public interface PublicInvalidModule {}",
+ "}"))
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ // TODO(bcorso): Consider unwrapping pkg-private modules before reporting the error.
+ subject.hasErrorContaining(
+ "@UninstallModules should not contain test modules, but found: "
+ + "[test.MyTest.PkgPrivateInvalidModule, test.MyTest.PublicInvalidModule]");
+ });
}
}
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java b/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
index dc5d109..9ac3e27 100644
--- a/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
+++ b/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
@@ -729,13 +729,16 @@
CompilerTests.daggerCompiler(foo)
.withProcessingOptions(compilerMode.processorOptions())
.compile(
- subject -> {
- subject.hasErrorCount(1);
- subject.hasErrorContaining(
- "A type with an @AssistedInject-annotated constructor cannot be scoped")
- .onSource(foo)
- .onLine(8);
- });
+ subject ->
+ // Don't assert on the number of errors as Foo_Factory_Impl can also be created
+ // and have errors from the missing Foo_Factory.
+ // TODO(erichang): don't generate the factory impls if there are errors with the
+ // assisted type
+ subject
+ .hasErrorContaining(
+ "A type with an @AssistedInject-annotated constructor cannot be scoped")
+ .onSource(foo)
+ .onLine(8));
}
@Test
diff --git a/javatests/dagger/internal/codegen/BUILD b/javatests/dagger/internal/codegen/BUILD
index 9a5b7b8..5984e53 100644
--- a/javatests/dagger/internal/codegen/BUILD
+++ b/javatests/dagger/internal/codegen/BUILD
@@ -96,6 +96,7 @@
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/model",
"//java/dagger/internal/codegen/validation",
"//java/dagger/internal/codegen/writing",
"//java/dagger/internal/codegen/xprocessing",
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
index 2fc88fc..7e81901 100644
--- a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
+++ b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
@@ -16,21 +16,17 @@
package dagger.internal.codegen;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.base.ComponentCreatorKind.FACTORY;
import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
import static java.util.stream.Collectors.joining;
import androidx.room.compiler.processing.util.Source;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
import dagger.internal.codegen.base.ComponentCreatorAnnotation;
import dagger.internal.codegen.base.ComponentCreatorKind;
import dagger.internal.codegen.binding.ErrorMessages;
import dagger.testing.compile.CompilerTests;
import java.util.Arrays;
import java.util.stream.Stream;
-import javax.tools.JavaFileObject;
/**
* Base class for component creator codegen tests that are written in terms of builders and
@@ -82,21 +78,8 @@
return CompilerTests.javaSource(fullyQualifiedName, process(lines));
}
- /**
- * Returns a Java file with the {@linkplain #process(String...)} processed} versions of the given
- * lines.
- */
- JavaFileObject preprocessedJavaFile(String fullyQualifiedName, String... lines) {
- return JavaFileObjects.forSourceString(fullyQualifiedName, process(lines));
- }
-
/** Returns a file builder for the current creator kind. */
JavaFileBuilder javaFileBuilder(String qualifiedName) {
return new JavaFileBuilder(qualifiedName).withSettings(compilerMode, creatorKind);
}
-
- /** Compiles the given files with the set compiler mode's javacopts. */
- Compilation compile(JavaFileObject... files) {
- return compilerWithOptions(compilerMode.javacopts()).compile(files);
- }
}
diff --git a/javatests/dagger/internal/codegen/ComponentProcessorTest.java b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
index 9183639..e7f9b8e 100644
--- a/javatests/dagger/internal/codegen/ComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
@@ -153,10 +153,12 @@
.put("dagger.privateMemberValidation", "WARNING")
.buildOrThrow())
.compile(
- subject -> {
- subject.hasErrorCount(1);
- subject.hasErrorContaining("Dagger does not support injection into private classes");
- });
+ subject ->
+ // Because it is just a warning until it is used, the factory still gets generated
+ // which has errors from referencing the private class, so there are extra errors.
+ // Hence we don't assert on the number of errors.
+ subject.hasErrorContaining(
+ "Dagger does not support injection into private classes"));
}
@Test
diff --git a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
index 1fd8338..7092047 100644
--- a/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
+++ b/javatests/dagger/internal/codegen/DaggerSuperficialValidationTest.java
@@ -28,6 +28,7 @@
import androidx.room.compiler.processing.XVariableElement;
import androidx.room.compiler.processing.util.Source;
import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import dagger.BindsInstance;
import dagger.Component;
@@ -39,93 +40,108 @@
import javax.inject.Singleton;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
-@RunWith(JUnit4.class)
+@RunWith(Parameterized.class)
public class DaggerSuperficialValidationTest {
+ enum SourceKind {
+ JAVA,
+ KOTLIN
+ }
+
+ @Parameters(name = "sourceKind={0}")
+ public static ImmutableList<Object[]> parameters() {
+ return ImmutableList.of(new Object[] {SourceKind.JAVA}, new Object[] {SourceKind.KOTLIN});
+ }
+
+ private final SourceKind sourceKind;
+
+ public DaggerSuperficialValidationTest(SourceKind sourceKind) {
+ this.sourceKind = sourceKind;
+ }
+
private static final Joiner NEW_LINES = Joiner.on("\n ");
@Test
public void missingReturnType() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"abstract class TestClass {",
" abstract MissingType blah();",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (METHOD): blah()",
- " => type (ERROR return type): %1$s"),
- isJavac ? "MissingType" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "abstract class TestClass {",
+ " abstract fun blah(): MissingType",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): blah()",
+ " => type (ERROR return type): %1$s"),
+ isJavac ? "MissingType" : "error.NonExistentClass"));
+ });
}
@Test
public void missingGenericReturnType() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"abstract class TestClass {",
" abstract MissingType<?> blah();",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (METHOD): blah()",
- " => type (ERROR return type): %1$s"),
- isJavac ? "<any>" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "abstract class TestClass {",
+ " abstract fun blah(): MissingType<*>",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): blah()",
+ " => type (ERROR return type): %1$s"),
+ isJavac ? "<any>" : "error.NonExistentClass"));
+ });
}
@Test
public void missingReturnTypeTypeParameter() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
@@ -133,295 +149,289 @@
"import java.util.Map;",
"import java.util.Set;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"abstract class TestClass {",
" abstract Map<Set<?>, MissingType<?>> blah();",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (METHOD): blah()",
- " => type (DECLARED return type): "
- + "java.util.Map<java.util.Set<?>,%1$s>",
- " => type (ERROR type argument): %1$s"),
- isJavac ? "<any>" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "abstract class TestClass {",
+ " abstract fun blah(): Map<Set<*>, MissingType<*>>",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): blah()",
+ " => type (DECLARED return type): "
+ + "java.util.Map<java.util.Set<?>,%1$s>",
+ " => type (ERROR type argument): %1$s"),
+ isJavac ? "<any>" : "error.NonExistentClass"));
+ });
}
@Test
public void missingTypeParameter() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass", //
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
- "class TestClass<T extends MissingType> {}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (TYPE_PARAMETER): T",
- " => type (ERROR bound type): %s"),
- isJavac ? "MissingType" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "class TestClass<T extends MissingType> {}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt", //
+ "package test",
+ "",
+ "class TestClass<T : MissingType>"),
+ (processingEnv, superficialValidation) -> {
+ if (isKAPT(processingEnv)) {
+ // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT.
+ return;
+ }
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (TYPE_PARAMETER): T",
+ " => type (ERROR bound type): %s"),
+ isJavac ? "MissingType" : "error.NonExistentClass"));
+ });
}
@Test
public void missingParameterType() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"abstract class TestClass {",
" abstract void foo(MissingType param);",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (METHOD): foo(%1$s)",
- " => element (PARAMETER): param",
- " => type (ERROR parameter type): %1$s"),
- isJavac ? "MissingType" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "abstract class TestClass {",
+ " abstract fun foo(param: MissingType);",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): foo(%1$s)",
+ " => element (PARAMETER): param",
+ " => type (ERROR parameter type): %1$s"),
+ isJavac ? "MissingType" : "error.NonExistentClass"));
+ });
}
@Test
public void missingAnnotation() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass", //
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"@MissingAnnotation",
- "class TestClass {}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => annotation: @MissingAnnotation",
- " => type (ERROR annotation type): %s"),
- isJavac ? "MissingAnnotation" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "class TestClass {}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt", //
+ "package test",
+ "",
+ "@MissingAnnotation",
+ "class TestClass"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => annotation type: MissingAnnotation",
+ " => type (ERROR annotation type): %s"),
+ isJavac ? "MissingAnnotation" : "error.NonExistentClass"));
+ });
}
@Test
public void handlesRecursiveTypeParams() {
- Source javaFileObject =
+ runSuccessfulTest(
CompilerTests.javaSource(
"test.TestClass", //
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
- "class TestClass<T extends Comparable<T>> {}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- superficialValidation.validateElement(testClassElement);
- }
- })
- .compile(subject -> subject.hasErrorCount(0));
+ "class TestClass<T extends Comparable<T>> {}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt", //
+ "package test",
+ "",
+ "class TestClass<T : Comparable<T>>"),
+ (processingEnv, superficialValidation) ->
+ superficialValidation.validateElement(processingEnv.findTypeElement("test.TestClass")));
}
@Test
public void handlesRecursiveType() {
- Source javaFileObject =
+ runSuccessfulTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"abstract class TestClass {",
" abstract TestClass foo(TestClass x);",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- superficialValidation.validateElement(testClassElement);
- }
- })
- .compile(subject -> subject.hasErrorCount(0));
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "abstract class TestClass {",
+ " abstract fun foo(x: TestClass): TestClass",
+ "}"),
+ (processingEnv, superficialValidation) ->
+ superficialValidation.validateElement(processingEnv.findTypeElement("test.TestClass")));
}
@Test
public void missingWildcardBound() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
"",
"import java.util.Set;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"class TestClass {",
- " Set<? extends MissingType> extendsTest() {",
+ " static final class Foo<T> {}",
+ "",
+ " Foo<? extends MissingType> extendsTest() {",
" return null;",
" }",
"",
- " Set<? super MissingType> superTest() {",
+ " Foo<? super MissingType> superTest() {",
" return null;",
" }",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (METHOD): extendsTest()",
- " => type (DECLARED return type): java.util.Set<? extends %1$s>",
- " => type (WILDCARD type argument): ? extends %1$s",
- " => type (ERROR extends bound type): %1$s"),
- isJavac ? "MissingType" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "class TestClass {",
+ " class Foo<T>",
+ "",
+ " fun extendsTest(): Foo<out MissingType> = TODO()",
+ "",
+ " fun superTest(): Foo<in MissingType> = TODO()",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (METHOD): extendsTest()",
+ " => type (DECLARED return type): test.TestClass.Foo<? extends %1$s>",
+ " => type (WILDCARD type argument): ? extends %1$s",
+ " => type (ERROR extends bound type): %1$s"),
+ isJavac ? "MissingType" : "error.NonExistentClass"));
+ });
}
@Test
public void missingIntersection() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.TestClass",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
- "class TestClass<T extends Number & Missing> {}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.TestClass",
- " => element (TYPE_PARAMETER): T",
- " => type (ERROR bound type): %s"),
- isJavac ? "Missing" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "class TestClass<T extends Number & Missing> {}"),
+ CompilerTests.kotlinSource(
+ "test.TestClass.kt",
+ "package test",
+ "",
+ "class TestClass<T> where T: Number, T: Missing"),
+ (processingEnv, superficialValidation) -> {
+ if (isKAPT(processingEnv)) {
+ // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT.
+ return;
+ }
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.TestClass");
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.TestClass",
+ " => element (TYPE_PARAMETER): T",
+ " => type (ERROR bound type): %s"),
+ isJavac ? "Missing" : "error.NonExistentClass"));
+ });
}
@Test
public void invalidAnnotationValue() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.Outer",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"final class Outer {",
" @interface TestAnnotation {",
" Class[] classes();",
@@ -429,192 +439,252 @@
"",
" @TestAnnotation(classes = MissingType.class)",
" static class TestClass {}",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement =
- processingEnv.findTypeElement("test.Outer.TestClass");
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(testClassElement));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.Outer.TestClass",
- " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
- " => annotation value (TYPE_ARRAY): classes={<%1$s>}",
- " => annotation value (TYPE): classes=<%1$s>"),
- isJavac ? "error" : "Error"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.Outer.kt",
+ "package test",
+ "",
+ "class Outer {",
+ " annotation class TestAnnotation(",
+ " val classes: Array<kotlin.reflect.KClass<*>>",
+ " )",
+ "",
+ " @TestAnnotation(classes = [MissingType::class])",
+ " class TestClass {}",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.Outer.TestClass");
+ if (processingEnv.getBackend() == XProcessingEnv.Backend.KSP
+ && sourceKind == SourceKind.KOTLIN) {
+ // TODO(b/269364338): When using kotlin source with KSP the MissingType annotation value
+ // appears to be missing so validating this element does not cause the expected failure.
+ superficialValidation.validateElement(testClassElement);
+ return;
+ }
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(testClassElement));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer.TestClass",
+ " => annotation type: test.Outer.TestAnnotation",
+ " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
+ " => annotation value (TYPE_ARRAY): classes={<%1$s>}",
+ " => annotation value (TYPE): classes=<%1$s>"),
+ isJavac ? "error" : "Error"));
+ });
}
@Test
public void invalidAnnotationValueOnParameter() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.Outer",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"final class Outer {",
" @interface TestAnnotation {",
" Class[] classes();",
" }",
"",
" static class TestClass {",
- " TestClass(@TestAnnotation(classes = Foo) String strParam) {}",
+ " TestClass(@TestAnnotation(classes = MissingType.class) String strParam) {}",
" }",
- "}");
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement testClassElement =
- processingEnv.findTypeElement("test.Outer.TestClass");
- XConstructorElement constructor = testClassElement.getConstructors().get(0);
- XVariableElement parameter = constructor.getParameters().get(0);
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () -> superficialValidation.validateElement(parameter));
- assertThat(exception)
- .hasMessageThat()
- .contains(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.Outer.TestClass",
- " => element (CONSTRUCTOR): TestClass(java.lang.String)",
- " => element (PARAMETER): strParam",
- " => annotation: @test.Outer.TestAnnotation(classes={<error>})",
- " => annotation value (TYPE_ARRAY): classes={<error>}",
- " => annotation value (TYPE): classes=<error>"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.Outer.kt",
+ "package test",
+ "",
+ "class Outer {",
+ " annotation class TestAnnotation(",
+ " val classes: Array<kotlin.reflect.KClass<*>>",
+ " )",
+ "",
+ " class TestClass(",
+ " @TestAnnotation(classes = [MissingType::class]) strParam: String",
+ " )",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ if (sourceKind == SourceKind.KOTLIN) {
+ // TODO(b/268536260): Figure out why XProcessing Testing infra fails when using KAPT.
+ // TODO(b/269364338): When using kotlin source the MissingType annotation value appears
+ // to be missing so validating this element does not cause the expected failure.
+ return;
+ }
+ XTypeElement testClassElement = processingEnv.findTypeElement("test.Outer.TestClass");
+ XConstructorElement constructor = testClassElement.getConstructors().get(0);
+ XVariableElement parameter = constructor.getParameters().get(0);
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () -> superficialValidation.validateElement(parameter));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer.TestClass",
+ " => element (CONSTRUCTOR): TestClass(java.lang.String)",
+ " => element (PARAMETER): strParam",
+ " => annotation type: test.Outer.TestAnnotation",
+ " => annotation: @test.Outer.TestAnnotation(classes={<%1$s>})",
+ " => annotation value (TYPE_ARRAY): classes={<%1$s>}",
+ " => annotation value (TYPE): classes=<%1$s>"),
+ isJavac ? "error" : "Error"));
+ });
}
@Test
public void invalidSuperclassInTypeHierarchy() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.Outer",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"final class Outer {",
" Child<Long> getChild() { return null; }",
- "",
" static class Child<T> extends Parent<T> {}",
- "",
" static class Parent<T> extends MissingType<T> {}",
- "}");
-
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement outerElement = processingEnv.findTypeElement("test.Outer");
- XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0);
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () ->
- superficialValidation.validateTypeHierarchyOf(
- "return type", getChildMethod, getChildMethod.getReturnType()));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.Outer",
- " => element (METHOD): getChild()",
- " => type (DECLARED return type): "
- + "test.Outer.Child<java.lang.Long>",
- " => type (DECLARED supertype): test.Outer.Parent<java.lang.Long>",
- " => type (ERROR supertype): %s"),
- isJavac ? "MissingType<T>" : "error.NonExistentClass"));
- }
- })
- .compile(subject -> subject.hasError());
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.Outer.kt",
+ "package test",
+ "",
+ "class Outer {",
+ " fun getChild(): Child<Long> = TODO()",
+ " class Child<T> : Parent<T>",
+ " open class Parent<T> : MissingType<T>",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement outerElement = processingEnv.findTypeElement("test.Outer");
+ XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0);
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () ->
+ superficialValidation.validateTypeHierarchyOf(
+ "return type", getChildMethod, getChildMethod.getReturnType()));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer",
+ " => element (METHOD): getChild()",
+ " => type (DECLARED return type): test.Outer.Child<java.lang.Long>",
+ " => type (DECLARED supertype): test.Outer.Parent<java.lang.Long>",
+ " => type (ERROR supertype): %s"),
+ isJavac ? "MissingType<T>" : "error.NonExistentClass"));
+ });
}
@Test
public void invalidSuperclassTypeParameterInTypeHierarchy() {
- Source javaFileObject =
+ runTest(
CompilerTests.javaSource(
"test.Outer",
"package test;",
"",
- "@javax.inject.Singleton", // TODO(b/249322175): Used to trigger processing step
"final class Outer {",
" Child getChild() { return null; }",
- "",
" static class Child extends Parent<MissingType> {}",
- "",
" static class Parent<T> {}",
- "}");
+ "}"),
+ CompilerTests.kotlinSource(
+ "test.Outer.kt",
+ "package test",
+ "",
+ "class Outer {",
+ " fun getChild(): Child = TODO()",
+ " class Child : Parent<MissingType>()",
+ " open class Parent<T>",
+ "}"),
+ (processingEnv, superficialValidation) -> {
+ XTypeElement outerElement = processingEnv.findTypeElement("test.Outer");
+ XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0);
+ if (isKAPT(processingEnv)) {
+ // https://youtrack.jetbrains.com/issue/KT-34193/Kapt-CorrectErrorTypes-doesnt-work-for-generics
+ // There's no way to work around this bug in KAPT so validation doesn't catch this case.
+ superficialValidation.validateTypeHierarchyOf(
+ "return type", getChildMethod, getChildMethod.getReturnType());
+ return;
+ }
+ ValidationException exception =
+ assertThrows(
+ ValidationException.KnownErrorType.class,
+ () ->
+ superficialValidation.validateTypeHierarchyOf(
+ "return type", getChildMethod, getChildMethod.getReturnType()));
+ // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
+ boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
+ assertThat(exception)
+ .hasMessageThat()
+ .contains(
+ String.format(
+ NEW_LINES.join(
+ "Validation trace:",
+ " => element (CLASS): test.Outer",
+ " => element (METHOD): getChild()",
+ " => type (DECLARED return type): test.Outer.Child",
+ " => type (DECLARED supertype): test.Outer.Parent<%1$s>",
+ " => type (ERROR type argument): %1$s"),
+ isJavac ? "MissingType" : "error.NonExistentClass"));
+ });
+ }
- CompilerTests.daggerCompiler(javaFileObject)
- .withProcessingSteps(
- () -> new AssertingStep() {
- @Override
- void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation) {
- XTypeElement outerElement = processingEnv.findTypeElement("test.Outer");
- XMethodElement getChildMethod = outerElement.getDeclaredMethods().get(0);
- ValidationException exception =
- assertThrows(
- ValidationException.KnownErrorType.class,
- () ->
- superficialValidation.validateTypeHierarchyOf(
- "return type", getChildMethod, getChildMethod.getReturnType()));
- // TODO(b/248552462): Javac and KSP should match once this bug is fixed.
- boolean isJavac = processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC;
- assertThat(exception)
- .hasMessageThat()
- .contains(
- String.format(
- NEW_LINES.join(
- "Validation trace:",
- " => element (CLASS): test.Outer",
- " => element (METHOD): getChild()",
- " => type (DECLARED return type): test.Outer.Child",
- " => type (DECLARED supertype): test.Outer.Parent<%1$s>",
- " => type (ERROR type argument): %1$s"),
- isJavac ? "MissingType" : "error.NonExistentClass"));
- }
- })
+ private void runTest(
+ Source.JavaSource javaSource,
+ Source.KotlinSource kotlinSource,
+ AssertionHandler assertionHandler) {
+ CompilerTests.daggerCompiler(sourceKind == SourceKind.JAVA ? javaSource : kotlinSource)
+ .withProcessingSteps(() -> new AssertingStep(assertionHandler))
+ // We're expecting compiler errors that we assert on in the assertionHandler.
.compile(subject -> subject.hasError());
}
- private abstract static class AssertingStep implements XProcessingStep {
+ private void runSuccessfulTest(
+ Source.JavaSource javaSource,
+ Source.KotlinSource kotlinSource,
+ AssertionHandler assertionHandler) {
+ CompilerTests.daggerCompiler(sourceKind == SourceKind.JAVA ? javaSource : kotlinSource)
+ .withProcessingSteps(() -> new AssertingStep(assertionHandler))
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ private boolean isKAPT(XProcessingEnv processingEnv) {
+ return processingEnv.getBackend() == XProcessingEnv.Backend.JAVAC
+ && sourceKind == SourceKind.KOTLIN;
+ }
+
+ private interface AssertionHandler {
+ void runAssertions(
+ XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation);
+ }
+
+ private static final class AssertingStep implements XProcessingStep {
+ private final AssertionHandler assertionHandler;
private boolean processed = false;
+ AssertingStep(AssertionHandler assertionHandler) {
+ this.assertionHandler = assertionHandler;
+ }
+
@Override
public final ImmutableSet<String> annotations() {
- // TODO(b/249322175): Replace this with "*" after this bug is fixed.
- // For now, we just trigger off of annotations in the other sources in the test, but ideally
- // this should support "*" similar to javac's Processor.
- return ImmutableSet.of("javax.inject.Singleton");
+ return ImmutableSet.of("*");
}
@Override
@@ -624,11 +694,7 @@
processed = true; // only process once.
TestComponent component =
DaggerDaggerSuperficialValidationTest_TestComponent.factory().create(env);
- try {
- runAssertions(env, component.superficialValidation());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertionHandler.runAssertions(env, component.superficialValidation());
}
return ImmutableSet.of();
}
@@ -636,10 +702,6 @@
@Override
public void processOver(
XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) {}
-
- abstract void runAssertions(
- XProcessingEnv processingEnv, DaggerSuperficialValidation superficialValidation)
- throws Exception;
}
@Singleton
diff --git a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
index 07f8159..b45357c 100644
--- a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
+++ b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
@@ -16,18 +16,14 @@
package dagger.internal.codegen;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.message;
import static org.junit.Assume.assumeFalse;
+import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.util.Source;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
import dagger.testing.compile.CompilerTests;
-import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -1227,11 +1223,10 @@
}
// Tests the format of the error for a somewhat complex binding method.
- // TODO(b/241293838): Convert this test to use XProcessing Testing after fixing this bug.
@Test
public void formatTest() {
- JavaFileObject modules =
- JavaFileObjects.forSourceLines(
+ Source modules =
+ CompilerTests.javaSource(
"test.Modules",
"package test;",
"",
@@ -1269,8 +1264,8 @@
" }",
" }",
"}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -1283,17 +1278,23 @@
"interface TestComponent {",
" @Modules.Foo(bar = String.class) String foo();",
"}");
- Compilation compilation = daggerCompiler().compile(modules, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "String is bound multiple times:",
- " @Provides @Singleton @Modules.Foo(bar = String.class) String "
- + "Modules.Module1.foo(int, ImmutableList<Boolean>)",
- " @Provides @Singleton @Modules.Foo(bar = String.class) String "
- + "Modules.Module2.foo(int, ImmutableList<Boolean>)"))
- .inFile(component);
+ CompilerTests.daggerCompiler(modules, component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ String.format(
+ String.join(
+ "\n",
+ "String is bound multiple times:",
+ " @Provides @Singleton @Modules.Foo(%1$s) String "
+ + "Modules.Module1.foo(int, ImmutableList<Boolean>)",
+ " @Provides @Singleton @Modules.Foo(%1$s) String "
+ + "Modules.Module2.foo(int, ImmutableList<Boolean>)"),
+ // TODO(b/241293838): KSP and java should match after this is fixed.
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP
+ ? "bar=String"
+ : "bar = String.class"));
+ });
}
}
diff --git a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
index 3e7992b..1cd936e 100644
--- a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
+++ b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
@@ -17,11 +17,11 @@
package dagger.internal.codegen;
import static com.google.common.truth.Truth.assertThat;
-import static dagger.spi.model.RequestKind.INSTANCE;
-import static dagger.spi.model.RequestKind.LAZY;
-import static dagger.spi.model.RequestKind.PRODUCED;
-import static dagger.spi.model.RequestKind.PRODUCER;
-import static dagger.spi.model.RequestKind.PROVIDER;
+import static dagger.internal.codegen.model.RequestKind.INSTANCE;
+import static dagger.internal.codegen.model.RequestKind.LAZY;
+import static dagger.internal.codegen.model.RequestKind.PRODUCED;
+import static dagger.internal.codegen.model.RequestKind.PRODUCER;
+import static dagger.internal.codegen.model.RequestKind.PROVIDER;
import dagger.internal.codegen.binding.FrameworkType;
import dagger.internal.codegen.binding.FrameworkTypeMapper;
diff --git a/javatests/dagger/internal/codegen/IgnoreProvisionKeyWildcardsTest.java b/javatests/dagger/internal/codegen/IgnoreProvisionKeyWildcardsTest.java
new file mode 100644
index 0000000..008a0a8
--- /dev/null
+++ b/javatests/dagger/internal/codegen/IgnoreProvisionKeyWildcardsTest.java
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.util.CompilationResultSubject;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import dagger.testing.compile.CompilerTests;
+import java.util.function.Consumer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class IgnoreProvisionKeyWildcardsTest {
+ enum SourceKind { JAVA, KOTLIN }
+
+ @Parameters(name = "sourceKind={0}, isIgnoreProvisionKeyWildcardsEnabled={1}")
+ public static ImmutableList<Object[]> parameters() {
+ return ImmutableList.of(
+ new Object[] {SourceKind.JAVA, false},
+ new Object[] {SourceKind.KOTLIN, false},
+ new Object[] {SourceKind.JAVA, true},
+ new Object[] {SourceKind.KOTLIN, true}
+ );
+ }
+
+ private static final Joiner NEW_LINES = Joiner.on("\n");
+ private static final Joiner NEW_LINES_FOR_ERROR_MSG = Joiner.on("\n ");
+
+ private final boolean isIgnoreProvisionKeyWildcardsEnabled;
+ private final SourceKind sourceKind;
+ private final ImmutableMap<String, String> processingOptions;
+
+ public IgnoreProvisionKeyWildcardsTest(
+ SourceKind sourceKind,
+ boolean isIgnoreProvisionKeyWildcardsEnabled) {
+ this.sourceKind = sourceKind;
+ this.isIgnoreProvisionKeyWildcardsEnabled = isIgnoreProvisionKeyWildcardsEnabled;
+ processingOptions =
+ isIgnoreProvisionKeyWildcardsEnabled
+ ? ImmutableMap.of("dagger.ignoreProvisionKeyWildcards", "enabled")
+ : ImmutableMap.of();
+ }
+
+ @Test
+ public void testProvidesUniqueBindingsWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Foo<? extends Bar> fooExtends();",
+ " Foo<Bar> foo();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Provides static Foo<? extends Bar> fooExtends() { return null; }",
+ " @Provides static Foo<Bar> foo() { return null; }",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun fooExtends(): Foo<out Bar>",
+ " fun foo(): Foo<Bar>",
+ "}",
+ "@Module",
+ "object MyModule {",
+ " @Provides fun fooExtends(): Foo<out Bar> = TODO()",
+ " @Provides fun foo(): Foo<Bar> = TODO()",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Foo<? extends Bar> is bound multiple times:",
+ " @Provides Foo<Bar> MyModule.foo()",
+ " @Provides Foo<? extends Bar> MyModule.fooExtends()",
+ " in component: [MyComponent]"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesUniqueBindingsWithMatchingWildcardArguments() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Map<Foo<? extends Bar>, Foo<? extends Bar>> mapFooExtendsBarFooExtendsBar();",
+ " Map<Foo<? extends Bar>, Foo<Bar>> mapFooExtendsBarFooBar();",
+ " Map<Foo<Bar>, Foo<? extends Bar>> mapFooBarFooExtendsBar();",
+ " Map<Foo<Bar>, Foo<Bar>> mapFooBarFooBar();",
+ "}",
+ "@Module",
+ "class MyModule {",
+ " @Provides",
+ " Map<Foo<? extends Bar>, Foo<? extends Bar>> mapFooExtendsBarFooExtendsBar() {",
+ " return null; ",
+ " }",
+ " @Provides",
+ " Map<Foo<? extends Bar>, Foo<Bar>> mapFooExtendsBarFooBar() {",
+ " return null;",
+ " }",
+ " @Provides",
+ " Map<Foo<Bar>, Foo<? extends Bar>> mapFooBarFooExtendsBar() {",
+ " return null;",
+ " }",
+ " @Provides",
+ " Map<Foo<Bar>, Foo<Bar>> mapFooBarFooBar() {",
+ " return null;",
+ " }",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun mapFooExtendsBarFooExtendsBar(): Map<Foo<out Bar>, Foo<out Bar>>",
+ " fun mapFooExtendsBarFooBar(): Map<Foo<out Bar>, Foo<Bar>>",
+ " fun mapFooBarFooExtendsBar(): Map<Foo<Bar>, Foo<out Bar>>",
+ " fun mapFooBarFooBar(): Map<Foo<Bar>, Foo<Bar>>",
+ "}",
+ "@Module",
+ "class MyModule {",
+ " @Provides",
+ " fun mapFooExtendsBarFooExtendsBar(): Map<Foo<out Bar>, Foo<out Bar>> = TODO()",
+ " @Provides",
+ " fun mapFooExtendsBarFooBar(): Map<Foo<out Bar>, Foo<Bar>> = TODO()",
+ " @Provides",
+ " fun mapFooBarFooExtendsBar(): Map<Foo<Bar>, Foo<out Bar>> = TODO()",
+ " @Provides",
+ " fun mapFooBarFooBar(): Map<Foo<Bar>, Foo<Bar>> = TODO()",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Map<Foo<? extends Bar>,Foo<? extends Bar>> is bound multiple times:",
+ " @Provides Map<Foo<Bar>,Foo<Bar>> MyModule.mapFooBarFooBar()",
+ " @Provides Map<Foo<Bar>,Foo<? extends Bar>> "
+ + "MyModule.mapFooBarFooExtendsBar()",
+ " @Provides Map<Foo<? extends Bar>,Foo<Bar>> "
+ + "MyModule.mapFooExtendsBarFooBar()",
+ " @Provides Map<Foo<? extends Bar>,Foo<? extends Bar>> "
+ + "MyModule.mapFooExtendsBarFooExtendsBar()",
+ " in component: [MyComponent]"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesMultibindsSetDeclarationsWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Set<Foo<? extends Bar>> setExtends();",
+ " Set<Foo<Bar>> set();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds Set<Foo<? extends Bar>> setExtends();",
+ " @Multibinds Set<Foo<Bar>> set();",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun setExtends(): Set<Foo<out Bar>>",
+ " fun set(): Set<Foo<Bar>>",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds fun setExtends(): Set<Foo<out Bar>>",
+ " @Multibinds fun set(): Set<Foo<Bar>>",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Set<Foo<? extends Bar>> has incompatible bindings or declarations:",
+ " Set bindings and declarations:",
+ " @Multibinds Set<Foo<Bar>> MyModule.set()",
+ " @Multibinds Set<Foo<? extends Bar>> MyModule.setExtends()",
+ " in component: [MyComponent]"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesMultibindsSetContributionsWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Set<Foo<? extends Bar>> setExtends();",
+ " Set<Foo<Bar>> set();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Provides @IntoSet static Foo<? extends Bar> setExtends() { return null; }",
+ " @Provides @IntoSet static Foo<Bar> set() { return null; }",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun setExtends(): Set<Foo<out Bar>>",
+ " fun set(): Set<Foo<Bar>>",
+ "}",
+ "@Module",
+ "object MyModule {",
+ " @Provides @IntoSet fun setExtends(): Foo<out Bar> = TODO()",
+ " @Provides @IntoSet fun set(): Foo<Bar> = TODO()",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ String.format(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Set<Foo<? extends Bar>> has incompatible bindings or declarations:",
+ " Set bindings and declarations:",
+ " %1$s Foo<Bar> MyModule.set()",
+ " %1$s Foo<? extends Bar> MyModule.setExtends()",
+ " in component: [MyComponent]"),
+ isKapt(subject) ? "@IntoSet @Provides" : "@Provides @IntoSet"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesMultibindsSetContributionAndMultibindsWithDifferentVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Set<Foo<? extends Bar>> setExtends();",
+ " Set<Foo<Bar>> set();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Provides @IntoSet static Foo<? extends Bar> setExtends() { return null; }",
+ " @Multibinds Set<Foo<Bar>> mulitbindSet();",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun setExtends(): Set<Foo<out Bar>>",
+ " fun set(): Set<Foo<Bar>>",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds abstract fun mulitbindSet(): Set<Foo<Bar>>",
+ "",
+ " companion object {",
+ " @Provides @IntoSet fun setExtends(): Foo<out Bar> = TODO()",
+ " }",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ String.format(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Set<Foo<? extends Bar>> has incompatible bindings or declarations:",
+ " Set bindings and declarations:",
+ " @Multibinds Set<Foo<Bar>> MyModule.mulitbindSet()",
+ " %s Foo<? extends Bar> %s.setExtends()",
+ " in component: [MyComponent]"),
+ isKapt(subject) ? "@IntoSet @Provides" : "@Provides @IntoSet",
+ sourceKind == SourceKind.KOTLIN ? "MyModule.Companion" : "MyModule"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesIntoSetAndElementsIntoSetContributionsWithDifferentVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Set<Foo<? extends Bar>> setExtends();",
+ " Set<Foo<Bar>> set();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Provides @IntoSet static Foo<? extends Bar> setExtends() { return null; }",
+ "",
+ " @Provides",
+ " @ElementsIntoSet",
+ " static Set<Foo<Bar>> set() { return null; }",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun setExtends(): Set<Foo<out Bar>>",
+ " fun set(): Set<Foo<Bar>>",
+ "}",
+ "@Module",
+ "object MyModule {",
+ " @Provides @IntoSet fun setExtends(): Foo<out Bar> = TODO()",
+ " @Provides @ElementsIntoSet fun set(): Set<Foo<Bar>> = TODO()",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ String.format(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Set<Foo<? extends Bar>> has incompatible bindings or declarations:",
+ " Set bindings and declarations:",
+ " %s Set<Foo<Bar>> MyModule.set()",
+ " %s Foo<? extends Bar> MyModule.setExtends()",
+ " in component: [MyComponent]"),
+ isKapt(subject) ? "@ElementsIntoSet @Provides" : "@Provides @ElementsIntoSet",
+ isKapt(subject) ? "@IntoSet @Provides" : "@Provides @IntoSet"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesMultibindsSetContributionsWithSameTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Set<Foo<Bar>> set();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Provides @IntoSet static Foo<Bar> set1() { return null; }",
+ " @Provides @IntoSet static Foo<Bar> set2() { return null; }",
+ " @Provides @ElementsIntoSet static Set<Foo<Bar>> set3() { return null; }",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun set(): Set<Foo<Bar>>",
+ "}",
+ "@Module",
+ "object MyModule {",
+ " @Provides @IntoSet fun set1(): Foo<Bar> = TODO()",
+ " @Provides @IntoSet fun set2(): Foo<Bar> = TODO()",
+ " @Provides @ElementsIntoSet fun set3(): Set<Foo<Bar>> = TODO()",
+ "}"),
+ subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void testProvidesMultibindsMapDeclarationValuesWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Map<String, Foo<? extends Bar>> mapExtends();",
+ " Map<String, Foo<Bar>> map();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds Map<String, Foo<? extends Bar>> mapExtends();",
+ " @Multibinds Map<String, Foo<Bar>> map();",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun mapExtends(): Map<String, Foo<out Bar>>",
+ " fun map(): Map<String, Foo<Bar>>",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds fun mapExtends():Map<String, Foo<out Bar>>",
+ " @Multibinds fun map(): Map<String, Foo<Bar>>",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Map<String,Foo<? extends Bar>> has incompatible bindings or declarations:",
+ " Map bindings and declarations:",
+ " @Multibinds Map<String,Foo<Bar>> MyModule.map()",
+ " @Multibinds Map<String,Foo<? extends Bar>> MyModule.mapExtends()",
+ " in component: [MyComponent]"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesMultibindsMapDeclarationKeysWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Map<Foo<? extends Bar>, String> mapExtends();",
+ " Map<Foo<Bar>, String> map();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds Map<Foo<? extends Bar>, String> mapExtends();",
+ " @Multibinds Map<Foo<Bar>, String> map();",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun mapExtends(): Map<Foo<out Bar>, String>",
+ " fun map(): Map<Foo<Bar>, String>",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Multibinds fun mapExtends():Map<Foo<out Bar>, String>",
+ " @Multibinds fun map(): Map<Foo<Bar>, String>",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Map<Foo<? extends Bar>,String> has incompatible bindings or declarations:",
+ " Map bindings and declarations:",
+ " @Multibinds Map<Foo<Bar>,String> MyModule.map()",
+ " @Multibinds Map<Foo<? extends Bar>,String> MyModule.mapExtends()",
+ " in component: [MyComponent]"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesMultibindsMapContributionsWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Map<String, Foo<? extends Bar>> mapExtends();",
+ " Map<String, Foo<Bar>> map();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"fooExtends\")",
+ " static Foo<? extends Bar> fooExtends() { return null; }",
+ "",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"foo\")",
+ " static Foo<Bar> foo() { return null; }",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun mapExtends(): Map<String, Foo<out Bar>>",
+ " fun map(): Map<String, Foo<Bar>>",
+ "}",
+ "@Module",
+ "object MyModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"fooExtends\")",
+ " fun fooExtends(): Foo<out Bar> = TODO()",
+ "",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"foo\")",
+ " fun foo(): Foo<Bar> = TODO()",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorContaining(
+ String.format(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Map<String,Foo<? extends Bar>> has incompatible bindings or declarations:",
+ " Map bindings and declarations:",
+ " %s Foo<Bar> MyModule.foo()",
+ " %s Foo<? extends Bar> MyModule.fooExtends()",
+ " in component: [MyComponent]"),
+ isKapt(subject)
+ ? "@StringKey(\"foo\") @IntoMap @Provides"
+ : "@Provides @IntoMap @StringKey(\"foo\")",
+ isKapt(subject)
+ ? "@StringKey(\"fooExtends\") @IntoMap @Provides"
+ : "@Provides @IntoMap @StringKey(\"fooExtends\")"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ @Test
+ public void testProvidesOptionalDeclarationWithDifferentTypeVariances() {
+ compile(
+ /* javaComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = MyModule.class)",
+ "interface MyComponent {",
+ " Optional<Foo<? extends Bar>> fooExtends();",
+ " Optional<Foo<Bar>> foo();",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @BindsOptionalOf Foo<? extends Bar> fooExtends();",
+ " @BindsOptionalOf Foo<Bar> foo();",
+ "}"),
+ /* kotlinComponentClass = */
+ NEW_LINES.join(
+ "@Component(modules = [MyModule::class])",
+ "interface MyComponent {",
+ " fun fooExtends(): Optional<Foo<out Bar>>",
+ " fun foo(): Optional<Foo<Bar>>",
+ "}",
+ "@Module",
+ "interface MyModule {",
+ " @BindsOptionalOf fun fooExtends(): Foo<out Bar>",
+ " @BindsOptionalOf fun foo(): Foo<Bar>",
+ "}"),
+ subject -> {
+ if (isIgnoreProvisionKeyWildcardsEnabled) {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ NEW_LINES_FOR_ERROR_MSG.join(
+ "Optional<Foo<? extends Bar>> is bound multiple times:",
+ " @BindsOptionalOf Foo<Bar> MyModule.foo()",
+ " @BindsOptionalOf Foo<? extends Bar> MyModule.fooExtends()",
+ "in component: [MyComponent]"));
+ } else {
+ subject.hasErrorCount(0);
+ }
+ });
+ }
+
+ private void compile(
+ String javaComponentClass,
+ String kotlinComponentClass,
+ Consumer<CompilationResultSubject> onCompilationResult) {
+ if (sourceKind == SourceKind.JAVA) {
+ // Compile with Java sources
+ CompilerTests.daggerCompiler(
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Component;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.Multibinds;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "import java.util.Optional;",
+ "import java.util.Set;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ javaComponentClass,
+ "",
+ "interface Foo<T> {}",
+ "",
+ "class Bar {}"))
+ .withProcessingOptions(processingOptions)
+ .compile(onCompilationResult);
+ }
+
+ if (sourceKind == SourceKind.KOTLIN) {
+ // Compile with Kotlin sources
+ CompilerTests.daggerCompiler(
+ CompilerTests.kotlinSource(
+ "test.MyComponent.kt",
+ // TODO(bcorso): See if there's a better way to fix the following error.
+ //
+ // Error: Cannot inline bytecode built with JVM target 11 into bytecode that is
+ // being built with JVM target 1.8
+ "@file:Suppress(\"INLINE_FROM_HIGHER_PLATFORM\")",
+ "package test",
+ "",
+ "import dagger.BindsOptionalOf",
+ "import dagger.Component",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "import dagger.multibindings.ElementsIntoSet",
+ "import dagger.multibindings.IntoSet",
+ "import dagger.multibindings.IntoMap",
+ "import dagger.multibindings.Multibinds",
+ "import dagger.multibindings.StringKey",
+ "import java.util.Optional;",
+ "import javax.inject.Inject",
+ "import javax.inject.Provider",
+ "",
+ kotlinComponentClass,
+ "",
+ "interface Foo<T>",
+ "",
+ "class Bar"))
+ .withProcessingOptions(processingOptions)
+ .compile(onCompilationResult);
+ }
+ }
+
+ private boolean isKapt(CompilationResultSubject subject) {
+ return sourceKind == SourceKind.KOTLIN
+ && CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC;
+ }
+}
diff --git a/javatests/dagger/internal/codegen/KeyFactoryTest.java b/javatests/dagger/internal/codegen/KeyFactoryTest.java
index 829e2b5..f11f375 100644
--- a/javatests/dagger/internal/codegen/KeyFactoryTest.java
+++ b/javatests/dagger/internal/codegen/KeyFactoryTest.java
@@ -23,9 +23,7 @@
import static dagger.internal.codegen.xprocessing.XTypes.isPrimitive;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import androidx.room.compiler.processing.XAnnotation;
import androidx.room.compiler.processing.XConstructorElement;
-import androidx.room.compiler.processing.XFieldElement;
import androidx.room.compiler.processing.XMethodElement;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XType;
@@ -37,15 +35,11 @@
import dagger.Provides;
import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.javac.JavacPluginModule;
+import dagger.internal.codegen.model.Key;
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntoSet;
import dagger.producers.ProducerModule;
import dagger.producers.Produces;
-import dagger.spi.model.DaggerAnnotation;
-import dagger.spi.model.DaggerExecutableElement;
-import dagger.spi.model.DaggerType;
-import dagger.spi.model.DaggerTypeElement;
-import dagger.spi.model.Key;
import java.lang.annotation.Retention;
import java.util.Set;
import javax.inject.Inject;
@@ -83,7 +77,6 @@
Key key =
keyFactory.forInjectConstructorWithResolvedType(
constructor.getEnclosingElement().getType());
- assertThat(key).isEqualTo(Key.builder(DaggerType.from(typeElement.getType())).build());
assertThat(key.toString()).isEqualTo("dagger.internal.codegen.KeyFactoryTest.InjectedClass");
}
@@ -94,12 +87,10 @@
@Test
public void forProvidesMethod() {
- XType stringType = processingEnv.requireType(String.class.getCanonicalName());
XTypeElement moduleElement =
processingEnv.requireTypeElement(ProvidesMethodModule.class.getCanonicalName());
XMethodElement providesMethod = getOnlyElement(moduleElement.getDeclaredMethods());
Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(key).isEqualTo(Key.builder(DaggerType.from(stringType)).build());
assertThat(key.toString()).isEqualTo("java.lang.String");
}
@@ -139,17 +130,7 @@
processingEnv.requireTypeElement(QualifiedProvidesMethodModule.class.getCanonicalName());
XMethodElement providesMethod = getOnlyElement(moduleElement.getDeclaredMethods());
Key provisionKey = keyFactory.forProvidesMethod(providesMethod, moduleElement);
-
- XType type = processingEnv.requireType(String.class.getCanonicalName());
- XTypeElement injectableElement =
- processingEnv.requireTypeElement(QualifiedFieldHolder.class.getCanonicalName());
- XFieldElement injectionField = getOnlyElement(injectableElement.getDeclaredFields());
- XAnnotation qualifier = getOnlyElement(injectionField.getAllAnnotations());
- Key injectionKey =
- Key.builder(DaggerType.from(type)).qualifier(DaggerAnnotation.from(qualifier)).build();
-
- assertThat(provisionKey).isEqualTo(injectionKey);
- assertThat(injectionKey.toString())
+ assertThat(provisionKey.toString())
.isEqualTo(
"@dagger.internal.codegen.KeyFactoryTest.TestQualifier({"
+ "@dagger.internal.codegen.KeyFactoryTest.InnerAnnotation("
@@ -199,20 +180,10 @@
@Test
public void forProvidesMethod_sets() {
- XTypeElement setElement = processingEnv.requireTypeElement(Set.class.getCanonicalName());
- XType stringType = processingEnv.requireType(String.class.getCanonicalName());
- XType setOfStringsType = processingEnv.getDeclaredType(setElement, stringType);
XTypeElement moduleElement =
processingEnv.requireTypeElement(SetProvidesMethodsModule.class.getCanonicalName());
for (XMethodElement providesMethod : moduleElement.getDeclaredMethods()) {
Key key = keyFactory.forProvidesMethod(providesMethod, moduleElement);
- assertThat(key)
- .isEqualTo(
- Key.builder(DaggerType.from(setOfStringsType))
- .multibindingContributionIdentifier(
- DaggerTypeElement.from(moduleElement),
- DaggerExecutableElement.from(providesMethod))
- .build());
assertThat(key.toString())
.isEqualTo(
String.format(
@@ -269,12 +240,10 @@
}
@Test public void forProducesMethod() {
- XType stringType = processingEnv.requireType(String.class.getCanonicalName());
XTypeElement moduleElement =
processingEnv.requireTypeElement(ProducesMethodsModule.class.getCanonicalName());
for (XMethodElement producesMethod : moduleElement.getDeclaredMethods()) {
Key key = keyFactory.forProducesMethod(producesMethod, moduleElement);
- assertThat(key).isEqualTo(Key.builder(DaggerType.from(stringType)).build());
assertThat(key.toString()).isEqualTo("java.lang.String");
}
}
@@ -291,20 +260,10 @@
}
@Test public void forProducesMethod_sets() {
- XTypeElement setElement = processingEnv.requireTypeElement(Set.class.getCanonicalName());
- XType stringType = processingEnv.requireType(String.class.getCanonicalName());
- XType setOfStringsType = processingEnv.getDeclaredType(setElement, stringType);
XTypeElement moduleElement =
processingEnv.requireTypeElement(SetProducesMethodsModule.class.getCanonicalName());
for (XMethodElement producesMethod : moduleElement.getDeclaredMethods()) {
Key key = keyFactory.forProducesMethod(producesMethod, moduleElement);
- assertThat(key)
- .isEqualTo(
- Key.builder(DaggerType.from(setOfStringsType))
- .multibindingContributionIdentifier(
- DaggerTypeElement.from(moduleElement),
- DaggerExecutableElement.from(producesMethod))
- .build());
assertThat(key.toString())
.isEqualTo(
String.format(
diff --git a/javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java b/javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java
index d9a2469..0219e59 100644
--- a/javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java
+++ b/javatests/dagger/internal/codegen/MapRequestRepresentationWithGuavaTest.java
@@ -16,16 +16,10 @@
package dagger.internal.codegen;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-
import androidx.room.compiler.processing.util.Source;
import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
import dagger.testing.compile.CompilerTests;
import dagger.testing.golden.GoldenFileRule;
-import javax.tools.JavaFileObject;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -49,8 +43,8 @@
@Test
public void mapBindings() throws Exception {
- JavaFileObject mapModuleFile =
- JavaFileObjects.forSourceLines(
+ Source mapModuleFile =
+ CompilerTests.javaSource(
"test.MapModule",
"package test;",
"",
@@ -70,8 +64,8 @@
" @Provides @IntoMap @LongKey(1) static long provideLong1() { return 1; }",
" @Provides @IntoMap @LongKey(2) static long provideLong2() { return 2; }",
"}");
- JavaFileObject subcomponentModuleFile =
- JavaFileObjects.forSourceLines(
+ Source subcomponentModuleFile =
+ CompilerTests.javaSource(
"test.SubcomponentMapModule",
"package test;",
"",
@@ -89,8 +83,8 @@
" @Provides @IntoMap @LongKey(4) static long provideLong4() { return 4; }",
" @Provides @IntoMap @LongKey(5) static long provideLong5() { return 5; }",
"}");
- JavaFileObject componentFile =
- JavaFileObjects.forSourceLines(
+ Source componentFile =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -110,8 +104,8 @@
"",
" Sub sub();",
"}");
- JavaFileObject subcomponent =
- JavaFileObjects.forSourceLines(
+ Source subcomponent =
+ CompilerTests.javaSource(
"test.Sub",
"package test;",
"",
@@ -124,14 +118,13 @@
" Map<Long, Long> longs();",
" Map<Long, Provider<Long>> providerLongs();",
"}");
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
- .compile(mapModuleFile, componentFile, subcomponentModuleFile, subcomponent);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .hasSourceEquivalentTo(goldenFileRule.goldenFile("test.DaggerTestComponent"));
+ CompilerTests.daggerCompiler(mapModuleFile, componentFile, subcomponentModuleFile, subcomponent)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(0);
+ subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent"));
+ });
}
@Test
diff --git a/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java b/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
index 79c0dbf..db9b61c 100644
--- a/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
+++ b/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
@@ -16,14 +16,8 @@
package dagger.internal.codegen;
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-
import androidx.room.compiler.processing.util.Source;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
import dagger.testing.compile.CompilerTests;
-import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -61,11 +55,10 @@
});
}
- // TODO(b/246320661): Use XProcessing testing once this bug is fixed.
@Test
public void membersInjectPrimitive() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -75,12 +68,14 @@
"interface TestComponent {",
" void inject(int primitive);",
"}");
- Compilation compilation = daggerCompiler().compile(component);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Cannot inject members into int")
- .inFile(component)
- .onLineContaining("void inject(int primitive);");
+ CompilerTests.daggerCompiler(component)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining("Cannot inject members into int")
+ .onSource(component)
+ .onLineContaining("void inject(int primitive);");
+ });
}
@Test
@@ -263,11 +258,10 @@
});
}
- // TODO(b/245934092): Update this test after this bug is fixed on XProcessing side.
@Test
public void missingMembersInjectorForKotlinProperty() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -278,8 +272,8 @@
"interface TestComponent {",
" void inject(KotlinInjectedQualifier injected);",
"}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
+ Source module =
+ CompilerTests.javaSource(
"test.TestModule",
"package test;",
"",
@@ -293,17 +287,28 @@
" @Named(\"TheString\")",
" String theString() { return \"\"; }",
"}");
- Compilation compilation = daggerCompiler().compile(component, module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Unable to read annotations on an injected Kotlin property.");
+ CompilerTests.daggerCompiler(component, module)
+ .compile(
+ subject -> {
+ switch (CompilerTests.backend(subject)) {
+ case KSP:
+ // KSP works fine in this case so we shouldn't expect any errors here.
+ subject.hasErrorCount(0);
+ break;
+ case JAVAC:
+ subject.hasErrorCount(2);
+ subject.hasErrorContaining(
+ "Unable to read annotations on an injected Kotlin property.");
+ subject.hasErrorContaining("KotlinInjectedQualifier cannot be provided");
+ break;
+ }
+ });
}
- // TODO(b/245934092): Update this test after this bug is fixed on XProcessing side.
@Test
public void memberInjectionForKotlinObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -314,10 +319,22 @@
"interface TestComponent {",
" void inject(KotlinObjectWithMemberInjection injected);",
"}");
- Compilation compilation = daggerCompiler().compile(component, testModule.toJFO());
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
+ CompilerTests.daggerCompiler(component, testModule)
+ .compile(
+ subject -> {
+ switch (CompilerTests.backend(subject)) {
+ case KSP:
+ subject.hasErrorCount(2);
+ break;
+ case JAVAC:
+ subject.hasErrorCount(3);
+ subject.hasErrorContaining(
+ "Dagger does not support injection into static fields");
+ break;
+ }
+ subject.hasErrorContaining("Dagger does not support injection into Kotlin objects");
+ subject.hasErrorContaining("KotlinObjectWithMemberInjection cannot be provided");
+ });
}
@Test
@@ -345,11 +362,10 @@
});
}
- // TODO(b/245934092): Update this test after this bug is fixed on XProcessing side.
@Test
public void memberInjectionForKotlinClassWithCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -361,17 +377,29 @@
" void inject(KotlinClassWithMemberInjectedCompanion injected);",
" void injectCompanion(KotlinClassWithMemberInjectedCompanion.Companion injected);",
"}");
- Compilation compilation = daggerCompiler().compile(component, testModule.toJFO());
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into static fields");
+ CompilerTests.daggerCompiler(component, testModule)
+ .compile(
+ subject -> {
+ switch (CompilerTests.backend(subject)) {
+ case KSP:
+ subject.hasErrorCount(4);
+ subject.hasErrorContaining(
+ "Dagger does not support injection into Kotlin objects");
+ break;
+ case JAVAC:
+ subject.hasErrorCount(2);
+ break;
+ }
+ subject.hasErrorContaining("Dagger does not support injection into static fields");
+ subject.hasErrorContaining(
+ "KotlinClassWithMemberInjectedCompanion cannot be provided");
+ });
}
- // TODO(b/245792321): Update this test once this bug is fixed.
@Test
public void setterMemberInjectionForKotlinClassWithCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -382,17 +410,30 @@
"interface TestComponent {",
" void inject(KotlinClassWithSetterMemberInjectedCompanion.Companion injected);",
"}");
- Compilation compilation = daggerCompiler().compile(component, testModule.toJFO());
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
+ CompilerTests.daggerCompiler(component, testModule)
+ .compile(
+ subject -> {
+ switch (CompilerTests.backend(subject)) {
+ case KSP:
+ // TODO(b/268257007): The KSP results should match KAPT once this bug is fixed.
+ subject.hasErrorCount(3);
+ subject.hasErrorContaining(
+ "Dagger does not support injection into static methods");
+ break;
+ case JAVAC:
+ subject.hasErrorCount(2);
+ break;
+ }
+ subject.hasErrorContaining("Dagger does not support injection into Kotlin objects");
+ subject.hasErrorContaining(
+ "KotlinClassWithSetterMemberInjectedCompanion.Companion cannot be provided");
+ });
}
- // TODO(b/245934092): Update this test after this bug is fixed on XProcessing side.
@Test
public void memberInjectionForKotlinClassWithNamedCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -405,17 +446,29 @@
" void injectCompanion(KotlinClassWithMemberInjectedNamedCompanion.TheCompanion"
+ " injected);",
"}");
- Compilation compilation = daggerCompiler().compile(component, testModule.toJFO());
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into static fields");
+ CompilerTests.daggerCompiler(component, testModule)
+ .compile(
+ subject -> {
+ switch (CompilerTests.backend(subject)) {
+ case KSP:
+ subject.hasErrorCount(4);
+ subject.hasErrorContaining(
+ "Dagger does not support injection into Kotlin objects");
+ break;
+ case JAVAC:
+ subject.hasErrorCount(2);
+ break;
+ }
+ subject.hasErrorContaining("Dagger does not support injection into static fields");
+ subject.hasErrorContaining(
+ "KotlinClassWithMemberInjectedNamedCompanion cannot be provided");
+ });
}
- // TODO(b/245792321): Update this test once this bug is fixed.
@Test
public void setterMemberInjectionForKotlinClassWithNamedCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
+ Source component =
+ CompilerTests.javaSource(
"test.TestComponent",
"package test;",
"",
@@ -427,10 +480,25 @@
" void inject(",
" KotlinClassWithSetterMemberInjectedNamedCompanion.TheCompanion injected);",
"}");
- Compilation compilation = daggerCompiler().compile(component, testModule.toJFO());
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
+ CompilerTests.daggerCompiler(component, testModule)
+ .compile(
+ subject -> {
+ switch (CompilerTests.backend(subject)) {
+ case KSP:
+ // TODO(b/268257007): The KSP results should match KAPT once this bug is fixed.
+ subject.hasErrorCount(3);
+ subject.hasErrorContaining(
+ "Dagger does not support injection into static methods");
+ break;
+ case JAVAC:
+ subject.hasErrorCount(2);
+ break;
+ }
+ subject.hasErrorContaining("Dagger does not support injection into Kotlin objects");
+ subject.hasErrorContaining(
+ "KotlinClassWithSetterMemberInjectedNamedCompanion.TheCompanion "
+ + "cannot be provided");
+ });
}
private final Source testModule =
diff --git a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
index b25ac9d..919700e 100644
--- a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
+++ b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
@@ -16,9 +16,14 @@
package dagger.internal.codegen;
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.room.compiler.processing.util.DiagnosticMessage;
import androidx.room.compiler.processing.util.Source;
import com.google.common.collect.ImmutableList;
import dagger.testing.compile.CompilerTests;
+import java.util.List;
+import javax.tools.Diagnostic;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -1298,4 +1303,493 @@
"[foo.Sub] foo.Sub.getObject() [Parent → Child1 → foo.Sub]");
});
}
+
+ @Test
+ public void requestWildcardTypeWithNonWildcardTypeBindingProvided_failsWithMissingBinding() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ " Child getChild();",
+ "}");
+ Source child =
+ CompilerTests.javaSource(
+ "test.Child",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = ChildModule.class)",
+ "interface Child {}");
+ Source childModule =
+ CompilerTests.javaSource(
+ "test.ChildModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "import java.util.HashSet;",
+ "",
+ "@Module",
+ "interface ChildModule {",
+ " @Provides",
+ " static Set<? extends Bar> provideBar() {",
+ " return new HashSet<Bar>();",
+ " }",
+ "}");
+ Source fooSrc =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.Set;",
+ "",
+ "class Foo {",
+ " @Inject Foo(Set<? extends Bar> bar) {}",
+ "}");
+ Source barSrc =
+ CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "import java.util.HashSet;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @ElementsIntoSet",
+ " @Provides",
+ " Set<Bar> provideBars() {",
+ " return new HashSet<Bar>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(component, child, childModule, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Found similar bindings:")
+ .onSource(component)
+ .onLineContaining("interface MyComponent");
+ subject.hasErrorContaining("Set<Bar> in [MyComponent");
+ subject.hasErrorContaining("Set<? extends Bar> in [MyComponent → Child]");
+ });
+ }
+
+ @Test
+ public void
+ injectParameterDoesNotSuppressWildcardGeneration_conflictsWithNonWildcardTypeBinding() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.kotlinSource(
+ "Foo.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class Foo @Inject constructor(val bar: Set<Bar>) {}");
+ Source barSrc =
+ CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "import java.util.HashSet;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @ElementsIntoSet",
+ " @Provides",
+ " Set<Bar> provideBars() {",
+ " return new HashSet<Bar>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Set<Bar> in [MyComponent]")
+ .onSource(component)
+ .onLineContaining("interface MyComponent");
+ });
+ }
+
+ @Test
+ public void injectWildcardTypeWithNonWildcardTypeBindingProvided_failsWithMissingBinding() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import java.util.Set;",
+ "",
+ "class Foo {",
+ " @Inject Set<? extends Bar> bar;",
+ " @Inject Foo() {}",
+ "}");
+ Source barSrc =
+ CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "import java.util.HashSet;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @ElementsIntoSet",
+ " @Provides",
+ " Set<Bar> provideBars() {",
+ " return new HashSet<Bar>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Found similar bindings:")
+ .onSource(component)
+ .onLineContaining("interface MyComponent");
+ subject.hasErrorContaining("Set<Bar> in [MyComponent]");
+ });
+ }
+
+ @Test
+ public void requestFinalClassWithWildcardAnnotation_missingWildcardTypeBinding() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.kotlinSource(
+ "test.Foo.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class Foo @Inject constructor(val bar: List<Bar>) {}");
+ Source barSrc =
+ CompilerTests.javaSource("test.Bar", "package test;", "", "public final class Bar {}");
+ Source moduleSrc =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "import dagger.multibindings.ElementsIntoSet",
+ "",
+ "@Module",
+ "object TestModule {",
+ " @Provides fun provideBars(): List<@JvmWildcard Bar> = setOf()",
+ "}");
+
+ CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Found similar bindings:")
+ .onSource(component)
+ .onLineContaining("interface MyComponent");
+ subject.hasErrorContaining("List<? extends Bar> in [MyComponent]");
+ });
+ }
+
+ @Test
+ public void multipleTypeParameters_notSuppressWildcardType_failsWithMissingBinding() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.kotlinSource(
+ "test.Foo.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class Foo @Inject constructor(val bar: Bar<Baz, Baz, Set<Baz>>) {}");
+ Source barSrc =
+ CompilerTests.kotlinSource(
+ "test.Bar.kt", "package test", "", "class Bar<out T1, T2, T3> {}");
+
+ Source bazSrc =
+ CompilerTests.javaSource("test.Baz", "package test;", "", "public interface Baz {}");
+
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @Provides",
+ " Bar<Baz, Baz, Set<Baz>> provideBar() {",
+ " return new Bar<Baz, Baz, Set<Baz>>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(component, fooSrc, barSrc, bazSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Bar<Baz,Baz,Set<Baz>> in [MyComponent]")
+ .onSource(component)
+ .onLineContaining("interface MyComponent");
+ });
+ }
+
+ @Test
+ public void missingBindingWithoutQualifier_warnAboutSimilarTypeWithQualifierExists() {
+ Source qualifierSrc =
+ CompilerTests.javaSource(
+ "test.MyQualifier",
+ "package test;",
+ "",
+ "import javax.inject.Qualifier;",
+ "",
+ "@Qualifier",
+ "@interface MyQualifier {}");
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.kotlinSource(
+ "Foo.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class Foo @Inject constructor(val bar: Set<Bar>) {}");
+ Source barSrc =
+ CompilerTests.javaSource("test.Bar", "package test;", "", "public interface Bar {}");
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "import java.util.HashSet;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @ElementsIntoSet",
+ " @Provides",
+ " @MyQualifier",
+ " Set<Bar> provideBars() {",
+ " return new HashSet<Bar>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(qualifierSrc, component, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining("MissingBinding");
+ List<DiagnosticMessage> diagnostics =
+ subject.getCompilationResult().getDiagnostics().get(Diagnostic.Kind.ERROR);
+ assertThat(diagnostics).hasSize(1);
+ assertThat(diagnostics.get(0).getMsg())
+ .doesNotContain("bindings with similar types exists in the graph");
+ });
+ }
+
+ @Test
+ public void missingWildcardTypeWithObjectBound_providedRawType_warnAboutSimilarTypeExists() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.kotlinSource(
+ "test.Foo.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class Foo @Inject constructor(val bar: Bar<Object>) {}");
+ Source barSrc =
+ CompilerTests.kotlinSource("test.Bar.kt", "package test", "", "class Bar<out T1> {}");
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @Provides",
+ " Bar provideBar() {",
+ " return new Bar<Object>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining("Found similar bindings:");
+ subject.hasErrorContaining("Bar in [MyComponent]");
+ });
+ }
+
+ @Test
+ public void missingWildcardType_providedRawType_warnAboutSimilarTypeExists() {
+ Source component =
+ CompilerTests.javaSource(
+ "test.MyComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "import java.util.Set;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface MyComponent {",
+ " Foo getFoo();",
+ "}");
+ Source fooSrc =
+ CompilerTests.kotlinSource(
+ "test.Foo.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class Foo @Inject constructor(val bar: Bar<String>) {}");
+ Source barSrc =
+ CompilerTests.kotlinSource("test.Bar.kt", "package test", "", "class Bar<out T1> {}");
+ Source moduleSrc =
+ CompilerTests.javaSource(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "public class TestModule {",
+ " @Provides",
+ " Bar provideBar() {",
+ " return new Bar<Object>();",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(component, fooSrc, barSrc, moduleSrc)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining("MissingBinding");
+ List<DiagnosticMessage> diagnostics =
+ subject.getCompilationResult().getDiagnostics().get(Diagnostic.Kind.ERROR);
+ assertThat(diagnostics).hasSize(1);
+ assertThat(diagnostics.get(0).getMsg())
+ .doesNotContain("bindings with similar types exists in the graph");
+ });
+ }
}
diff --git a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
index 814652a..cc8e3b4 100644
--- a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2014 The Dagger Authors.
*
@@ -557,6 +556,31 @@
});
}
+ @Test
+ public void privateModule_kotlin() {
+ Source moduleFile =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "private class TestModule {",
+ " @Provides fun provideInt(): Int = 1",
+ "}");
+
+ CompilerTests.daggerCompiler(moduleFile)
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject
+ .hasErrorContaining("Modules cannot be private")
+ .onSource(moduleFile);
+ });
+ }
@Test
public void enclosedInPrivateModule() {
diff --git a/javatests/dagger/internal/codegen/XExecutableTypesTest.java b/javatests/dagger/internal/codegen/XExecutableTypesTest.java
new file mode 100644
index 0000000..faca16b
--- /dev/null
+++ b/javatests/dagger/internal/codegen/XExecutableTypesTest.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.util.Source;
+import dagger.internal.codegen.xprocessing.XExecutableTypes;
+import dagger.testing.compile.CompilerTests;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class XExecutableTypesTest {
+
+ @Test
+ public void subsignatureMethodNamesAreIgnored() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " void p(String s) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " void q(String s) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isTrue();
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isTrue();
+ });
+ }
+
+ @Test
+ public void subsignatureReturnTypesAreIgnored() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " List m(Collection c) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " Set m(Collection c) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isTrue();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isTrue();
+ });
+ }
+
+ @Test
+ public void subsignatureStaticIsIgnored() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " void m(Collection i) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " static void m(Collection i) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isTrue();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isTrue();
+ });
+ }
+
+ @Test
+ public void subsignatureWithAndWithoutTypeArguments() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " <T> void m(Collection<T> i) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " void m(Collection i) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isTrue();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isFalse();
+ });
+ }
+
+ @Test
+ public void subsignatureDifferentNumberOfTypeArguments() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " <T, Q> void m(Collection i) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " <T> void m(Collection i) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isFalse();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isFalse();
+ });
+ }
+
+ @Test
+ public void subsignatureDifferentTypeArgumentBounds() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " <T extends Foo> void m(Collection<T> i) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " <T> void m(Collection<T> i) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isFalse();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isFalse();
+ });
+ }
+
+ @Test
+ public void subsignatureWithGenericClasses() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " void m(Collection i) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " void m(Collection<String> i) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isFalse();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isTrue();
+ });
+ }
+
+ @Test
+ public void subsignatureSameSignature() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " <T> List<T> toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar extends Foo {",
+ " <T> List<T> toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isTrue();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isTrue();
+ });
+ }
+
+ @Test
+ public void subsignatureSameSignatureUnrelatedClasses() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " <T> List<T> toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " <T> List<T> toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isTrue();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isTrue();
+ });
+ }
+
+ @Test
+ public void subsignatureWildcards() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " void toList(Collection<Object> c) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " void toList(Collection<? extends Foo> c) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isFalse();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isFalse();
+ });
+ }
+
+ @Test
+ public void subsignatureBounded() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " void toList(Collection<Foo> c) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " <T extends Foo> void toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isFalse();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isFalse();
+ });
+ }
+
+ @Test
+ public void subsignatureGenericMethodAndWildcard() {
+ Source foo =
+ CompilerTests.javaSource(
+ "test.Foo",
+ "package test;",
+ "import java.util.*;",
+ "class Foo {",
+ " <T> List<T> toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ Source bar =
+ CompilerTests.javaSource(
+ "test.Bar",
+ "package test;",
+ "import java.util.*;",
+ "class Bar {",
+ " <T extends Foo> List<T> toList(Collection<T> c) { throw new RuntimeException(); }",
+ "}");
+ CompilerTests.invocationCompiler(foo, bar)
+ .compile(
+ invocation -> {
+ XTypeElement fooType = invocation.getProcessingEnv().requireTypeElement("test.Foo");
+ XMethodElement m1 = fooType.getDeclaredMethods().get(0);
+
+ XTypeElement barType = invocation.getProcessingEnv().requireTypeElement("test.Bar");
+ XMethodElement m2 = barType.getDeclaredMethods().get(0);
+
+ assertThat(XExecutableTypes.isSubsignature(m2, m1)).isFalse();
+ assertThat(XExecutableTypes.isSubsignature(m1, m2)).isFalse();
+ });
+ }
+}
diff --git a/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java b/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java
new file mode 100644
index 0000000..3a3da57
--- /dev/null
+++ b/javatests/dagger/internal/codegen/XTypesStripTypeNameTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static androidx.room.compiler.processing.util.ProcessorTestExtKt.runProcessorTest;
+import static com.google.common.truth.Truth.assertThat;
+import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
+import static dagger.internal.codegen.xprocessing.XTypes.stripVariances;
+
+import androidx.room.compiler.processing.XMethodElement;
+import androidx.room.compiler.processing.XProcessingEnvConfig;
+import androidx.room.compiler.processing.XTypeElement;
+import androidx.room.compiler.processing.util.Source;
+import androidx.room.compiler.processing.util.XTestInvocation;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.TypeName;
+import dagger.testing.compile.CompilerTests;
+import java.util.function.Function;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class XTypesStripTypeNameTest {
+ @Test
+ public void fooExtendsBar() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " Foo<? extends Bar<? extends Baz>> method();",
+ "",
+ " interface Foo<T> {}",
+ " interface Bar<T> {}",
+ " interface Baz {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<Bar<Baz>>");
+ }
+
+ @Test
+ public void fooSuperBar() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " Foo<? super Bar<? super Baz>> method();",
+ "",
+ " interface Foo<T> {}",
+ " interface Bar<T> {}",
+ " interface Baz {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<Bar<Baz>>");
+ }
+
+ @Test
+ public void multipleParameters() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " Foo<Bar<? extends Baz>, Bar<? super Baz>> method();",
+ "",
+ " interface Foo<T1, T2> {}",
+ " interface Bar<T> {}",
+ " interface Baz {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<Bar<Baz>, Bar<Baz>>");
+ }
+
+ @Test
+ public void multipleParametersSameArgument() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " Foo<Bar<? extends Baz>, Bar<? extends Baz>> method();",
+ "",
+ " interface Foo<T1, T2> {}",
+ " interface Bar<T> {}",
+ " interface Baz {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<Bar<Baz>, Bar<Baz>>");
+ }
+
+ @Test
+ public void multipleParametersCrossReferencing() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " Foo<Bar<? extends Baz>, Bar<? extends Bar<? extends Baz>>> method();",
+ "",
+ " interface Foo<T1, T2 extends Bar<? extends T1>> {}",
+ " interface Bar<T> {}",
+ " interface Baz {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<Bar<Baz>, Bar<Bar<Baz>>>");
+ }
+
+ @Test
+ public void selfReferencing() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " <T extends Foo<T>> Foo<T> method();",
+ "",
+ " interface Foo<T extends Foo<T>> {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<T>");
+ }
+
+ @Test
+ public void arrayType() {
+ assertStrippedWildcardTypeNameEquals(
+ /* source = */
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " Foo<? extends Bar<? extends Baz>>[] method();",
+ "",
+ " interface Foo<T> {}",
+ " interface Bar<T> {}",
+ " interface Baz {}",
+ "}"),
+ /* strippedTypeName = */ "Foo<Bar<Baz>>[]");
+ }
+
+ @Test
+ public void typeVariableSameVariableName() {
+ runTest(
+ CompilerTests.javaSource(
+ "Subject",
+ "interface Subject {",
+ " <T extends Bar> Foo<T> method1();",
+ " <T extends Baz> Foo<T> method2();",
+ "",
+ " interface Foo<T> {}",
+ " interface Bar {}",
+ " interface Baz {}",
+ "}"),
+ invocation -> {
+ XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject");
+ TypeName method1ReturnTypeName =
+ getDeclaredMethod(subject, "method1").getReturnType().getTypeName();
+ TypeName method2ReturnTypeName =
+ getDeclaredMethod(subject, "method2").getReturnType().getTypeName();
+ assertThat(method1ReturnTypeName).isEqualTo(method2ReturnTypeName);
+ return null;
+ });
+ }
+
+ private static void assertStrippedWildcardTypeNameEquals(Source source, String strippedTypeName) {
+ runTest(
+ source,
+ invocation -> {
+ XTypeElement subject = invocation.getProcessingEnv().requireTypeElement("Subject");
+ TypeName returnTypeName =
+ getDeclaredMethod(subject, "method").getReturnType().getTypeName();
+ assertThat(stripVariances(returnTypeName).toString().replace("Subject.", ""))
+ .isEqualTo(strippedTypeName);
+ return null;
+ });
+ }
+
+ private static void runTest(Source source, Function<XTestInvocation, Void> handler) {
+ runProcessorTest(
+ ImmutableList.of(source),
+ /* classpath = */ ImmutableList.of(),
+ /* options = */ ImmutableMap.of(),
+ /* javacArguments = */ ImmutableList.of(),
+ /* kotlincArguments = */ ImmutableList.of(),
+ /* config = */ new XProcessingEnvConfig.Builder().build(),
+ /* handler = */ invocation -> {
+ handler.apply(invocation);
+ return null;
+ });
+ }
+
+ private static XMethodElement getDeclaredMethod(XTypeElement typeElement, String jvmName) {
+ return typeElement.getDeclaredMethods().stream()
+ .filter(method -> method.getJvmName().contentEquals(jvmName))
+ .collect(onlyElement());
+ }
+}
diff --git a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
index 1ed0425..ce7197a 100644
--- a/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
+++ b/javatests/dagger/internal/codegen/bindinggraphvalidation/BUILD
@@ -27,6 +27,7 @@
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
"//java/dagger/internal/codegen/bindinggraphvalidation",
+ "//java/dagger/internal/codegen/xprocessing",
"//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
"//java/dagger/testing/compile",
"//javatests/dagger/internal/codegen:compilers",
diff --git a/javatests/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidationKotlinTest.java b/javatests/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidationKotlinTest.java
new file mode 100644
index 0000000..6b63b7c
--- /dev/null
+++ b/javatests/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidationKotlinTest.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2023 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen.bindinggraphvalidation;
+
+import static dagger.internal.codegen.bindinggraphvalidation.NullableBindingValidator.nullableToNonNullable;
+
+import androidx.room.compiler.processing.XProcessingEnv;
+import androidx.room.compiler.processing.util.Source;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import dagger.internal.codegen.CompilerMode;
+import dagger.testing.compile.CompilerTests;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class NullableBindingValidationKotlinTest {
+ @Parameters(name = "{0}")
+ public static ImmutableList<Object[]> parameters() {
+ return CompilerMode.TEST_PARAMETERS;
+ }
+
+ private final CompilerMode compilerMode;
+
+ public NullableBindingValidationKotlinTest(CompilerMode compilerMode) {
+ this.compilerMode = compilerMode;
+ }
+
+ @Test
+ public void nullCheckForConstructorParameters() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class A @Inject constructor(string: String)");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides fun provideString(): String? = null",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ nullableToNonNullable(
+ "String",
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC
+ ? "@Nullable @Provides String TestModule.provideString()"
+ // TODO(b/268550160): For KSP, we should be including the kotlin typename
+ // in the error message, e.g. "String?" otherwise the message doesn't make
+ // a lot of sense.
+ : "@Provides String TestModule.provideString()"));
+ });
+
+ // but if we disable the validation, then it compiles fine.
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(
+ ImmutableMap.<String, String>builder()
+ .putAll(compilerMode.processorOptions())
+ .put("dagger.nullableValidation", "WARNING")
+ .buildOrThrow())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void nullCheckForMembersInjectParam() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class A @Inject constructor() {",
+ " @Inject fun register(string: String) {}",
+ "}");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides fun provideString(): String? = null",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ nullableToNonNullable(
+ "String",
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC
+ ? "@Nullable @Provides String TestModule.provideString()"
+ // TODO(b/268550160): For KSP, we should be including the kotlin typename
+ // in the error message, e.g. "String?" otherwise the message doesn't make
+ // a lot of sense.
+ : "@Provides String TestModule.provideString()"));
+ });
+
+ // but if we disable the validation, then it compiles fine.
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(
+ ImmutableMap.<String, String>builder()
+ .putAll(compilerMode.processorOptions())
+ .put("dagger.nullableValidation", "WARNING")
+ .buildOrThrow())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void nullCheckForVariable() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import javax.inject.Inject",
+ "",
+ "class A @Inject constructor() {",
+ " @Inject lateinit var string: String",
+ "}");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides fun provideString():String? = null",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ nullableToNonNullable(
+ "String",
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC
+ ? "@Nullable @Provides String TestModule.provideString()"
+ // TODO(b/268550160): For KSP, we should be including the kotlin typename
+ // in the error message, e.g. "String?" otherwise the message doesn't make
+ // a lot of sense.
+ : "@Provides String TestModule.provideString()"));
+ });
+
+ // but if we disable the validation, then it compiles fine.
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(
+ ImmutableMap.<String, String>builder()
+ .putAll(compilerMode.processorOptions())
+ .put("dagger.nullableValidation", "WARNING")
+ .buildOrThrow())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test public void nullCheckForComponentReturn() {
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides fun provideString():String? = null",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun string(): String",
+ "}");
+ CompilerTests.daggerCompiler(module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ nullableToNonNullable(
+ "String",
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC
+ ? "@Nullable @Provides String TestModule.provideString()"
+ // TODO(b/268550160): For KSP, we should be including the kotlin typename
+ // in the error message, e.g. "String?" otherwise the message doesn't make
+ // a lot of sense.
+ : "@Provides String TestModule.provideString()"));
+ });
+
+ // but if we disable the validation, then it compiles fine.
+ CompilerTests.daggerCompiler(module, component)
+ .withProcessingOptions(
+ ImmutableMap.<String, String>builder()
+ .putAll(compilerMode.processorOptions())
+ .put("dagger.nullableValidation", "WARNING")
+ .buildOrThrow())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void nullCheckForOptionalInstance() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import com.google.common.base.Optional",
+ "import javax.inject.Inject",
+ "",
+ "class A @Inject constructor(optional: Optional<String>)");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.BindsOptionalOf",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @BindsOptionalOf abstract fun optionalString(): String",
+ "",
+ " companion object {",
+ " @Provides fun provideString():String? = null",
+ " }",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ nullableToNonNullable(
+ "String",
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC
+ ? "@Nullable @Provides String TestModule.Companion.provideString()"
+ // TODO(b/268550160): For KSP, we should be including the kotlin typename
+ // in the error message, e.g. "String?" otherwise the message doesn't make
+ // a lot of sense.
+ : "@Provides String TestModule.Companion.provideString()"));
+ });
+ }
+
+ @Test
+ public void nullCheckForOptionalProvider() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import com.google.common.base.Optional",
+ "import javax.inject.Inject",
+ "import javax.inject.Provider",
+ "",
+ "class A @Inject constructor(optional: Optional<Provider<String>>)");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.BindsOptionalOf",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @BindsOptionalOf abstract fun optionalString(): String",
+ "",
+ " companion object {",
+ " @Provides fun provideString():String? = null",
+ " }",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void nullCheckForOptionalLazy() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import com.google.common.base.Optional",
+ "import dagger.Lazy",
+ "import javax.inject.Inject",
+ "",
+ "class A @Inject constructor(optional: Optional<Lazy<String>>)");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.BindsOptionalOf",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @BindsOptionalOf abstract fun optionalString(): String",
+ "",
+ " companion object {",
+ " @Provides fun provideString():String? = null",
+ " }",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void nullCheckForOptionalProviderOfLazy() {
+ Source a =
+ CompilerTests.kotlinSource(
+ "test.A.kt",
+ "package test",
+ "",
+ "import com.google.common.base.Optional",
+ "import dagger.Lazy",
+ "import javax.inject.Inject",
+ "import javax.inject.Provider",
+ "",
+ "class A @Inject constructor(optional: Optional<Provider<Lazy<String>>>)");
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.BindsOptionalOf",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @BindsOptionalOf abstract fun optionalString(): String",
+ "",
+ " companion object {",
+ " @Provides fun provideString():String? = null",
+ " }",
+ "}");
+ Source component =
+ CompilerTests.kotlinSource(
+ "test.TestComponent.kt",
+ "package test",
+ "",
+ "import dagger.Component",
+ "",
+ "@Component(modules = [TestModule::class])",
+ "interface TestComponent {",
+ " fun a(): A",
+ "}");
+ CompilerTests.daggerCompiler(a, module, component)
+ .withProcessingOptions(compilerMode.processorOptions())
+ .compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
+ public void moduleValidation() {
+ Source module =
+ CompilerTests.kotlinSource(
+ "test.TestModule.kt",
+ "package test",
+ "",
+ "import dagger.Binds",
+ "import dagger.Module",
+ "import dagger.Provides",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @Binds abstract fun bindObject(string: String): Object",
+ "",
+ " companion object {",
+ " @Provides fun nullableString():String? = null",
+ " }",
+ "}");
+ CompilerTests.daggerCompiler(module)
+ .withProcessingOptions(
+ ImmutableMap.<String, String>builder()
+ .putAll(compilerMode.processorOptions())
+ .put("dagger.fullBindingGraphValidation", "ERROR")
+ .buildOrThrow())
+ .compile(
+ subject -> {
+ subject.hasErrorCount(1);
+ subject.hasErrorContaining(
+ nullableToNonNullable(
+ "String",
+ CompilerTests.backend(subject) == XProcessingEnv.Backend.JAVAC
+ ? "@Nullable @Provides String TestModule.Companion.nullableString()"
+ // TODO(b/268550160): For KSP, we should be including the kotlin typename
+ // in the error message, e.g. "String?" otherwise the message doesn't make
+ // a lot of sense.
+ : "@Provides String TestModule.Companion.nullableString()"));
+ });
+ }
+}
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjectionInsideProvision_DEFAULT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjectionInsideProvision_DEFAULT_MODE_test.DaggerSimpleComponent
deleted file mode 100644
index e4fa976..0000000
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjectionInsideProvision_DEFAULT_MODE_test.DaggerSimpleComponent
+++ /dev/null
@@ -1,59 +0,0 @@
-package test;
-
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.internal.DaggerGenerated;
-import javax.annotation.processing.Generated;
-
-@DaggerGenerated
-@Generated(
- value = "dagger.internal.codegen.ComponentProcessor",
- comments = "https://dagger.dev"
-)
-@SuppressWarnings({
- "unchecked",
- "rawtypes",
- "KotlinInternal",
- "KotlinInternalInJava"
-})
-final class DaggerSimpleComponent {
- private DaggerSimpleComponent() {
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static SimpleComponent create() {
- return new Builder().build();
- }
-
- static final class Builder {
- private Builder() {
- }
-
- public SimpleComponent build() {
- return new SimpleComponentImpl();
- }
- }
-
- private static final class SimpleComponentImpl implements SimpleComponent {
- private final SimpleComponentImpl simpleComponentImpl = this;
-
- private SimpleComponentImpl() {
-
-
- }
-
- @Override
- public SomeInjectedType createAndInject() {
- return injectSomeInjectedType(SomeInjectedType_Factory.newInstance());
- }
-
- @CanIgnoreReturnValue
- private SomeInjectedType injectSomeInjectedType(SomeInjectedType instance) {
- SomeInjectedType_MembersInjector.injectInjectedField(instance, new SomeInjectableType());
- return instance;
- }
- }
-}
-
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjectionInsideProvision_FAST_INIT_MODE_test.DaggerSimpleComponent b/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjectionInsideProvision_FAST_INIT_MODE_test.DaggerSimpleComponent
deleted file mode 100644
index e4fa976..0000000
--- a/javatests/dagger/internal/codegen/goldens/ComponentProcessorTest_membersInjectionInsideProvision_FAST_INIT_MODE_test.DaggerSimpleComponent
+++ /dev/null
@@ -1,59 +0,0 @@
-package test;
-
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.internal.DaggerGenerated;
-import javax.annotation.processing.Generated;
-
-@DaggerGenerated
-@Generated(
- value = "dagger.internal.codegen.ComponentProcessor",
- comments = "https://dagger.dev"
-)
-@SuppressWarnings({
- "unchecked",
- "rawtypes",
- "KotlinInternal",
- "KotlinInternalInJava"
-})
-final class DaggerSimpleComponent {
- private DaggerSimpleComponent() {
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static SimpleComponent create() {
- return new Builder().build();
- }
-
- static final class Builder {
- private Builder() {
- }
-
- public SimpleComponent build() {
- return new SimpleComponentImpl();
- }
- }
-
- private static final class SimpleComponentImpl implements SimpleComponent {
- private final SimpleComponentImpl simpleComponentImpl = this;
-
- private SimpleComponentImpl() {
-
-
- }
-
- @Override
- public SomeInjectedType createAndInject() {
- return injectSomeInjectedType(SomeInjectedType_Factory.newInstance());
- }
-
- @CanIgnoreReturnValue
- private SomeInjectedType injectSomeInjectedType(SomeInjectedType instance) {
- SomeInjectedType_MembersInjector.injectInjectedField(instance, new SomeInjectableType());
- return instance;
- }
- }
-}
-
diff --git a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
index 06c68ee..81056e2 100644
--- a/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/ComponentShardTest_testNewShardCreated_FAST_INIT_MODE_dagger.internal.codegen.DaggerTestComponent
@@ -252,4 +252,5 @@
}
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent
index 3a29729..9c25066 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_DEFAULT_MODE_test.DaggerTestComponent
@@ -71,4 +71,5 @@
return OtherEntryPoint_Factory.newInstance(fooImpl());
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent
index fd92c6d..a18b8a4 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoopScoped_FAST_INIT_MODE_test.DaggerTestComponent
@@ -93,4 +93,5 @@
}
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent
index 8e03211..c1345ad 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_DEFAULT_MODE_test.DaggerTestComponent
@@ -67,4 +67,5 @@
return OtherEntryPoint_Factory.newInstance(fooImpl());
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent
index 137cbcf..8e2e959 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_inaccessibleTypeBoundInALoop_FAST_INIT_MODE_test.DaggerTestComponent
@@ -89,4 +89,5 @@
}
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent
index 19d8352..73dda53 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_DEFAULT_MODE_test.DaggerTestComponent
@@ -59,4 +59,5 @@
return bindProvider.get();
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent
index 922d293..84ae12f 100644
--- a/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent
+++ b/javatests/dagger/internal/codegen/goldens/InaccessibleTypeBindsTest_scopedInaccessibleTypeBound_FAST_INIT_MODE_test.DaggerTestComponent
@@ -85,4 +85,5 @@
}
}
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory
index 8804127..67f856c 100644
--- a/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory
+++ b/javatests/dagger/internal/codegen/goldens/InjectConstructorFactoryGeneratorTest_noDeps_test.SimpleType_Factory
@@ -36,4 +36,5 @@
private static final class InstanceHolder {
private static final SimpleType_Factory INSTANCE = new SimpleType_Factory();
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector
index e15bf9b..72b876e 100644
--- a/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector
+++ b/javatests/dagger/internal/codegen/goldens/MembersInjectionTest_componentWithNestingAndGeneratedType_FAST_INIT_MODE_test.OuterType_B_MembersInjector
@@ -39,4 +39,5 @@
public static void injectA(Object instance, Object a) {
((OuterType.B) instance).a = (OuterType.A) a;
}
-}
\ No newline at end of file
+}
+
diff --git a/javatests/dagger/internal/codegen/goldens/embersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector b/javatests/dagger/internal/codegen/goldens/embersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector
deleted file mode 100644
index 479cf07..0000000
--- a/javatests/dagger/internal/codegen/goldens/embersInjectionTest_injectConstructorAndMembersInjection_DEFAULT_MODE_test.AllInjections_MembersInjector
+++ /dev/null
@@ -1,52 +0,0 @@
-package test;
-
-import dagger.MembersInjector;
-import dagger.internal.DaggerGenerated;
-import dagger.internal.InjectedFieldSignature;
-import dagger.internal.QualifierMetadata;
-import javax.annotation.processing.Generated;
-import javax.inject.Provider;
-
-@QualifierMetadata
-@DaggerGenerated
-@Generated(
- value = "dagger.internal.codegen.ComponentProcessor",
- comments = "https://dagger.dev"
-)
-@SuppressWarnings({
- "unchecked",
- "rawtypes",
- "KotlinInternal",
- "KotlinInternalInJava"
-})
-public final class AllInjections_MembersInjector implements MembersInjector<AllInjections> {
- private final Provider<String> sProvider;
-
- private final Provider<String> sProvider2;
-
- public AllInjections_MembersInjector(Provider<String> sProvider, Provider<String> sProvider2) {
- this.sProvider = sProvider;
- this.sProvider2 = sProvider2;
- }
-
- public static MembersInjector<AllInjections> create(Provider<String> sProvider,
- Provider<String> sProvider2) {
- return new AllInjections_MembersInjector(sProvider, sProvider2);
- }
-
- @Override
- public void injectMembers(AllInjections instance) {
- injectS(instance, sProvider.get());
- injectS2(instance, sProvider2.get());
- }
-
- @InjectedFieldSignature("test.AllInjections.s")
- public static void injectS(Object instance, String s) {
- ((AllInjections) instance).s = s;
- }
-
- public static void injectS2(Object instance, String s) {
- ((AllInjections) instance).s(s);
- }
-}
-
diff --git a/javatests/dagger/internal/codegen/kotlin/BUILD b/javatests/dagger/internal/codegen/kotlin/BUILD
index 0c217ab..f84b559 100644
--- a/javatests/dagger/internal/codegen/kotlin/BUILD
+++ b/javatests/dagger/internal/codegen/kotlin/BUILD
@@ -48,36 +48,6 @@
)
kt_compiler_test(
- name = "KspDescriptorTest",
- srcs = ["KspDescriptorTest.java"],
- compiler_deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen:package_info",
- "//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/bindinggraphvalidation",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/codegen/writing",
- "//java/dagger/model/testing",
- "//java/dagger/producers",
- "//java/dagger/spi",
- ],
- deps = [
- "//java/dagger/internal/codegen:package_info",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/xprocessing",
- "//java/dagger/internal/codegen/xprocessing:xprocessing-testing",
- "//third_party/java/guava/collect",
- "//third_party/java/junit",
- "//third_party/java/truth",
- ],
-)
-
-kt_compiler_test(
name = "ComponentValidationKtTest",
srcs = ["ComponentValidationKtTest.java"],
compiler_deps = [
diff --git a/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java b/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java
index 56ecdaf..cc4f5a1 100644
--- a/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/kotlin/KspComponentProcessorTest.java
@@ -93,6 +93,34 @@
}
@Test
+ public void
+ testComponentReferencingGeneratedTypeInCompanionObject_successfullyGeneratedComponent()
+ throws Exception {
+ Source componentSrc =
+ CompilerTests.kotlinSource(
+ "MyComponent.kt",
+ "package test",
+ "",
+ "import dagger.BindsInstance",
+ "import dagger.Component",
+ "",
+ "@Component",
+ "interface MyComponent {",
+ " @Component.Builder",
+ " interface Builder {",
+ " @BindsInstance fun text(text: String): Builder",
+ " fun build(): MyComponent",
+ " }",
+ "",
+ " companion object {",
+ " fun getComponent(text: String) = DaggerMyComponent.builder().text(text).build()",
+ " }",
+ "}");
+
+ CompilerTests.daggerCompiler(componentSrc).compile(subject -> subject.hasErrorCount(0));
+ }
+
+ @Test
public void injectBindingComponentTest() throws Exception {
Source componentSrc =
CompilerTests.kotlinSource(
diff --git a/javatests/dagger/internal/codegen/kotlin/KspDescriptorTest.java b/javatests/dagger/internal/codegen/kotlin/KspDescriptorTest.java
deleted file mode 100644
index d2ce2dc..0000000
--- a/javatests/dagger/internal/codegen/kotlin/KspDescriptorTest.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2022 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.kotlin;
-
-import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import androidx.room.compiler.processing.XFieldElement;
-import androidx.room.compiler.processing.XMethodElement;
-import androidx.room.compiler.processing.util.Source;
-import androidx.room.compiler.processing.util.XTestInvocation;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.xprocessing.XElements;
-import dagger.testing.compile.CompilerTests;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class KspDescriptorTest {
- private static final Source describeAnnotationSrc =
- Source.Companion.kotlin(
- "Describe.kt",
- String.join(
- "\n",
- "package test",
- "",
- "import kotlin.annotation.Target",
- "import kotlin.annotation.AnnotationTarget.FIELD",
- "import kotlin.annotation.AnnotationTarget.FUNCTION",
- "",
- "@Target(FIELD, FUNCTION)",
- "annotation class Describe"));
-
- @Test
- public void testFieldDescriptor() {
- Source dummySrc =
- CompilerTests.kotlinSource(
- "DummyClass.kt",
- "package test",
- "",
- "class DummyClass {",
- " @Describe val field1: Int = 0",
- " @Describe val field2: String = \"\"",
- " @Describe val field3: List<String> = listOf()",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getFieldDescriptor(invocation))
- .containsExactly(
- "field1:I", "field2:Lkotlin/String;", "field3:Lkotlin/collections/List;");
- } else {
- assertThat(getFieldDescriptor(invocation))
- .containsExactly(
- "field1:I", "field2:Ljava/lang/String;", "field3:Ljava/util/List;");
- }
- });
- }
-
- @Test
- public void testFieldDescriptorWithJavaSource() {
- Source dummySrc =
- CompilerTests.javaSource(
- "test.DummyClass",
- "package test;",
- "",
- "import java.util.List;",
- "",
- "class DummyClass {",
- " @Describe int field1;",
- " @Describe String field2;",
- " @Describe List<String> field3;",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getFieldDescriptor(invocation))
- .containsExactly(
- "field1:I",
- "field2:Lkotlin/String;",
- "field3:Lkotlin/collections/MutableList;");
- } else {
- assertThat(getFieldDescriptor(invocation))
- .containsExactly(
- "field1:I", "field2:Ljava/lang/String;", "field3:Ljava/util/List;");
- }
- });
- }
-
- @Test
- public void testMethodDescriptor() {
- Source dummySrc =
- CompilerTests.kotlinSource(
- "DummyClass.kt",
- "package test;",
- "",
- "class DummyClass {",
- " @Describe fun method1() {}",
- " @Describe fun method2(yesOrNo: Boolean, number: Int) {}",
- " @Describe fun method3(letter: Char) {}",
- " @Describe fun method4(realNumber1: Double, realNumber2: Float) {}",
- " @Describe fun method5(bigNumber1: Long, littleNumber: Short) {}",
- " @Describe fun method6(somthing: Any) {}",
- " @Describe fun method7(): Any? = null",
- " @Describe fun method8(): Map<String, Any> = mapOf()",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1()V",
- "method2(ZI)V",
- "method3(C)V",
- "method4(DF)V",
- "method5(JS)V",
- "method6(Lkotlin/Any;)V",
- "method7()Lkotlin/Any;",
- "method8()Lkotlin/collections/Map;");
- } else {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1()V",
- "method2(ZI)V",
- "method3(C)V",
- "method4(DF)V",
- "method5(JS)V",
- "method6(Ljava/lang/Object;)V",
- "method7()Ljava/lang/Object;",
- "method8()Ljava/util/Map;");
- }
- });
- }
-
- @Test
- public void methodDescriptorWithJavaSource() {
- Source dummySrc =
- CompilerTests.javaSource(
- "test.DummyClass",
- "package test;",
- "",
- "import java.util.ArrayList;",
- "import java.util.List;",
- "import java.util.Map;",
- "",
- "class DummyClass {",
- " @Describe void method1() {}",
- " @Describe void method2(boolean yesOrNo, int number) {}",
- " @Describe void method3(char letter) {}",
- " @Describe void method4(double realNumber1, float realNumber2) {}",
- " @Describe void method5(long bigNumber1, short littleNumber) {}",
- " @Describe void method6(Object somthing) {}",
- " @Describe Object method7() { return null; }",
- " @Describe List<String> method8(ArrayList<Integer> list) { return null; }",
- " @Describe Map<String, Object> method9() { return null; }",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1()V",
- "method2(ZI)V",
- "method3(C)V",
- "method4(DF)V",
- "method5(JS)V",
- "method6(Lkotlin/Any;)V",
- "method7()Lkotlin/Any;",
- "method8(Ljava/util/ArrayList;)Lkotlin/collections/MutableList;",
- "method9()Lkotlin/collections/MutableMap;");
- } else {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1()V",
- "method2(ZI)V",
- "method3(C)V",
- "method4(DF)V",
- "method5(JS)V",
- "method6(Ljava/lang/Object;)V",
- "method7()Ljava/lang/Object;",
- "method8(Ljava/util/ArrayList;)Ljava/util/List;",
- "method9()Ljava/util/Map;");
- }
- });
- }
-
- @Test
- public void testArraysMethodDescriptor() {
- Source customClassSrc =
- CompilerTests.kotlinSource("CustomClass.kt", "package test", "class CustomClass {}");
-
- Source dummySrc =
- CompilerTests.kotlinSource(
- "DummyClass.kt",
- "package test",
- "",
- "class DummyClass {",
- " @Describe fun method1(param: Array<CustomClass>) {}",
- " @Describe fun method2(): Array<CustomClass> = arrayOf()",
- " @Describe fun method3(param: Array<Int>) {}",
- "}");
-
- CompilerTests.invocationCompiler(customClassSrc, dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1([Ltest/CustomClass;)V",
- "method2()[Ltest/CustomClass;",
- "method3([Lkotlin/Int;)V");
- } else {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1([Ltest/CustomClass;)V",
- "method2()[Ltest/CustomClass;",
- "method3([Ljava/lang/Integer;)V");
- }
- });
- }
-
- @Test
- public void testArraysMethodDescriptorJavaSource() {
- Source customClassSrc =
- CompilerTests.kotlinSource("CustomClass.kt", "package test", "class CustomClass {}");
-
- Source dummySrc =
- CompilerTests.javaSource(
- "test.DummyClass",
- "package test;",
- "",
- "class DummyClass {",
- " @Describe void method1(CustomClass [] param) {}",
- " @Describe CustomClass[] method2() { return null; }",
- " @Describe void method3(int[] array) {}",
- " @Describe void method4(int... array) {}",
- "}");
-
- CompilerTests.invocationCompiler(customClassSrc, dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1([Ltest/CustomClass;)V",
- "method2()[Ltest/CustomClass;",
- "method3([I)V",
- "method4([I)V");
- } else {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1([Ltest/CustomClass;)V",
- "method2()[Ltest/CustomClass;",
- "method3([I)V",
- "method4([I)V");
- }
- });
- }
-
- @Test
- public void testInnerClassMethodDescriptorJavaSource() {
- Source customClassSrc =
- CompilerTests.javaSource(
- "test.CustomClass",
- "package test;",
- "",
- "public class CustomClass {",
- " class InnerData {}",
- " static class StaticInnerData {}",
- " enum EnumData { VALUE1, VALUE2 }",
- "}");
-
- Source dummySrc =
- CompilerTests.javaSource(
- "test.DummyClass",
- "package test;",
- "",
- "class DummyClass {",
- " @Describe void method1(CustomClass.InnerData data) {}",
- " @Describe void method2(CustomClass.StaticInnerData data) {}",
- " @Describe void method3(CustomClass.EnumData data) {}",
- " @Describe CustomClass.StaticInnerData method4() { return null; }",
- "}");
-
- CompilerTests.invocationCompiler(customClassSrc, dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1(Ltest/CustomClass$InnerData;)V",
- "method2(Ltest/CustomClass$StaticInnerData;)V",
- "method3(Ltest/CustomClass$EnumData;)V",
- "method4()Ltest/CustomClass$StaticInnerData;");
- });
- }
-
- @Test
- public void testNestedFieldDescriptor() {
- Source dummySrc =
- CompilerTests.kotlinSource(
- "DummyClass.kt",
- "package test",
- "",
- "class DummyClass {",
- " class Nested1 {",
- " class Nested2 {",
- " @Describe val field1: DummyClass? = null",
- " @Describe val field2: Nested2? = null",
- " }",
- " }",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- if (invocation.isKsp()) {
- assertThat(getFieldDescriptor(invocation))
- .containsExactly(
- "field1:Ltest/DummyClass;", "field2:Ltest/DummyClass$Nested1$Nested2;");
- } else {
- assertThat(getFieldDescriptor(invocation))
- .containsExactly(
- "field1:Ltest/DummyClass;", "field2:Ltest/DummyClass$Nested1$Nested2;");
- }
- });
- }
-
- @Test
- public void testGenericTypeMethodDescriptor() {
- Source dummySrc =
- CompilerTests.kotlinSource(
- "DummyClass.kt",
- "package test",
- "",
- "public class DummyClass<T> {",
- " @Describe fun method1(something: T) {}",
- " @Describe fun method2(): T? = null",
- " @Describe fun <O : String> method3(): List<O> = listOf()",
- " @Describe fun method4(): Map<T, String> = mapOf()",
- " @Describe fun method5(): List<Map<String, T>> = listOf()",
- " @Describe fun <I, O : I> method6(input: I): O? = null",
- " @Describe fun <I, O : String> method7(input: I): O? = null",
- " @Describe fun <P> method8(): P? where P : Collection<String>, P : Comparable<String> "
- + " = null",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- // TODO(b/231169600): Add ksp test when generic type is supported.
- if (!invocation.isKsp()) {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1(Ljava/lang/Object;)V",
- "method2()Ljava/lang/Object;",
- "method3()Ljava/util/List;",
- "method4()Ljava/util/Map;",
- "method5()Ljava/util/List;",
- "method6(Ljava/lang/Object;)Ljava/lang/Object;",
- "method7(Ljava/lang/Object;)Ljava/lang/String;",
- "method8()Ljava/util/Collection;");
- }
- });
- }
-
- @Test
- public void testGenericTypeMethodDescriptorWithJavaSource() {
- Source dummySrc =
- CompilerTests.javaSource(
- "test.DummyClass",
- "package test;",
- "",
- "import java.util.ArrayList;",
- "import java.util.Collection;",
- "import java.util.List;",
- "import java.util.Map;",
- "import java.util.Set;",
- "",
- "public class DummyClass<T> {",
- " @Describe void method1(T something) {}",
- " @Describe T method2() { return null; }",
- " @Describe List<? extends String> method3() { return null; }",
- " @Describe Map<T, String> method4() { return null; }",
- " @Describe ArrayList<Map<String, T>> method5() { return null; }",
- " @Describe <I, O extends I> O method6(I input) { return null; }",
- " @Describe static <I, O extends String> O method7(I input) { return null; }",
- " @Describe static <P extends Collection<String> & Comparable<String>> P method8() {"
- + " return null; }",
- " @Describe static <P extends String & List<Character>> P method9() { return null; }",
- "}");
-
- CompilerTests.invocationCompiler(dummySrc, describeAnnotationSrc)
- .compile(
- invocation -> {
- // TODO(b/231169600): Add ksp test when generic type is supported.
- if (!invocation.isKsp()) {
- assertThat(getMethodDescriptor(invocation))
- .containsExactly(
- "method1(Ljava/lang/Object;)V",
- "method2()Ljava/lang/Object;",
- "method3()Ljava/util/List;",
- "method4()Ljava/util/Map;",
- "method5()Ljava/util/ArrayList;",
- "method6(Ljava/lang/Object;)Ljava/lang/Object;",
- "method7(Ljava/lang/Object;)Ljava/lang/String;",
- "method8()Ljava/util/Collection;",
- "method9()Ljava/lang/String;");
- }
- });
- }
-
- private ImmutableSet<String> getFieldDescriptor(XTestInvocation invocation) {
- return invocation.getRoundEnv().getElementsAnnotatedWith("test.Describe").stream()
- .filter(element -> element instanceof XFieldElement)
- .map(element -> XElements.getFieldDescriptor((XFieldElement) element))
- .collect(toImmutableSet());
- }
-
- private ImmutableSet<String> getMethodDescriptor(XTestInvocation invocation) {
- return invocation.getRoundEnv().getElementsAnnotatedWith("test.Describe").stream()
- .filter(element -> element instanceof XMethodElement)
- .map(element -> XElements.getMethodDescriptor((XMethodElement) element))
- .collect(toImmutableSet());
- }
-}
diff --git a/resources/META-INF/services/javax.annotation.processing.Processor b/resources/META-INF/services/javax.annotation.processing.Processor
deleted file mode 100644
index 069807e..0000000
--- a/resources/META-INF/services/javax.annotation.processing.Processor
+++ /dev/null
@@ -1 +0,0 @@
-dagger.internal.codegen.ComponentProcessor
diff --git a/test_defs.bzl b/test_defs.bzl
index 2046778..467f4e9 100644
--- a/test_defs.bzl
+++ b/test_defs.bzl
@@ -31,6 +31,7 @@
"Shards": ["-Adagger.keysPerComponentShard=2"],
"FastInit": ["-Adagger.fastInit=enabled"],
"FastInit_Shards": ["-Adagger.fastInit=enabled", "-Adagger.keysPerComponentShard=2"],
+ "IgnoreProvisionKeyWildcards": ["-Adagger.ignoreProvisionKeyWildcards=enabled"],
}
def GenKtLibrary(
diff --git a/third_party/kotlin/build_extensions/BUILD b/third_party/kotlin/build_extensions/BUILD
new file mode 100644
index 0000000..8c46830
--- /dev/null
+++ b/third_party/kotlin/build_extensions/BUILD
@@ -0,0 +1,18 @@
+# Copyright (C) 2023 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Description:
+# Build extension helpers for Kotlin.
+
+package(default_visibility = ["//:src"])
diff --git a/third_party/kotlin/build_extensions/rules.bzl b/third_party/kotlin/build_extensions/rules.bzl
new file mode 100644
index 0000000..f1d9b7c
--- /dev/null
+++ b/third_party/kotlin/build_extensions/rules.bzl
@@ -0,0 +1,20 @@
+# Copyright (C) 2023 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Convenience wrapper for kt_android_library."""
+
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", io_kt_android_library = "kt_android_library")
+
+def kt_android_library(**kwargs):
+ io_kt_android_library(**kwargs)
diff --git a/tools/bazel_compat.bzl b/tools/bazel_compat.bzl
index e9354da..bc8b04a 100644
--- a/tools/bazel_compat.bzl
+++ b/tools/bazel_compat.bzl
@@ -15,7 +15,7 @@
"""Macros for building with Bazel.
"""
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_android_library")
+load("//third_party/kotlin/build_extensions:rules.bzl", "kt_android_library")
def compat_kt_android_library(name, **kwargs):
bazel_kt_android_library(name, kwargs)
diff --git a/tools/maven.bzl b/tools/maven.bzl
index f842c88..bc76386 100644
--- a/tools/maven.bzl
+++ b/tools/maven.bzl
@@ -20,6 +20,11 @@
load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
load("@google_bazel_common//tools/jarjar:jarjar.bzl", "jarjar_library")
+SHADED_MAVEN_DEPS = [
+ "com.google.auto:auto-common",
+ "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
+]
+
def pom_file(name, targets, artifact_name, artifact_id, packaging = None, **kwargs):
default_pom_file(
name = name,
@@ -34,7 +39,12 @@
"{artifact_id}": artifact_id,
"{packaging}": packaging or "jar",
},
- excluded_artifacts = ["com.google.auto:auto-common"],
+ # NOTE: The shaded maven dependencies are excluded from every Dagger pom file.
+ # Thus, if a Dagger artifact needs the dependencies it must jarjar the dependency
+ # into the artifact itself using the gen_maven_artifact.shaded_deps or get it from
+ # a transitive Dagger artifact as a dependency. In addition, the artifact must add
+ # the shade rules in the deploy scripts, e.g. deploy-dagger.sh.
+ excluded_artifacts = SHADED_MAVEN_DEPS,
**kwargs
)
@@ -54,7 +64,6 @@
javadoc_exclude_packages = None,
javadoc_android_api_level = None,
shaded_deps = None,
- shaded_rules = None,
manifest = None,
lint_deps = None,
proguard_specs = None):
@@ -282,7 +291,8 @@
actual_maven_deps = [_strip_artifact_version(artifact) for artifact in maven_nearest_artifacts]
_validate_list(
"artifact_target_maven_deps",
- actual_maven_deps,
+ # Exclude shaded maven deps from this list since they're not actual dependencies.
+ [dep for dep in actual_maven_deps if dep not in SHADED_MAVEN_DEPS],
expected_maven_deps,
ctx.attr.banned_maven_deps,
)
diff --git a/tools/shader/build.gradle b/tools/shader/build.gradle
index aa9ba79..51218ba 100644
--- a/tools/shader/build.gradle
+++ b/tools/shader/build.gradle
@@ -84,6 +84,9 @@
}
shadowJar {
+ // This transform is needed so that services get relocated/shaded as well.
+ mergeServiceFiles()
+
archiveClassifier = "" // postfix for output jar
configurations = [project.configurations.shaded]
transform(ManifestMerger.class)
diff --git a/util/deploy-dagger.sh b/util/deploy-dagger.sh
index 7f59b46..9249b91 100755
--- a/util/deploy-dagger.sh
+++ b/util/deploy-dagger.sh
@@ -51,10 +51,8 @@
gwt/libgwt.jar \
""
-# This artifact uses the shaded classes from dagger-spi, so we use the same
-# shading rules so that our references to those classes are shaded the same way.
_deploy \
- "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler,dagger.spi.shaded.androidx.room.compiler" \
+ "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler,dagger.spi.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.shaded.kotlinx.metadata;androidx.room,dagger.spi.shaded.androidx.room" \
java/dagger/internal/codegen/artifact.jar \
java/dagger/internal/codegen/pom.xml \
java/dagger/internal/codegen/artifact-src.jar \
@@ -70,7 +68,7 @@
""
_deploy \
- "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler,dagger.spi.shaded.androidx.room.compiler" \
+ "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler,dagger.spi.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.shaded.kotlinx.metadata;androidx.room,dagger.spi.shaded.androidx.room" \
java/dagger/spi/artifact.jar \
java/dagger/spi/pom.xml \
java/dagger/spi/artifact-src.jar \
diff --git a/util/deploy-hilt.sh b/util/deploy-hilt.sh
index 325ef13..cdf4b6b 100755
--- a/util/deploy-hilt.sh
+++ b/util/deploy-hilt.sh
@@ -52,7 +52,7 @@
""
_deploy \
- "com.google.auto.common,dagger.hilt.android.shaded.auto.common" \
+ "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler,dagger.spi.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.shaded.kotlinx.metadata;androidx.room,dagger.spi.shaded.androidx.room" \
java/dagger/hilt/processor/artifact.jar \
java/dagger/hilt/processor/pom.xml \
java/dagger/hilt/processor/artifact-src.jar \
@@ -60,7 +60,7 @@
""
_deploy \
- "com.google.auto.common,dagger.hilt.android.shaded.auto.common" \
+ "com.google.auto.common,dagger.spi.shaded.auto.common;androidx.room.compiler,dagger.spi.shaded.androidx.room.compiler;kotlinx.metadata,dagger.spi.shaded.kotlinx.metadata;androidx.room,dagger.spi.shaded.androidx.room" \
java/dagger/hilt/android/processor/artifact.jar \
java/dagger/hilt/android/processor/pom.xml \
java/dagger/hilt/android/processor/artifact-src.jar \
diff --git a/util/install-maven.sh b/util/install-maven.sh
new file mode 100755
index 0000000..5541cc8
--- /dev/null
+++ b/util/install-maven.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -eux
+
+function install-maven-version {
+ local VERSION=$1
+
+ if [[ ! "$VERSION" =~ ^3\. ]]; then
+ echo 'Version must begin with "3."'
+ exit 2
+ fi
+
+ pushd "$(mktemp -d)"
+ # Download the maven version
+ curl https://archive.apache.org/dist/maven/maven-3/${VERSION}/binaries/apache-maven-${VERSION}-bin.tar.gz --output apache-maven-${VERSION}-bin.tar.gz
+
+ # Unzip the contents to the /usr/share/ directory
+ sudo tar xvf apache-maven-${VERSION}-bin.tar.gz -C /usr/share/
+ popd
+
+ # Replace old symlink with new one
+ sudo unlink /usr/bin/mvn
+ sudo ln -s /usr/share/apache-maven-${VERSION}/bin/mvn /usr/bin/mvn
+}
+
+if [ $# -lt 1 ]; then
+ echo "usage $0 <version>"
+ exit 1;
+fi
+
+install-maven-version $1
+
+
diff --git a/util/latest-dagger-version.sh b/util/latest-dagger-version.sh
index ebb7a8d..305a748 100755
--- a/util/latest-dagger-version.sh
+++ b/util/latest-dagger-version.sh
@@ -4,15 +4,16 @@
function github-rest-api {
local GITHUB_REST_API=$1
-
local GITHUB_API_HEADER_ACCEPT="Accept: application/vnd.github.v3+json"
+ # Grab the GH_TOKEN or else default to an empty string.
+ local GITHUB_TOKEN="${GH_TOKEN:-}"
- if [ -z "$GH_TOKEN" ]; then
+ if [ -z "$GITHUB_TOKEN" ]; then
curl -s $GITHUB_REST_API -H $GITHUB_API_HEADER_ACCEPT
else
curl -s $GITHUB_REST_API \
-H $GITHUB_API_HEADER_ACCEPT \
- -H "authorization: Bearer $GH_TOKEN"
+ -H "authorization: Bearer $GITHUB_TOKEN"
fi
}
diff --git a/util/run-local-gradle-android-tests.sh b/util/run-local-gradle-android-tests.sh
index 23eb864..0b3a5f5 100755
--- a/util/run-local-gradle-android-tests.sh
+++ b/util/run-local-gradle-android-tests.sh
@@ -3,13 +3,24 @@
set -ex
readonly AGP_VERSION_INPUT=$1
-readonly ANDROID_GRADLE_PROJECTS=(
+readonly COMMON_GRADLE_ARGS="--no-daemon --stacktrace --configuration-cache"
+
+readonly JAVA_ANDROID_GRADLE_PROJECTS=(
"javatests/artifacts/dagger-android/simple"
"javatests/artifacts/hilt-android/simple"
+)
+for project in "${JAVA_ANDROID_GRADLE_PROJECTS[@]}"; do
+ echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --continue $COMMON_GRADLE_ARGS
+done
+
+readonly KOTLIN_ANDROID_GRADLE_PROJECTS=(
"javatests/artifacts/hilt-android/simpleKotlin"
)
-for project in "${ANDROID_GRADLE_PROJECTS[@]}"; do
+for project in "${KOTLIN_ANDROID_GRADLE_PROJECTS[@]}"; do
echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
- AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug --no-daemon --stacktrace --configuration-cache
- AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --continue --no-daemon --stacktrace --configuration-cache
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project assembleDebug $COMMON_GRADLE_ARGS
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testWithKaptDebugUnitTest --continue $COMMON_GRADLE_ARGS
+ AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testWithKspDebugUnitTest --continue $COMMON_GRADLE_ARGS
done
diff --git a/util/run-local-gradle-tests.sh b/util/run-local-gradle-tests.sh
index ecbbd35..bb0c458 100755
--- a/util/run-local-gradle-tests.sh
+++ b/util/run-local-gradle-tests.sh
@@ -4,6 +4,7 @@
readonly GRADLE_PROJECTS=(
"javatests/artifacts/dagger"
+ "javatests/artifacts/dagger-ksp"
"javatests/artifacts/hilt-android/pluginMarker"
)
for project in "${GRADLE_PROJECTS[@]}"; do