Snap for 8426163 from 678a3d564813c41376a7ed56ac4e63acf4043346 to mainline-tzdata2-release
Change-Id: I44a728fa343eaf8f7c8cae20bc914145768678eb
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 328d4b1..0000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,214 +0,0 @@
-name: CI
-
-on:
- push:
- branches:
- - master
- pull_request:
-
-jobs:
- bazel-test:
- name: 'Bazel tests'
- runs-on: ubuntu-latest
- steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache local Maven repository'
- uses: actions/cache@v2
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/google/dagger
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
- - name: 'Cache Bazel files'
- uses: actions/cache@v2
- with:
- path: ~/.cache/bazel
- key: ${{ runner.os }}-bazel-${{ github.sha }}
- restore-keys: |
- ${{ runner.os }}-bazel-
- - name: 'Cache Gradle files'
- 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
- - name: 'Install local snapshot'
- run: ./util/install-local-snapshot.sh
- shell: bash
- - name: 'Upload local snapshot for tests'
- uses: actions/upload-artifact@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- artifact-java-local-tests:
- name: 'Artifact Java local tests'
- needs: bazel-test
- runs-on: ubuntu-latest
- steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- 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@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Java local tests'
- run: ./util/run-local-gradle-tests.sh
- shell: bash
- artifact-android-local-tests:
- name: 'Artifact Android local tests (AGP ${{ matrix.agp }})'
- needs: bazel-test
- runs-on: ubuntu-latest
- strategy:
- matrix:
- agp: ['4.1.0', '4.2.0-beta04']
- steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- 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@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Android local tests (AGP ${{ matrix.agp }})'
- run: ./util/run-local-gradle-android-tests.sh "${{ matrix.agp }}"
- shell: bash
- artifact-android-emulator-tests:
- name: 'Artifact Android emulator tests (API 30)'
- needs: bazel-test
- # It's recommended to run emulator tests on macOS
- # See https://github.com/marketplace/actions/android-emulator-runner
- runs-on: macos-latest
- steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- 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@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Android emulator tests (API 30)'
- uses: reactivecircus/android-emulator-runner@v2
- timeout-minutes: 25
- with:
- api-level: 30
- target: google_apis
- script: ./util/run-local-emulator-tests.sh
- publish-snapshot:
- name: 'Publish snapshot'
- # TODO(bcorso): Consider also waiting on artifact-android-emulator-tests
- # and artifact-android-emulator-legacy-api-tests after checking flakiness.
- needs: [bazel-test, artifact-java-local-tests, artifact-android-local-tests]
- if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master'
- runs-on: ubuntu-latest
- steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache local Maven repository'
- uses: actions/cache@v2
- with:
- path: |
- ~/.m2/repository
- !~/.m2/repository/com/google/dagger
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
- - name: 'Cache Bazel files'
- uses: actions/cache@v2
- with:
- path: ~/.cache/bazel
- key: ${{ runner.os }}-bazel-${{ github.sha }}
- restore-keys: |
- ${{ runner.os }}-bazel-
- - name: 'Cache Gradle files'
- 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: 'Publish latest docs'
- run: ./util/generate-latest-docs.sh
- shell: bash
- env:
- GH_TOKEN: ${{ github.token }}
- - name: 'Publish latest snapshot'
- run: ./util/publish-snapshot-on-commit.sh
- shell: bash
- env:
- CI_DEPLOY_USERNAME: ${{ secrets.CI_DEPLOY_USERNAME }}
- CI_DEPLOY_PASSWORD: ${{ secrets.CI_DEPLOY_PASSWORD }}
- artifact-android-emulator-legacy-api-tests:
- name: 'Artifact Android emulator tests (API ${{ matrix.api-level }})'
- # We only run this on master push (essentially a postsubmit) since these
- # can take a while to run
- if: github.event_name == 'push' && github.repository == 'google/dagger' && github.ref == 'refs/heads/master'
- needs: bazel-test
- # It's recommended to run emulator tests on macOS
- # See https://github.com/marketplace/actions/android-emulator-runner
- runs-on: macos-latest
- strategy:
- matrix:
- api-level: [16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 29]
- steps:
- - name: 'Check out repository'
- uses: actions/checkout@v2
- - name: 'Cache Gradle files'
- 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@v2
- with:
- name: local-snapshot
- path: ~/.m2/repository/com/google/dagger
- - name: 'Gradle Android emulator tests (API ${{ matrix.api-level }})'
- uses: reactivecircus/android-emulator-runner@v2
- timeout-minutes: 25
- with:
- api-level: ${{ matrix.api-level }}
- target: google_apis
- script: ./util/run-local-emulator-tests.sh
diff --git a/.gitignore b/.gitignore
index 1f7ead8..fabb38f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,8 +30,6 @@
gen-external-apklibs
-bazel-*
+/bazel-*
*.pyc
-
-.gradle
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9015f2e
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,65 @@
+language: android
+
+os: linux
+dist: trusty
+sudo: required
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - libstdc++-4.9-dev # https://github.com/nodegit/nodegit/issues/853
+ - gcc-4.8
+ - g++-4.8
+
+jdk:
+ - &jdk_for_publishing oraclejdk8
+
+android:
+ components:
+ - tools
+ - tools # Duplicated as per https://github.com/travis-ci/travis-ci/issues/6040#issuecomment-219367943
+ - build-tools-26.0.2
+ - android-26
+ - platform-tools
+ - extra-android-m2repository
+
+before_install:
+ - wget https://github.com/bazelbuild/bazel/releases/download/"${BAZEL_VERSION}"/bazel_"${BAZEL_VERSION}"-linux-x86_64.deb
+ - sudo dpkg -i bazel_"${BAZEL_VERSION}"-linux-x86_64.deb
+ - sudo rm -f /etc/mavenrc
+ - wget http://www.us.apache.org/dist/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz
+ - tar -zxf apache-maven-3.1.1-bin.tar.gz
+ - export PATH="$PWD/apache-maven-3.1.1/bin:$PATH"
+ - mkdir travis_bin
+ - ln -s $(which gcc-4.8) travis_bin/gcc
+ - ln -s $(which g++-4.8) travis_bin/g++
+ - export PATH="${PWD}/travis_bin:${PATH}"
+
+script:
+ - bazel test --test_output errors //...
+ - pushd examples && mvn compile && popd
+
+env:
+ global:
+ # Encrypted credentials for deploying snapshots.
+ - secure: eGc3LHBRIPmTnXLM1YoIqG1do9BkpFI2pJm3fz5Cd8UaXtf7Oefa+Ts3rcn4ipee5A+lf8kEouPshSoaQs81KZ2/qf8rSTCIqeFjHR8hzmOVYo/0zRfS/VSUT0yqN+jeRhuNk3+A49RTPlcfJqPv3tyddtrM1vF7axhCJPQIRJM=
+ - secure: LTzrlqcSNeZTOV52D3ibY9RBdxY4Yu8dUOYhAonrWLE+eDTzuoyCzcPw8pEcYVNUi1rG6Q7v3QBDTnBztsPoCbcN5tEGjw5cQEbfEzSTkWaNCFjncWn36cLwx9lgbF+5Db/L0mYJ36unDKUpKVC8AgOtxQibfv/ffugfxxj8ohY=
+
+ # Encrypted GitHub access token to allow util/generate-latest-docs.sh to
+ # push Javadoc to gh-pages.
+ # This uses an access token created by cgdecker and will need to be updated
+ # (see util/generate-latest-docs.sh for a link) if he no longer has
+ # permission to push to the repo.
+ - secure: "UpTUhCQzAGbr5JetRg2GZxp/dPDep/7Il3yGeyDECopciWdx41OPk/QNqAXBhNtKuEaMVsmASyoteuhgaTryQdV4qUIGVOMhES6kbOlYy3nwK44VdsNeeepwVospyDyZbxMtXq5LuHWuTADmAl1mdjNPNoziXc523zjnUzUx/EQ="
+ - JDK_FOR_PUBLISHING: *jdk_for_publishing
+ - BAZEL_VERSION="0.24.1"
+
+after_success:
+ - util/generate-latest-docs.sh
+ - util/publish-snapshot-on-commit.sh
+
+branches:
+ only:
+ - master
+ - /^release.*$/
diff --git a/Android.bp b/Android.bp
index 1bdbd1b..27a05c5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,46 +12,87 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package {
- default_visibility: [":__subpackages__"],
- default_applicable_licenses: ["external_dagger2_license"],
+java_import_host {
+ name: "dagger2-auto-common",
+ jars: ["lib/auto-common-0.10.jar"],
}
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-//
-// large-scale-change included anything that looked like it might be a license
-// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
-//
-// Please consider removing redundant or irrelevant files from 'license_text:'.
-// See: http://go/android-license-faq
-license {
- name: "external_dagger2_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- "legacy_not_a_contribution",
- ],
- license_text: [
- "LICENSE.txt",
- "NOTICE",
+java_import_host {
+ name: "dagger2-auto-factory-jar",
+ jars: ["lib/auto-factory-1.0-beta6.jar"],
+}
+
+java_plugin {
+ name: "dagger2-auto-factory",
+ processor_class: "com.google.auto.factory.processor.AutoFactoryProcessor",
+ static_libs: [
+ "dagger2-auto-factory-jar",
+ "dagger2-auto-common",
+ "guava",
+ "javapoet",
+ "dagger2-google-java-format",
],
}
java_import_host {
+ name: "dagger2-auto-service-jar",
+ jars: ["lib/auto-service-1.0-rc5.jar"],
+}
+
+java_import_host {
+ name: "dagger2-auto-service-annotations",
+ jars: ["lib/auto-service-annotations-1.0-rc5.jar"],
+}
+
+java_plugin {
+ name: "dagger2-auto-service",
+ processor_class: "com.google.auto.service.processor.AutoServiceProcessor",
+ static_libs: [
+ "dagger2-auto-common",
+ "dagger2-auto-service-jar",
+ "dagger2-auto-service-annotations",
+ "guava",
+ ],
+}
+
+java_import_host {
+ name: "dagger2-auto-value-jar",
+ jars: ["lib/auto-value-1.6.5.jar"],
+}
+
+java_import_host {
+ name: "dagger2-auto-value-annotations",
+ jars: ["lib/auto-value-annotations-1.6.5.jar"],
+}
+
+java_plugin {
+ name: "dagger2-auto-value",
+ processor_class: "com.google.auto.value.processor.AutoValueProcessor",
+ static_libs: [
+ "dagger2-auto-value-jar",
+ "dagger2-auto-value-annotations",
+ ],
+}
+
+java_plugin {
+ name: "dagger2-auto-annotation",
+ processor_class: "com.google.auto.value.processor.AutoAnnotationProcessor",
+ static_libs: ["dagger2-auto-value-jar"],
+}
+
+java_import_host {
+ name: "dagger2-google-java-format",
+ jars: ["lib/google-java-format-1.7-all-deps.jar"],
+}
+
+java_import_host {
+ name: "dagger2-inject",
+ jars: ["lib/javax.inject-1.jar"],
+}
+
+java_import_host {
name: "dagger2-bootstrap-compiler-jar",
- jars: ["java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar"],
+ jars: ["java/dagger/internal/codegen/bootstrap_compiler_deploy.jar"],
}
java_plugin {
@@ -59,42 +100,36 @@
processor_class: "dagger.internal.codegen.ComponentProcessor",
generates_api: true,
static_libs: ["dagger2-bootstrap-compiler-jar"],
- jarjar_rules: "jarjar-rules.txt",
}
-java_library {
+java_library_host {
name: "dagger2",
- visibility: ["//visibility:public"],
- host_supported: true,
srcs: [
"java/dagger/*.java",
- "java/dagger/assisted/*.java",
"java/dagger/internal/*.java",
"java/dagger/multibindings/*.java",
"java/dagger/releasablereferences/*.java",
],
exclude_srcs: ["java/dagger/android/**/*.java"],
- libs: [
- "guava",
- "jsr330",
- ],
+ static_libs: ["dagger2-inject"],
+
+ libs: ["guava"],
java_version: "1.8",
- sdk_version: "core_current",
}
// build dagger2 producers library
// ============================================================
-java_library {
+java_library_host {
name: "dagger2-producers",
- host_supported: true,
srcs: ["java/dagger/producers/**/*.java"],
static_libs: [
+ "dagger2-inject",
"error_prone_annotations",
],
@@ -102,11 +137,9 @@
"dagger2",
"dagger2-android-annotation-stubs",
"guava",
- "jsr330",
],
java_version: "1.8",
- sdk_version: "core_current",
}
// build dagger2 compiler plugin
@@ -114,16 +147,8 @@
java_plugin {
name: "dagger2-compiler",
- visibility: ["//visibility:public"],
processor_class: "dagger.internal.codegen.ComponentProcessor",
generates_api: true,
- static_libs: ["dagger2-compiler-lib"],
- // shade guava to avoid conflicts with guava embedded in Error Prone.
- jarjar_rules: "jarjar-rules.txt",
-}
-
-java_library_host {
- name: "dagger2-compiler-lib",
use_tools_jar: true,
srcs: [
@@ -136,7 +161,7 @@
exclude_srcs: [
"java/dagger/internal/codegen/BindingGraphStatisticsCollector.java",
- "java/dagger/internal/codegen/kythe/DaggerKythePlugin.java",
+ "java/dagger/internal/codegen/DaggerKythePlugin.java",
],
// Manually include META-INF/services/javax.annotation.processing.Processor
@@ -144,32 +169,30 @@
java_resource_dirs: ["resources"],
static_libs: [
- "auto_common",
"dagger2",
+ "dagger2-auto-common",
+ "dagger2-auto-factory",
+ "dagger2-auto-service",
+ "dagger2-auto-value",
+ "dagger2-google-java-format",
+ "dagger2-inject",
"dagger2-producers",
- "google_java_format",
"guava",
"javapoet",
- "jsr330",
- "kotlin-stdlib",
- "kotlinx_metadata_jvm",
],
+ // shade guava to avoid conflicts with guava embedded in Error Prone.
+ jarjar_rules: "jarjar-rules.txt",
libs: [
- "auto_factory_annotations",
- "auto_service_annotations",
- "auto_value_annotations",
- "auto_value_memoized_extension_annotations",
"dagger2-android-annotation-stubs",
],
plugins: [
- "auto_factory_plugin",
- "auto_service_plugin",
- "auto_value_plugin",
- "auto_value_memoized_extension_plugin",
- "auto_annotation_plugin",
+ "dagger2-auto-factory",
+ "dagger2-auto-service",
+ "dagger2-auto-value",
+ "dagger2-auto-annotation",
"dagger2-bootstrap-compiler",
],
@@ -189,233 +212,3 @@
sdk_version: "core_current",
srcs: ["android-annotation-stubs/src/**/*.java"],
}
-
-// build core hilt library
-
-java_library {
- name: "hilt_core",
- srcs: [
- "java/dagger/hilt/*.java",
- "java/dagger/hilt/codegen/*.java",
- "java/dagger/hilt/components/*.java",
- "java/dagger/hilt/internal/*.java",
- "java/dagger/hilt/internal/aliasof/*.java",
- "java/dagger/hilt/internal/definecomponent/*.java",
- "java/dagger/hilt/internal/generatesrootinput/*.java",
- "java/dagger/hilt/migration/*.java",
- "java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDeps.java",
- ],
- static_libs: [
- "jsr305",
- "jsr330",
- "dagger2",
- ],
- sdk_version: "core_current",
- plugins: [
- "hilt_define_component_processor",
- "hilt_generates_root_input_processor",
- ],
-}
-
-// Build the android hilt library. Depending on this will enable the Hilt annotation processors.
-
-android_library {
- name: "hilt_android",
- visibility: ["//visibility:public"],
-
- srcs: [
- "java/dagger/hilt/android/*.java",
- "java/dagger/hilt/android/components/*.java",
- "java/dagger/hilt/android/migration/*.java",
- "java/dagger/hilt/android/qualifiers/*.java",
- "java/dagger/hilt/android/scopes/*.java",
- "java/dagger/hilt/android/internal/*.java",
- "java/dagger/hilt/android/internal/builders/*.java",
- "java/dagger/hilt/android/internal/lifecycle/*.java",
- "java/dagger/hilt/android/internal/managers/*.java",
- "java/dagger/hilt/android/internal/migration/*.java",
- "java/dagger/hilt/android/internal/modules/*.java",
- "java/dagger/hilt/android/lifecycle/*.java",
- ],
- manifest: "java/dagger/hilt/android/AndroidManifest.xml",
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.fragment_fragment",
- "jsr305",
- "jsr330",
- "dagger2",
- "hilt_core",
- ],
- sdk_version: "current",
- min_sdk_version: "14",
- plugins: [
- "dagger2-compiler",
- "hilt_android_entry_point_processor",
- "hilt_aggregated_deps_processor",
- "hilt_define_component_processor",
- "hilt_generates_root_input_processor",
- "hilt_originating_element_processor",
- "hilt_root_processor",
- ],
- exported_plugins: [
- "dagger2-compiler",
- "hilt_android_entry_point_processor",
- "hilt_aggregated_deps_processor",
- "hilt_alias_of_processor",
- "hilt_define_component_processor",
- "hilt_generates_root_input_processor",
- "hilt_originating_element_processor",
- "hilt_root_processor",
- "hilt_viewmodel_processor",
- ],
-}
-
-android_library {
- name: "hilt_android_testing",
- visibility: ["//visibility:public"],
-
- srcs: [
- "java/dagger/hilt/android/internal/testing/*.java",
- "java/dagger/hilt/android/testing/*.java",
- ],
- manifest: "java/dagger/hilt/android/testing/AndroidManifest.xml",
- static_libs: [
- "auto_value_annotations",
- "androidx.annotation_annotation",
- "androidx.fragment_fragment",
- "androidx.annotation_annotation",
- "androidx.fragment_fragment",
- "androidx.test.core",
- "android-support-multidex",
- "jsr305",
- "dagger2",
- "hilt_core",
- "junit",
- ],
- sdk_version: "current",
- min_sdk_version: "14",
- plugins: [
- "auto_value_plugin",
- "dagger2-compiler",
- "hilt_generates_root_input_processor",
- ],
- exported_plugins: [
- "dagger2-compiler",
- "hilt_android_entry_point_processor",
- "hilt_aggregated_deps_processor",
- "hilt_define_component_processor",
- "hilt_generates_root_input_processor",
- "hilt_originating_element_processor",
- "hilt_root_processor",
- "hilt_viewmodel_processor",
- "hilt_custom_test_application_processor",
- "hilt_bindvalue_processor",
- "hilt_uninstall_modules_processor",
- ],
-}
-
-// Hilt has many annotation processors. To reduce compilation and runtime cost, they are all compiled
-// into hilt_android_processors. A java_plugin can only expose a single processor class, so each has
-// to be defined separately. Since they are not visible outside this package and will always be
-// exported together, only the first actually contains the annotation processor classes.
-java_plugin {
- name: "hilt_generates_root_input_processor",
- generates_api: true,
- processor_class: "dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor",
- static_libs: ["hilt_android_processors"],
-}
-
-java_plugin {
- name: "hilt_android_entry_point_processor",
- generates_api: true,
- processor_class: "dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor",
-}
-
-java_plugin {
- name: "hilt_aggregated_deps_processor",
- generates_api: true,
- processor_class: "dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor",
-}
-
-java_plugin {
- name: "hilt_alias_of_processor",
- generates_api: true,
- processor_class: "dagger.hilt.processor.internal.aliasof.AliasOfProcessor",
-}
-
-java_plugin {
- name: "hilt_define_component_processor",
- generates_api: true,
- processor_class: "dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor",
-}
-
-java_plugin {
- name: "hilt_originating_element_processor",
- generates_api: true,
- processor_class: "dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor",
-}
-
-java_plugin {
- name: "hilt_root_processor",
- generates_api: true,
- processor_class: "dagger.hilt.processor.internal.root.RootProcessor",
-}
-
-java_plugin {
- name: "hilt_viewmodel_processor",
- generates_api: true,
- processor_class: "dagger.hilt.android.processor.internal.viewmodel.ViewModelProcessor",
-}
-
-// Hilt testing processors
-java_plugin {
- name: "hilt_custom_test_application_processor",
- generates_api: true,
- processor_class: "dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor",
-}
-
-java_plugin {
- name: "hilt_bindvalue_processor",
- generates_api: true,
- processor_class: "dagger.hilt.android.processor.internal.bindvalue.BindValueProcessor",
-}
-
-java_plugin {
- name: "hilt_uninstall_modules_processor",
- generates_api: true,
- processor_class: "dagger.hilt.android.processor.internal.uninstallmodules.UninstallModulesProcessor",
-}
-
-java_library_host {
- name: "hilt_android_processors",
- use_tools_jar: true,
- srcs: [
- "java/dagger/hilt/android/processor/**/*.java",
- "java/dagger/hilt/android/processor/**/*.kt",
- "java/dagger/hilt/codegen/*.java",
- "java/dagger/hilt/processor/internal/**/*.java",
- ],
- plugins: [
- "auto_service_plugin",
- "auto_value_plugin",
- "auto_value_memoized_extension_plugin",
- "dagger2-compiler",
- ],
- static_libs: [
- "auto_common",
- "auto_service_annotations",
- "auto_value_annotations",
- "auto_value_memoized_extension_annotations",
- "guava",
- "jsr305",
- "dagger2-compiler-lib",
- "dagger2",
- "javapoet",
- "jsr330",
- "kotlin-stdlib",
- "kotlinx_metadata_jvm",
- "dagger2-android-annotation-stubs",
- ],
- // shade guava to avoid conflicts with guava embedded in Error Prone.
- jarjar_rules: "jarjar-rules.txt",
-}
diff --git a/BUILD b/BUILD
index 015e849..8becb3e 100644
--- a/BUILD
+++ b/BUILD
@@ -12,25 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-load("@rules_java//java:defs.bzl", "java_library")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-load("@google_bazel_common//tools/jarjar:jarjar.bzl", "jarjar_library")
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "define_kt_toolchain")
-
package(default_visibility = ["//visibility:public"])
-define_kt_toolchain(
- name = "kotlin_toolchain",
- api_version = "1.4",
- jvm_target = "1.8",
- language_version = "1.4",
-)
-
package_group(
name = "src",
packages = ["//..."],
)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
java_library(
name = "dagger_with_compiler",
exported_plugins = ["//java/dagger/internal/codegen:component-codegen"],
@@ -45,22 +35,6 @@
],
)
-java_library(
- name = "spi",
- exports = ["//java/dagger/spi"],
-)
-
-java_library(
- name = "compiler_internals",
- exports = [
- "//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/codegen/writing",
- ],
-)
-
android_library(
name = "android",
exported_plugins = ["//java/dagger/android/processor:plugin"],
@@ -75,48 +49,118 @@
],
)
+load("@google_bazel_common//tools/jarjar:jarjar.bzl", "jarjar_library")
+
+SHADE_RULES = ["rule com.google.auto.common.** dagger.shaded.auto.common.@1"]
+
+jarjar_library(
+ name = "shaded_compiler",
+ jars = [
+ "//java/dagger/internal/codegen:base",
+ "//java/dagger/internal/codegen:binding",
+ "//java/dagger/internal/codegen:binding_graph_validation",
+ "//java/dagger/internal/codegen:jdk-and-guava-extras",
+ "//java/dagger/internal/codegen:processor",
+ "//java/dagger/internal/codegen:validation",
+ "//java/dagger/internal/codegen:writing",
+ "//java/dagger/internal/codegen/javapoet",
+ "//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/serialization",
+ "//java/dagger/model:internal-proxies",
+ "//java/dagger/errorprone",
+ "@com_google_auto_auto_common//jar",
+ ],
+ rules = SHADE_RULES,
+)
+
+jarjar_library(
+ name = "shaded_compiler_src",
+ jars = [
+ "//java/dagger/internal/codegen:libbase-src.jar",
+ "//java/dagger/internal/codegen:libbinding-src.jar",
+ "//java/dagger/internal/codegen:libbinding_graph_validation-src.jar",
+ "//java/dagger/internal/codegen:libjdk-and-guava-extras-src.jar",
+ "//java/dagger/internal/codegen:libprocessor-src.jar",
+ "//java/dagger/internal/codegen:libvalidation-src.jar",
+ "//java/dagger/internal/codegen:libwriting-src.jar",
+ "//java/dagger/internal/codegen/javapoet:libjavapoet-src.jar",
+ "//java/dagger/internal/codegen/langmodel:liblangmodel-src.jar",
+ # TODO(ronshapiro): is there a generated src.jar for protos in Bazel?
+ "//java/dagger/errorprone:liberrorprone-src.jar",
+ ],
+)
+
+jarjar_library(
+ name = "shaded_spi",
+ jars = [
+ "//java/dagger/internal/codegen:jdk-and-guava-extras",
+ "//java/dagger/model",
+ "//java/dagger/spi",
+ "@com_google_auto_auto_common//jar",
+ ],
+ rules = SHADE_RULES,
+)
+
+jarjar_library(
+ name = "shaded_spi_src",
+ jars = [
+ "//java/dagger/internal/codegen:libjdk-and-guava-extras-src.jar",
+ "//java/dagger/model:libmodel-src.jar",
+ "//java/dagger/spi:libspi-src.jar",
+ ],
+)
+
+javadoc_library(
+ name = "spi-javadoc",
+ srcs = [
+ "//java/dagger/model:model-srcs",
+ "//java/dagger/spi:spi-srcs",
+ ],
+ root_packages = [
+ "dagger.model",
+ "dagger.spi",
+ ],
+ deps = [
+ "//java/dagger/model",
+ "//java/dagger/spi",
+ ],
+)
+
jarjar_library(
name = "shaded_android_processor",
jars = [
"//java/dagger/android/processor",
- "@maven//:com_google_auto_auto_common",
+ "@com_google_auto_auto_common//jar",
],
- rules = [
- "rule com.google.auto.common.** dagger.android.shaded.auto.common.@1",
- ],
+ rules = SHADE_RULES,
)
jarjar_library(
name = "shaded_grpc_server_processor",
jars = [
"//java/dagger/grpc/server/processor",
- "@maven//:com_google_auto_auto_common",
+ "@com_google_auto_auto_common//jar",
],
- rules = [
- "rule com.google.auto.common.** dagger.grpc.shaded.auto.common.@1",
- ],
+ rules = SHADE_RULES,
)
# coalesced javadocs used for the gh-pages site
javadoc_library(
name = "user-docs",
- testonly = 1,
srcs = [
"//java/dagger:javadoc-srcs",
"//java/dagger/android:android-srcs",
"//java/dagger/android/support:support-srcs",
"//java/dagger/grpc/server:javadoc-srcs",
"//java/dagger/grpc/server/processor:javadoc-srcs",
- "//java/dagger/hilt:javadoc-srcs",
+ "//java/dagger/model:model-srcs",
"//java/dagger/producers:producers-srcs",
"//java/dagger/spi:spi-srcs",
],
- android_api_level = 30,
+ android_api_level = 26,
# TODO(ronshapiro): figure out how to specify the version number for release builds
doctitle = "Dagger Dependency Injection API",
exclude_packages = [
- "dagger.hilt.android.internal",
- "dagger.hilt.internal",
"dagger.internal",
"dagger.producers.internal",
"dagger.producers.monitoring.internal",
@@ -128,8 +172,7 @@
"//java/dagger/android/support",
"//java/dagger/grpc/server",
"//java/dagger/grpc/server/processor",
- "//java/dagger/hilt/android:artifact-lib",
- "//java/dagger/hilt/android/testing:artifact-lib",
+ "//java/dagger/model",
"//java/dagger/producers",
"//java/dagger/spi",
],
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 54fb50a..45f15c4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -33,19 +33,11 @@
* [Install Bazel](https://docs.bazel.build/versions/master/install.html)
* Build the Dagger project with `bazel build <target>`
* Learn more about Bazel targets [here][bazel targets].
- * Building Dagger's Android targets requires additional setup:
- * Set the `ANDROID_HOME` environment variable to point to a directory
- containing the Android SDK. If you do not have the Android SDK
- installed, you'll have to
- [download](https://developer.android.com/studio#command-tools)
- and unzip it first.
- * Install the necessary components. For example, under Linux, run:
- `$ANDROID_HOME/tools/bin/sdkmanager "platforms;android-30" "build-tools;30.0.2"`
- * If you skip this step, you will see an error similar to
- `ERROR: missing input file '@androidsdk//:build-tools/30.0.2/aapt'`.
- * You may also need to run `bazel sync`.
+ * If you see an error similar to `ERROR: missing input file
+ '@androidsdk//:build-tools/26.0.2/aapt'`, install the missing build
+ tools version with the android `sdkmanager` tool.
* Run tests with `bazel test <target>`, or `bazel test //...` to run all
- tests.
+ tests
* You can install the Dagger libraries in your **local maven repository** by
running the `./util/install-local-snapshot.sh` script.
* It will build the libraries and install them with a `LOCAL-SNAPSHOT`
diff --git a/METADATA b/METADATA
index 5eef5c3..59b9e25 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@
type: GIT
value: "https://github.com/google/dagger"
}
- version: "dagger-2.19.1"
- last_upgrade_date { year: 2020 month: 11 day: 18 }
- license_type: NOTICE
+ version: "dagger-2.23.1"
+ last_upgrade_date { year: 2019 month: 6 day: 14 }
+ license_type: PERMISSIVE
}
diff --git a/README.md b/README.md
index 393e2e7..a9ebc26 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,34 @@
-# Dagger
+# Dagger 2
[![Maven Central][mavenbadge-svg]][mavencentral]
-A fast dependency injector for Java and Android.
+A fast dependency injector for Android and Java.
-Dagger is a compile-time framework for dependency injection. It uses no
-reflection or runtime bytecode generation, does all its analysis at
-compile-time, and generates plain Java source code.
+## About Google's Fork
-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 2 is a compile-time evolution approach to dependency injection.
+Taking the approach started in Dagger 1.x to its ultimate conclusion,
+Dagger 2.x eliminates all reflection, and improves code clarity by
+removing the traditional ObjectGraph/Injector in favor of user-specified
+`@Component` interfaces.
+
+This github project represents the Dagger 2 development stream. The earlier
+[project page][square] (Square, Inc's repository) represents the earlier 1.0
+development stream. Both versions have benefited from strong involvement from
+Square, Google, and other contributors.
+
+Dagger is currently in active development, primarily internally at Google,
+with regular pushes to the open-source community. Snapshot releases are
+auto-deployed to sonatype's central maven repository on every clean build with
+the version `HEAD-SNAPSHOT`.
+
+> [Dagger 2's main documentation website can be found here.][website]
## Documentation
You can [find the dagger documentation here][website] which has extended usage
-instructions and other useful information. More detailed information can be
-found in the [API documentation][latestapi].
+instructions and other useful information. Substantial usage information can be
+found in the [API documentation][20api].
You can also learn more from [the original proposal][proposal],
[this talk by Greg Kick][gaktalk], and on the dagger-discuss@googlegroups.com
@@ -27,154 +38,19 @@
### Bazel
-First, import the Dagger repository into your `WORKSPACE` file using
-[`http_archive`][bazel-external-deps].
+If you build with `bazel`, follow the [`bazel` documentation for referencing
+external projects][bazel-external-deps] to include Dagger in your build.
-Note: The `http_archive` must point to a tagged release of Dagger, not just any
-commit. The version of the Dagger artifacts will match the version of the tagged
-release.
+Given the following `WORKSPACE` definition, you can reference dagger via
+`@com_google_dagger//:dagger_with_compiler` in your deps.
```python
-# Top-level WORKSPACE file
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-DAGGER_TAG = "2.28.1"
-DAGGER_SHA = "9e69ab2f9a47e0f74e71fe49098bea908c528aa02fa0c5995334447b310d0cdd"
http_archive(
- name = "dagger",
- strip_prefix = "dagger-dagger-%s" % DAGGER_TAG,
- sha256 = DAGGER_SHA,
- urls = ["https://github.com/google/dagger/archive/dagger-%s.zip" % DAGGER_TAG],
+ name = "com_google_dagger",
+ urls = ["https://github.com/google/dagger/archive/dagger-<version>.zip"],
)
```
-Next you will need to setup targets that export the proper dependencies
-and plugins. Follow the sections below to setup the dependencies you need.
-
-#### Dagger Setup
-
-First, load the Dagger artifacts and repositories, and add them to your list of
-[`maven_install`] artifacts.
-
-```python
-# Top-level WORKSPACE file
-
-load("@dagger//:workspace_defs.bzl", "DAGGER_ARTIFACTS", "DAGGER_REPOSITORIES")
-
-maven_install(
- artifacts = DAGGER_ARTIFACTS + [...],
- repositories = DAGGER_REPOSITORIES + [...],
-)
-```
-
-Next, load and call [`dagger_rules`](https://github.com/google/dagger/blob/master/workspace_defs.bzl)
-in your top-level `BUILD` file:
-
-```python
-# Top-level BUILD file
-
-load("@dagger//:workspace_defs.bzl", "dagger_rules")
-
-dagger_rules()
-```
-
-This will add the following Dagger build targets:
-(Note that these targets already export all of the dependencies and processors
-they need).
-
-```python
-deps = [
- ":dagger", # For Dagger
- ":dagger-spi", # For Dagger SPI
- ":dagger-producers", # For Dagger Producers
-]
-```
-
-#### Dagger Android Setup
-
-First, load the Dagger Android artifacts and repositories, and add them to your
-list of [`maven_install`] artifacts.
-
-```python
-# Top-level WORKSPACE file
-
-load(
- "@dagger//:workspace_defs.bzl",
- "DAGGER_ANDROID_ARTIFACTS",
- "DAGGER_ANDROID_REPOSITORIES"
-)
-
-maven_install(
- artifacts = DAGGER_ANDROID_ARTIFACTS + [...],
- repositories = DAGGER_ANDROID_REPOSITORIES + [...],
-)
-```
-
-Next, load and call [`dagger_android_rules`](https://github.com/google/dagger/blob/master/workspace_defs.bzl)
-in your top-level `BUILD` file:
-
-```python
-# Top-level BUILD file
-
-load("@dagger//:workspace_defs.bzl", "dagger_android_rules")
-
-dagger_android_rules()
-```
-
-This will add the following Dagger Android build targets:
-(Note that these targets already export all of the dependencies and processors
-they need).
-
-```python
-deps = [
- ":dagger-android", # For Dagger Android
- ":dagger-android-support", # For Dagger Android (Support)
-]
-```
-
-#### Hilt Android Setup
-
-First, load the Hilt Android artifacts and repositories, and add them to your
-list of [`maven_install`] artifacts.
-
-```python
-# Top-level WORKSPACE file
-
-load(
- "@dagger//:workspace_defs.bzl",
- "HILT_ANDROID_ARTIFACTS",
- "HILT_ANDROID_REPOSITORIES"
-)
-
-maven_install(
- artifacts = HILT_ANDROID_ARTIFACTS + [...],
- repositories = HILT_ANDROID_REPOSITORIES + [...],
-)
-```
-
-Next, load and call [`hilt_android_rules`](https://github.com/google/dagger/blob/master/workspace_defs.bzl)
-in your top-level `BUILD` file:
-
-```python
-# Top-level BUILD file
-
-load("@dagger//:workspace_defs.bzl", "hilt_android_rules")
-
-hilt_android_rules()
-```
-
-This will add the following Hilt Android build targets:
-(Note that these targets already export all of the dependencies and processors
-they need).
-
-```python
-deps = [
- ":hilt-android", # For Hilt Android
- ":hilt-android-testing", # For Hilt Android Testing
-]
-```
-
### Other build systems
You will need to include the `dagger-2.x.jar` in your application's runtime.
@@ -248,11 +124,25 @@
</dependencies>
```
-#### Gradle
+#### Java Gradle
+```groovy
+// Add plugin https://plugins.gradle.org/plugin/net.ltgt.apt
+plugins {
+ id "net.ltgt.apt" version "0.10"
+}
+
+// Add Dagger dependencies
+dependencies {
+ compile 'com.google.dagger:dagger:2.x'
+ apt 'com.google.dagger:dagger-compiler:2.x'
+}
+```
+
+#### Android Gradle
```groovy
// Add Dagger dependencies
dependencies {
- implementation 'com.google.dagger:dagger:2.x'
+ compile 'com.google.dagger:dagger:2.x'
annotationProcessor 'com.google.dagger:dagger-compiler:2.x'
}
```
@@ -260,19 +150,13 @@
If you're using classes in `dagger.android` you'll also want to include:
```groovy
-implementation 'com.google.dagger:dagger-android:2.x'
-implementation 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
+compile 'com.google.dagger:dagger-android:2.x'
+compile 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
```
-Notes:
-
-- We use `implementation` instead of `api` for better compilation performance.
- - See the [Gradle documentation][gradle-api-implementation] for more
- information on how to select appropriately, and the [Android Gradle
- plugin documentation][gradle-api-implementation-android] for Android
- projects.
-- For Kotlin projects, use [`kapt`] in place of `annotationProcessor`.
+If you're using a version of the Android gradle plugin below `2.2`, see
+https://bitbucket.org/hvisser/android-apt.
If you're using the [Android Databinding library][databinding], you may want to
increase the number of errors that `javac` will print. When Dagger prints an
@@ -288,11 +172,16 @@
}
```
-### Resources
+### Download
-* [Documentation][website]
-* [Javadocs][latestapi]
-* [GitHub Issues]
+ * 2.x (google/dagger)
+ * [Dagger 2.0 Documentation][website]
+ * [Dagger 2.0 Javadocs][20api]
+ * [Dagger development Javadocs][latestapi] (from the `master` branch
+ on GitHub)
+ * [Google's Dagger project site on GitHub][project]
+ * 1.x (square/dagger)
+ * [Square's original Dagger project site on GitHub][square]
If you do not use maven, gradle, ivy, or other build systems that consume
@@ -323,18 +212,13 @@
See the License for the specific language governing permissions and
limitations under the License.
+[20api]: https://dagger.dev/api/2.0/
[`bazel`]: https://bazel.build
[bazel-external-deps]: https://docs.bazel.build/versions/master/external.html#depending-on-other-bazel-projects
-[`maven_install`]: https://github.com/bazelbuild/rules_jvm_external#exporting-and-consuming-artifacts-from-external-repositories
[Building Dagger]: CONTRIBUTING.md#building-dagger
[dagger-snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/dagger/
[databinding]: https://developer.android.com/topic/libraries/data-binding/
[gaktalk]: https://www.youtube.com/watch?v=oK_XtfXPkqw
-[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
[mavencentral]: https://search.maven.org/artifact/com.google.dagger/dagger
diff --git a/WORKSPACE b/WORKSPACE
index 6c2b6b0..8758b38 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -12,143 +12,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Declare the nested workspace so that the top-level workspace doesn't try to
-# traverse it when calling `bazel build //...`
-local_repository(
- name = "examples_bazel",
- path = "examples/bazel",
-)
-
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "google_bazel_common",
- sha256 = "d8aa0ef609248c2a494d5dbdd4c89ef2a527a97c5a87687e5a218eb0b77ff640",
- strip_prefix = "bazel-common-4a8d451e57fb7e1efecbf9495587a10684a19eb2",
- urls = ["https://github.com/google/bazel-common/archive/4a8d451e57fb7e1efecbf9495587a10684a19eb2.zip"],
+ strip_prefix = "bazel-common-26011657fee96a949c66500b1662c4c7288a4968",
+ urls = ["https://github.com/google/bazel-common/archive/26011657fee96a949c66500b1662c4c7288a4968.zip"],
)
load("@google_bazel_common//:workspace_defs.bzl", "google_common_workspace_rules")
google_common_workspace_rules()
-RULES_JVM_EXTERNAL_TAG = "2.7"
-
-RULES_JVM_EXTERNAL_SHA = "f04b1466a00a2845106801e0c5cec96841f49ea4e7d1df88dc8e4bf31523df74"
-
-http_archive(
- name = "rules_jvm_external",
- sha256 = RULES_JVM_EXTERNAL_SHA,
- strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
- url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
-)
-
-# rules_python and zlib are required by protobuf.
-# TODO(ronshapiro): Figure out if zlib is in fact necessary, or if proto can depend on the
+# This fixes an issue with protobuf starting to use zlib by default in 3.7.0.
+# TODO(ronshapiro): Figure out if this is in fact necessary, or if proto can depend on the
# @bazel_tools library directly. See discussion in
# https://github.com/protocolbuffers/protobuf/pull/5389#issuecomment-481785716
-# TODO(cpovirk): Should we eventually get rules_python from "Bazel Federation?"
-# https://github.com/bazelbuild/rules_python#getting-started
-
-http_archive(
- name = "rules_python",
- sha256 = "e5470e92a18aa51830db99a4d9c492cc613761d5bdb7131c04bd92b9834380f6",
- strip_prefix = "rules_python-4b84ad270387a7c439ebdccfd530e2339601ef27",
- urls = ["https://github.com/bazelbuild/rules_python/archive/4b84ad270387a7c439ebdccfd530e2339601ef27.tar.gz"],
-)
-
-http_archive(
+bind(
name = "zlib",
- build_file = "@com_google_protobuf//:third_party/zlib.BUILD",
- sha256 = "629380c90a77b964d896ed37163f5c3a34f6e6d897311f1df2a7016355c45eff",
- strip_prefix = "zlib-1.2.11",
- urls = ["https://github.com/madler/zlib/archive/v1.2.11.tar.gz"],
+ actual = "@bazel_tools//third_party/zlib",
)
-
-RULES_KOTLIN_COMMIT = "2c283821911439e244285b5bfec39148e7d90e21"
-
-RULES_KOTLIN_SHA = "b04cd539e7e3571745179da95069586b6fa76a64306b24bb286154e652010608"
-
-http_archive(
- name = "io_bazel_rules_kotlin",
- sha256 = RULES_KOTLIN_SHA,
- strip_prefix = "rules_kotlin-%s" % RULES_KOTLIN_COMMIT,
- type = "zip",
- urls = ["https://github.com/bazelbuild/rules_kotlin/archive/%s.zip" % RULES_KOTLIN_COMMIT],
-)
-
-load("@io_bazel_rules_kotlin//kotlin:dependencies.bzl", "kt_download_local_dev_dependencies")
-
-kt_download_local_dev_dependencies()
-
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kotlin_repositories")
-
-KOTLIN_VERSION = "1.4.20"
-
-KOTLINC_RELEASE_SHA = "11db93a4d6789e3406c7f60b9f267eba26d6483dcd771eff9f85bb7e9837011f"
-
-KOTLINC_RELEASE = {
- "sha256": KOTLINC_RELEASE_SHA,
- "urls": ["https://github.com/JetBrains/kotlin/releases/download/v{v}/kotlin-compiler-{v}.zip".format(v = KOTLIN_VERSION)],
-}
-
-kotlin_repositories(compiler_release = KOTLINC_RELEASE)
-
-register_toolchains("//:kotlin_toolchain")
-
-load("@rules_jvm_external//:defs.bzl", "maven_install")
-
-ANDROID_LINT_VERSION = "26.6.2"
-
-maven_install(
- artifacts = [
- "androidx.annotation:annotation:1.1.0",
- "androidx.appcompat:appcompat:1.2.0",
- "androidx.activity:activity:1.1.0",
- "androidx.fragment:fragment:1.2.5",
- "androidx.lifecycle:lifecycle-viewmodel:2.2.0",
- "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0",
- "androidx.multidex:multidex:2.0.1",
- "androidx.savedstate:savedstate:1.0.0",
- "androidx.test:monitor:1.1.1",
- "androidx.test:core:1.1.0",
- "com.google.auto:auto-common:0.11",
- "com.android.support:appcompat-v7:25.0.0",
- "com.android.support:support-annotations:25.0.0",
- "com.android.support:support-fragment:25.0.0",
- "com.android.tools.external.org-jetbrains:uast:%s" % ANDROID_LINT_VERSION,
- "com.android.tools.external.com-intellij:intellij-core:%s" % ANDROID_LINT_VERSION,
- "com.android.tools.external.com-intellij:kotlin-compiler:%s" % ANDROID_LINT_VERSION,
- "com.android.tools.lint:lint:%s" % ANDROID_LINT_VERSION,
- "com.android.tools.lint:lint-api:%s" % ANDROID_LINT_VERSION,
- "com.android.tools.lint:lint-checks:%s" % ANDROID_LINT_VERSION,
- "com.android.tools.lint:lint-tests:%s" % ANDROID_LINT_VERSION,
- "com.android.tools:testutils:%s" % ANDROID_LINT_VERSION,
- "com.github.tschuchortdev:kotlin-compile-testing:1.2.8",
- "com.google.guava:guava:27.1-android",
- "org.jetbrains.kotlin:kotlin-stdlib:%s" % KOTLIN_VERSION,
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.1.0",
- "org.robolectric:robolectric:4.3.1",
- ],
- repositories = [
- "https://repo1.maven.org/maven2",
- "https://maven.google.com",
- "https://jcenter.bintray.com/", # Lint has one trove4j dependency in jCenter
- ],
-)
-
-BAZEL_SKYLIB_VERSION = "1.0.2"
-
-BAZEL_SKYLIB_SHA = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44"
-
-http_archive(
- name = "bazel_skylib",
- sha256 = BAZEL_SKYLIB_SHA,
- urls = [
- "https://github.com/bazelbuild/bazel-skylib/releases/download/{version}/bazel-skylib-{version}.tar.gz".format(version = BAZEL_SKYLIB_VERSION),
- ],
-)
-
-load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
-
-bazel_skylib_workspace()
diff --git a/android-annotation-stubs/gen_annotations.sh b/android-annotation-stubs/gen_annotations.sh
index d4a0290..21aeb46 100755
--- a/android-annotation-stubs/gen_annotations.sh
+++ b/android-annotation-stubs/gen_annotations.sh
@@ -59,8 +59,6 @@
package net.ltgt.gradle.incap;
public enum IncrementalAnnotationProcessorType {
- AGGREGATING,
- DYNAMIC,
- ISOLATING
+ DYNAMIC
}
EOF
diff --git a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java b/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
index ef86328..83e3590 100644
--- a/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
+++ b/android-annotation-stubs/src/net/ltgt/gradle/incap/IncrementalAnnotationProcessorType.java
@@ -16,7 +16,5 @@
package net.ltgt.gradle.incap;
public enum IncrementalAnnotationProcessorType {
- AGGREGATING,
- DYNAMIC,
- ISOLATING
+ DYNAMIC
}
diff --git a/build_defs.bzl b/build_defs.bzl
index 932ca08..0bd7402 100644
--- a/build_defs.bzl
+++ b/build_defs.bzl
@@ -24,8 +24,3 @@
"-target",
"1.7",
]
-
-POM_VERSION = "2.29.1"
-
-# DO NOT remove the comment on the next line. It's used in deploy-to-maven-central.sh
-POM_VERSION_ALPHA = POM_VERSION + "-alpha"
diff --git a/examples/BUILD b/examples/BUILD
deleted file mode 100644
index 5cd2290..0000000
--- a/examples/BUILD
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Dagger examples
-
-package(default_visibility = ["//:src"])
diff --git a/examples/bazel/BUILD b/examples/bazel/BUILD
deleted file mode 100644
index 0f9a621..0000000
--- a/examples/bazel/BUILD
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Dagger Bazel examples
-
-load("@dagger//:workspace_defs.bzl", "dagger_rules", "hilt_android_rules")
-
-dagger_rules()
-
-hilt_android_rules()
diff --git a/examples/bazel/WORKSPACE b/examples/bazel/WORKSPACE
deleted file mode 100644
index 23f93b1..0000000
--- a/examples/bazel/WORKSPACE
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Defines the Bazel workspace rules for the Dagger examples.
-
-########################
-# Load Dagger repository
-########################
-
-# TODO(bcorso): Replace with `http_archive` pointing to tagged released.
-local_repository(
- name = "dagger",
- path = "../../",
-)
-
-load(
- "@dagger//:workspace_defs.bzl",
- "DAGGER_ARTIFACTS",
- "DAGGER_REPOSITORIES",
- "HILT_ANDROID_ARTIFACTS",
- "HILT_ANDROID_REPOSITORIES",
-)
-
-#########################
-# Load Android repository
-#########################
-
-android_sdk_repository(
- name = "androidsdk",
- api_level = 30,
- build_tools_version = "30.0.2",
-)
-
-#############################
-# Load Robolectric repository
-#############################
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-http_archive(
- name = "robolectric",
- strip_prefix = "robolectric-bazel-4.1",
- urls = ["https://github.com/robolectric/robolectric-bazel/archive/4.1.tar.gz"],
-)
-
-load("@robolectric//bazel:robolectric.bzl", "robolectric_repositories")
-
-robolectric_repositories()
-
-#########################
-# Load Maven repositories
-#########################
-
-RULES_JVM_EXTERNAL_TAG = "2.7"
-
-RULES_JVM_EXTERNAL_SHA = "f04b1466a00a2845106801e0c5cec96841f49ea4e7d1df88dc8e4bf31523df74"
-
-http_archive(
- name = "rules_jvm_external",
- sha256 = RULES_JVM_EXTERNAL_SHA,
- strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
- url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
-)
-
-load("@rules_jvm_external//:defs.bzl", "maven_install")
-
-maven_install(
- artifacts = DAGGER_ARTIFACTS + HILT_ANDROID_ARTIFACTS + [
- "androidx.test.ext:junit:1.1.1",
- "androidx.test:runner:1.1.1",
- "com.google.truth:truth:1.0.1",
- "junit:junit:4.13",
- "org.robolectric:robolectric:4.1",
- "org.robolectric:annotations:4.1",
- ],
- repositories = DAGGER_REPOSITORIES + HILT_ANDROID_REPOSITORIES,
-)
diff --git a/examples/bazel/java/example/common/BUILD b/examples/bazel/java/example/common/BUILD
deleted file mode 100644
index 4de78ae..0000000
--- a/examples/bazel/java/example/common/BUILD
+++ /dev/null
@@ -1,25 +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.
-
-java_library(
- name = "common",
- srcs = glob(["*.java"]),
- visibility = [
- "//java/example:__subpackages__",
- "//javatests/example:__subpackages__",
- ],
- deps = [
- "//:dagger",
- ],
-)
diff --git a/examples/bazel/java/example/common/CoffeeLogger.java b/examples/bazel/java/example/common/CoffeeLogger.java
deleted file mode 100644
index 10c1849..0000000
--- a/examples/bazel/java/example/common/CoffeeLogger.java
+++ /dev/null
@@ -1,39 +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 example.common;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** A logger to logs steps while brewing coffee. */
-@Singleton
-public final class CoffeeLogger {
- private final List<String> logs = new ArrayList<>();
-
- @Inject
- CoffeeLogger() {}
-
- public void log(String msg) {
- logs.add(msg);
- }
-
- public List<String> logs() {
- return new ArrayList<>(logs);
- }
-}
diff --git a/examples/bazel/java/example/common/CoffeeMaker.java b/examples/bazel/java/example/common/CoffeeMaker.java
deleted file mode 100644
index 796638d..0000000
--- a/examples/bazel/java/example/common/CoffeeMaker.java
+++ /dev/null
@@ -1,41 +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 example.common;
-
-import dagger.Lazy;
-import javax.inject.Inject;
-
-/** A coffee maker to brew the coffee. */
-public class CoffeeMaker {
- private final CoffeeLogger logger;
- private final Lazy<Heater> heater; // Create a possibly costly heater only when we use it.
- private final Pump pump;
-
- @Inject
- CoffeeMaker(CoffeeLogger logger, Lazy<Heater> heater, Pump pump) {
- this.logger = logger;
- this.heater = heater;
- this.pump = pump;
- }
-
- public void brew() {
- heater.get().on();
- pump.pump();
- logger.log(" [_]P coffee! [_]P ");
- heater.get().off();
- }
-}
diff --git a/examples/bazel/java/example/common/ElectricHeater.java b/examples/bazel/java/example/common/ElectricHeater.java
deleted file mode 100644
index 981a41a..0000000
--- a/examples/bazel/java/example/common/ElectricHeater.java
+++ /dev/null
@@ -1,47 +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 example.common;
-
-import javax.inject.Inject;
-
-/** An electric heater to heat the coffee. */
-public class ElectricHeater implements Heater {
-
- private final CoffeeLogger logger;
- private boolean heating;
-
- @Inject
- ElectricHeater(CoffeeLogger logger) {
- this.logger = logger;
- }
-
- @Override
- public void on() {
- this.heating = true;
- logger.log("~ ~ ~ heating ~ ~ ~");
- }
-
- @Override
- public void off() {
- this.heating = false;
- }
-
- @Override
- public boolean isHot() {
- return heating;
- }
-}
diff --git a/examples/bazel/java/example/common/Heater.java b/examples/bazel/java/example/common/Heater.java
deleted file mode 100644
index 9f9df50..0000000
--- a/examples/bazel/java/example/common/Heater.java
+++ /dev/null
@@ -1,24 +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 example.common;
-
-/** A heater to heat the coffee. */
-public interface Heater {
- void on();
- void off();
- boolean isHot();
-}
diff --git a/examples/bazel/java/example/common/Pump.java b/examples/bazel/java/example/common/Pump.java
deleted file mode 100644
index 4a627cf..0000000
--- a/examples/bazel/java/example/common/Pump.java
+++ /dev/null
@@ -1,22 +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 example.common;
-
-/** A pump to pump the coffee. */
-public interface Pump {
- void pump();
-}
diff --git a/examples/bazel/java/example/common/Thermosiphon.java b/examples/bazel/java/example/common/Thermosiphon.java
deleted file mode 100644
index 6509c80..0000000
--- a/examples/bazel/java/example/common/Thermosiphon.java
+++ /dev/null
@@ -1,38 +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 example.common;
-
-import javax.inject.Inject;
-
-/** A thermosiphon to pump the coffee. */
-public class Thermosiphon implements Pump {
- private final CoffeeLogger logger;
- private final Heater heater;
-
- @Inject
- Thermosiphon(CoffeeLogger logger, Heater heater) {
- this.logger = logger;
- this.heater = heater;
- }
-
- @Override
- public void pump() {
- if (heater.isHot()) {
- logger.log("=> => pumping => =>");
- }
- }
-}
diff --git a/examples/bazel/java/example/dagger/BUILD b/examples/bazel/java/example/dagger/BUILD
deleted file mode 100644
index 7af63b9..0000000
--- a/examples/bazel/java/example/dagger/BUILD
+++ /dev/null
@@ -1,23 +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.
-
-java_binary(
- name = "dagger",
- srcs = glob(["*.java"]),
- main_class = "dagger.coffee.CoffeeApp",
- deps = [
- "//:dagger",
- "//java/example/common",
- ],
-)
diff --git a/examples/bazel/java/example/dagger/CoffeeApp.java b/examples/bazel/java/example/dagger/CoffeeApp.java
deleted file mode 100644
index 624fdf7..0000000
--- a/examples/bazel/java/example/dagger/CoffeeApp.java
+++ /dev/null
@@ -1,43 +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 example.dagger;
-
-import dagger.Component;
-import example.common.CoffeeLogger;
-import example.common.CoffeeMaker;
-import javax.inject.Singleton;
-
-/** The main app responsible for brewing the coffee and printing the logs. */
-public class CoffeeApp {
- @Singleton
- @Component(
- modules = {
- HeaterModule.class,
- PumpModule.class
- }
- )
- public interface CoffeeShop {
- CoffeeMaker maker();
- CoffeeLogger logger();
- }
-
- public static void main(String[] args) {
- CoffeeShop coffeeShop = DaggerCoffeeApp_CoffeeShop.builder().build();
- coffeeShop.maker().brew();
- coffeeShop.logger().logs().forEach(log -> System.out.println(log));
- }
-}
diff --git a/examples/bazel/java/example/dagger/HeaterModule.java b/examples/bazel/java/example/dagger/HeaterModule.java
deleted file mode 100644
index 0709222..0000000
--- a/examples/bazel/java/example/dagger/HeaterModule.java
+++ /dev/null
@@ -1,30 +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 example.dagger;
-
-import dagger.Binds;
-import dagger.Module;
-import example.common.ElectricHeater;
-import example.common.Heater;
-import javax.inject.Singleton;
-
-@Module
-interface HeaterModule {
- @Binds
- @Singleton
- Heater bindHeater(ElectricHeater impl);
-}
diff --git a/examples/bazel/java/example/dagger/PumpModule.java b/examples/bazel/java/example/dagger/PumpModule.java
deleted file mode 100644
index 3af7052..0000000
--- a/examples/bazel/java/example/dagger/PumpModule.java
+++ /dev/null
@@ -1,28 +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 example.dagger;
-
-import dagger.Binds;
-import dagger.Module;
-import example.common.Pump;
-import example.common.Thermosiphon;
-
-@Module
-abstract class PumpModule {
- @Binds
- abstract Pump providePump(Thermosiphon pump);
-}
diff --git a/examples/bazel/java/example/hilt/AndroidManifest.xml b/examples/bazel/java/example/hilt/AndroidManifest.xml
deleted file mode 100644
index a786737..0000000
--- a/examples/bazel/java/example/hilt/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="example.hilt">
-
- <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="28"/>
-
- <application android:name=".CoffeeApp">
- </application>
-</manifest>
diff --git a/examples/bazel/java/example/hilt/BUILD b/examples/bazel/java/example/hilt/BUILD
deleted file mode 100644
index e890401..0000000
--- a/examples/bazel/java/example/hilt/BUILD
+++ /dev/null
@@ -1,48 +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.
-
-android_binary(
- name = "hilt",
- srcs = ["CoffeeApp.java"],
- manifest = "AndroidManifest.xml",
- resource_files = glob(["res/**"]),
- deps = [
- ":heater_module",
- ":pump_module",
- "//:hilt-android",
- "//java/example/common",
- ],
-)
-
-android_library(
- name = "heater_module",
- srcs = ["HeaterModule.java"],
- manifest = "AndroidManifest.xml",
- visibility = ["//javatests/example/hilt:__pkg__"],
- deps = [
- "//:hilt-android",
- "//java/example/common",
- ],
-)
-
-android_library(
- name = "pump_module",
- srcs = ["PumpModule.java"],
- manifest = "AndroidManifest.xml",
- visibility = ["//javatests/example/hilt:__pkg__"],
- deps = [
- "//:hilt-android",
- "//java/example/common",
- ],
-)
diff --git a/examples/bazel/java/example/hilt/CoffeeApp.java b/examples/bazel/java/example/hilt/CoffeeApp.java
deleted file mode 100644
index 0ff7212..0000000
--- a/examples/bazel/java/example/hilt/CoffeeApp.java
+++ /dev/null
@@ -1,38 +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 example.hilt;
-
-import android.app.Application;
-import dagger.hilt.android.HiltAndroidApp;
-import example.common.CoffeeLogger;
-import example.common.CoffeeMaker;
-import javax.inject.Inject;
-
-/** The main app responsible for brewing the coffee and printing the logs. */
-@HiltAndroidApp(Application.class)
-public class CoffeeApp extends Hilt_CoffeeApp {
-
- @Inject CoffeeMaker maker;
- @Inject CoffeeLogger logger;
-
- @Override
- public void onCreate() {
- super.onCreate();
- maker.brew();
- logger.logs().forEach(log -> System.out.println(log));
- }
-}
diff --git a/examples/bazel/java/example/hilt/HeaterModule.java b/examples/bazel/java/example/hilt/HeaterModule.java
deleted file mode 100644
index 122bec0..0000000
--- a/examples/bazel/java/example/hilt/HeaterModule.java
+++ /dev/null
@@ -1,33 +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 example.hilt;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-import example.common.ElectricHeater;
-import example.common.Heater;
-import javax.inject.Singleton;
-
-@Module
-@InstallIn(SingletonComponent.class)
-interface HeaterModule {
- @Binds
- @Singleton
- Heater bindHeater(ElectricHeater impl);
-}
diff --git a/examples/bazel/java/example/hilt/PumpModule.java b/examples/bazel/java/example/hilt/PumpModule.java
deleted file mode 100644
index 0ad3903..0000000
--- a/examples/bazel/java/example/hilt/PumpModule.java
+++ /dev/null
@@ -1,31 +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 example.hilt;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-import example.common.Pump;
-import example.common.Thermosiphon;
-
-@Module
-@InstallIn(SingletonComponent.class)
-abstract class PumpModule {
- @Binds
- abstract Pump providePump(Thermosiphon pump);
-}
diff --git a/examples/bazel/javatests/example/hilt/BUILD b/examples/bazel/javatests/example/hilt/BUILD
deleted file mode 100644
index 9982fbd..0000000
--- a/examples/bazel/javatests/example/hilt/BUILD
+++ /dev/null
@@ -1,55 +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.
-
-android_local_test(
- name = "CoffeeAppFakePumpTest",
- srcs = [
- "CoffeeAppFakePumpTest.java",
- ],
- manifest_values = {
- "minSdkVersion": "15",
- },
- deps = [
- "//:hilt-android-testing",
- "//java/example/common",
- "//java/example/hilt:heater_module",
- "@maven//:androidx_test_ext_junit",
- "@maven//:androidx_test_runner",
- "@maven//:com_google_truth_truth",
- "@maven//:org_robolectric_annotations",
- "@maven//:org_robolectric_robolectric",
- "@robolectric//bazel:android-all",
- ],
-)
-
-android_local_test(
- name = "CoffeeAppFakeHeaterTest",
- srcs = [
- "CoffeeAppFakeHeaterTest.java",
- ],
- manifest_values = {
- "minSdkVersion": "15",
- },
- deps = [
- "//:hilt-android-testing",
- "//java/example/common",
- "//java/example/hilt:pump_module",
- "@maven//:androidx_test_ext_junit",
- "@maven//:androidx_test_runner",
- "@maven//:com_google_truth_truth",
- "@maven//:org_robolectric_annotations",
- "@maven//:org_robolectric_robolectric",
- "@robolectric//bazel:android-all",
- ],
-)
diff --git a/examples/bazel/javatests/example/hilt/CoffeeAppFakeHeaterTest.java b/examples/bazel/javatests/example/hilt/CoffeeAppFakeHeaterTest.java
deleted file mode 100644
index 5f4e162..0000000
--- a/examples/bazel/javatests/example/hilt/CoffeeAppFakeHeaterTest.java
+++ /dev/null
@@ -1,88 +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 example.hilt;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.Build;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.HiltTestApplication;
-import example.common.CoffeeLogger;
-import example.common.CoffeeMaker;
-import example.common.Heater;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** Tests using a fake heater. */
-@HiltAndroidTest
-@Config(sdk = {Build.VERSION_CODES.P}, application = HiltTestApplication.class)
-@RunWith(AndroidJUnit4.class)
-public final class CoffeeAppFakeHeaterTest {
- public @Rule HiltAndroidRule rule = new HiltAndroidRule(this);
-
- final class FakeHeater implements Heater {
- private boolean heating;
-
- @Override
- public void on() {
- this.heating = true;
- logger.log("~ ~ ~ fake heating ~ ~ ~");
- }
-
- @Override
- public void off() {
- this.heating = false;
- }
-
- @Override
- public boolean isHot() {
- return heating;
- }
- }
-
- @Inject CoffeeMaker maker;
- @Inject CoffeeLogger logger;
-
- @BindValue Heater fakeHeater = new FakeHeater();
-
- @Test
- public void testApplicationClass() throws Exception {
- assertThat((Context) ApplicationProvider.getApplicationContext())
- .isInstanceOf(HiltTestApplication.class);
- }
-
- @Test
- public void testLogs() throws Exception {
- rule.inject();
- assertThat(logger.logs()).isEmpty();
- maker.brew();
- assertThat(logger.logs())
- .containsExactly(
- "~ ~ ~ fake heating ~ ~ ~",
- "=> => pumping => =>",
- " [_]P coffee! [_]P ")
- .inOrder();
- }
-}
diff --git a/examples/bazel/javatests/example/hilt/CoffeeAppFakePumpTest.java b/examples/bazel/javatests/example/hilt/CoffeeAppFakePumpTest.java
deleted file mode 100644
index 6d89270..0000000
--- a/examples/bazel/javatests/example/hilt/CoffeeAppFakePumpTest.java
+++ /dev/null
@@ -1,68 +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 example.hilt;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.Build;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.HiltTestApplication;
-import example.common.CoffeeLogger;
-import example.common.CoffeeMaker;
-import example.common.Pump;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** Tests using a fake pump. */
-@HiltAndroidTest
-@Config(sdk = {Build.VERSION_CODES.P}, application = HiltTestApplication.class)
-@RunWith(AndroidJUnit4.class)
-public final class CoffeeAppFakePumpTest {
- public @Rule HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject CoffeeMaker maker;
- @Inject CoffeeLogger logger;
-
- @BindValue Pump fakePump = () -> logger.log("=> => fake pumping => =>");
-
- @Test
- public void testApplicationClass() throws Exception {
- assertThat((Context) ApplicationProvider.getApplicationContext())
- .isInstanceOf(HiltTestApplication.class);
- }
-
- @Test
- public void testLogs() throws Exception {
- rule.inject();
- assertThat(logger.logs()).isEmpty();
- maker.brew();
- assertThat(logger.logs())
- .containsExactly(
- "~ ~ ~ heating ~ ~ ~",
- "=> => fake pumping => =>",
- " [_]P coffee! [_]P ")
- .inOrder();
- }
-}
diff --git a/examples/maven/coffee/pom.xml b/examples/maven/coffee/pom.xml
deleted file mode 100644
index a196d99..0000000
--- a/examples/maven/coffee/pom.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2012 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>com.google.dagger.examples</groupId>
- <artifactId>parent</artifactId>
- <version>LOCAL-SNAPSHOT</version>
- </parent>
-
- <artifactId>coffee</artifactId>
- <name>Examples: Coffee</name>
-
- <dependencies>
- <dependency>
- <!-- Force the correct version of Guava to be on the classpath. -->
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- </dependency>
- <dependency>
- <groupId>com.google.dagger</groupId>
- <artifactId>dagger</artifactId>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.6.1</version>
- <configuration>
- <annotationProcessorPaths>
- <path>
- <groupId>com.google.dagger</groupId>
- <artifactId>dagger-compiler</artifactId>
- <version>${project.version}</version>
- </path>
- </annotationProcessorPaths>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/examples/maven/coffee/src/main/java/example/dagger/CoffeeApp.java b/examples/maven/coffee/src/main/java/example/dagger/CoffeeApp.java
deleted file mode 100644
index 723ab91..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/CoffeeApp.java
+++ /dev/null
@@ -1,41 +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 example.dagger;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-/** The main app responsible for brewing the coffee and printing the logs. */
-public class CoffeeApp {
- @Singleton
- @Component(
- modules = {
- HeaterModule.class,
- PumpModule.class
- }
- )
- public interface CoffeeShop {
- CoffeeMaker maker();
- CoffeeLogger logger();
- }
-
- public static void main(String[] args) {
- CoffeeShop coffeeShop = DaggerCoffeeApp_CoffeeShop.builder().build();
- coffeeShop.maker().brew();
- coffeeShop.logger().logs().forEach(log -> System.out.println(log));
- }
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/CoffeeLogger.java b/examples/maven/coffee/src/main/java/example/dagger/CoffeeLogger.java
deleted file mode 100644
index 16d2bdb..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/CoffeeLogger.java
+++ /dev/null
@@ -1,39 +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 example.dagger;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** A logger to logs steps while brewing coffee. */
-@Singleton
-public final class CoffeeLogger {
- private final List<String> logs = new ArrayList<>();
-
- @Inject
- CoffeeLogger() {}
-
- public void log(String msg) {
- logs.add(msg);
- }
-
- public List<String> logs() {
- return new ArrayList<>(logs);
- }
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/CoffeeMaker.java b/examples/maven/coffee/src/main/java/example/dagger/CoffeeMaker.java
deleted file mode 100644
index 20c1f27..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/CoffeeMaker.java
+++ /dev/null
@@ -1,41 +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 example.dagger;
-
-import dagger.Lazy;
-import javax.inject.Inject;
-
-/** A coffee maker to brew the coffee. */
-public class CoffeeMaker {
- private final CoffeeLogger logger;
- private final Lazy<Heater> heater; // Create a possibly costly heater only when we use it.
- private final Pump pump;
-
- @Inject
- CoffeeMaker(CoffeeLogger logger, Lazy<Heater> heater, Pump pump) {
- this.logger = logger;
- this.heater = heater;
- this.pump = pump;
- }
-
- public void brew() {
- heater.get().on();
- pump.pump();
- logger.log(" [_]P coffee! [_]P ");
- heater.get().off();
- }
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/ElectricHeater.java b/examples/maven/coffee/src/main/java/example/dagger/ElectricHeater.java
deleted file mode 100644
index 567c7aa..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/ElectricHeater.java
+++ /dev/null
@@ -1,47 +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 example.dagger;
-
-import javax.inject.Inject;
-
-/** An electric heater to heat the coffee. */
-public class ElectricHeater implements Heater {
-
- private final CoffeeLogger logger;
- private boolean heating;
-
- @Inject
- ElectricHeater(CoffeeLogger logger) {
- this.logger = logger;
- }
-
- @Override
- public void on() {
- this.heating = true;
- logger.log("~ ~ ~ heating ~ ~ ~");
- }
-
- @Override
- public void off() {
- this.heating = false;
- }
-
- @Override
- public boolean isHot() {
- return heating;
- }
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/Heater.java b/examples/maven/coffee/src/main/java/example/dagger/Heater.java
deleted file mode 100644
index 3d6d1f2..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/Heater.java
+++ /dev/null
@@ -1,24 +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 example.dagger;
-
-/** A heater to heat the coffee. */
-public interface Heater {
- void on();
- void off();
- boolean isHot();
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/HeaterModule.java b/examples/maven/coffee/src/main/java/example/dagger/HeaterModule.java
deleted file mode 100644
index fb8c969..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/HeaterModule.java
+++ /dev/null
@@ -1,28 +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 example.dagger;
-
-import dagger.Binds;
-import dagger.Module;
-import javax.inject.Singleton;
-
-@Module
-interface HeaterModule {
- @Binds
- @Singleton
- Heater bindHeater(ElectricHeater impl);
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/Pump.java b/examples/maven/coffee/src/main/java/example/dagger/Pump.java
deleted file mode 100644
index 712b21c..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/Pump.java
+++ /dev/null
@@ -1,22 +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 example.dagger;
-
-/** A pump to pump the coffee. */
-public interface Pump {
- void pump();
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/PumpModule.java b/examples/maven/coffee/src/main/java/example/dagger/PumpModule.java
deleted file mode 100644
index 202fed3..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/PumpModule.java
+++ /dev/null
@@ -1,26 +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 example.dagger;
-
-import dagger.Binds;
-import dagger.Module;
-
-@Module
-abstract class PumpModule {
- @Binds
- abstract Pump providePump(Thermosiphon pump);
-}
diff --git a/examples/maven/coffee/src/main/java/example/dagger/Thermosiphon.java b/examples/maven/coffee/src/main/java/example/dagger/Thermosiphon.java
deleted file mode 100644
index d94c33f..0000000
--- a/examples/maven/coffee/src/main/java/example/dagger/Thermosiphon.java
+++ /dev/null
@@ -1,38 +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 example.dagger;
-
-import javax.inject.Inject;
-
-/** A thermosiphon to pump the coffee. */
-public class Thermosiphon implements Pump {
- private final CoffeeLogger logger;
- private final Heater heater;
-
- @Inject
- Thermosiphon(CoffeeLogger logger, Heater heater) {
- this.logger = logger;
- this.heater = heater;
- }
-
- @Override
- public void pump() {
- if (heater.isHot()) {
- logger.log("=> => pumping => =>");
- }
- }
-}
diff --git a/examples/maven/pom.xml b/examples/maven/pom.xml
deleted file mode 100644
index be21b96..0000000
--- a/examples/maven/pom.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (C) 2013 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.sonatype.oss</groupId>
- <artifactId>oss-parent</artifactId>
- <version>9</version>
- </parent>
-
- <groupId>com.google.dagger.examples</groupId>
- <artifactId>parent</artifactId>
- <packaging>pom</packaging>
- <name>Examples</name>
- <version>LOCAL-SNAPSHOT</version>
-
- <modules>
- <module>coffee</module>
- </modules>
-
- <!-- Example-only dependencies. -->
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>com.google.dagger</groupId>
- <artifactId>dagger</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>com.google.dagger</groupId>
- <artifactId>dagger-compiler</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- <version>26.0-jre</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
-</project>
diff --git a/examples/pom.xml b/examples/pom.xml
new file mode 100644
index 0000000..c12050d
--- /dev/null
+++ b/examples/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.sonatype.oss</groupId>
+ <artifactId>oss-parent</artifactId>
+ <version>9</version>
+ </parent>
+
+ <groupId>com.google.dagger.example</groupId>
+ <artifactId>dagger-example-parent</artifactId>
+ <packaging>pom</packaging>
+ <name>Examples</name>
+ <version>2.17</version>
+
+ <modules>
+ <module>simple</module>
+ </modules>
+
+ <!-- Example-only dependencies. -->
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>26.0-jre</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/examples/simple/pom.xml b/examples/simple/pom.xml
new file mode 100644
index 0000000..ffc99dc
--- /dev/null
+++ b/examples/simple/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2012 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>com.google.dagger.example</groupId>
+ <artifactId>dagger-example-parent</artifactId>
+ <version>2.17</version>
+ </parent>
+
+ <artifactId>simple</artifactId>
+ <name>Examples: Simple</name>
+
+ <dependencies>
+ <dependency>
+ <!-- Force the correct version of Guava to be on the classpath. -->
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.6.1</version>
+ <configuration>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger-compiler</artifactId>
+ <version>${project.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/simple/src/main/java/coffee/CoffeeApp.java b/examples/simple/src/main/java/coffee/CoffeeApp.java
new file mode 100644
index 0000000..7a2b9a6
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/CoffeeApp.java
@@ -0,0 +1,17 @@
+package coffee;
+
+import dagger.Component;
+import javax.inject.Singleton;
+
+public class CoffeeApp {
+ @Singleton
+ @Component(modules = { DripCoffeeModule.class })
+ public interface CoffeeShop {
+ CoffeeMaker maker();
+ }
+
+ public static void main(String[] args) {
+ CoffeeShop coffeeShop = DaggerCoffeeApp_CoffeeShop.builder().build();
+ coffeeShop.maker().brew();
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/CoffeeMaker.java b/examples/simple/src/main/java/coffee/CoffeeMaker.java
new file mode 100644
index 0000000..6410336
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/CoffeeMaker.java
@@ -0,0 +1,21 @@
+package coffee;
+
+import dagger.Lazy;
+import javax.inject.Inject;
+
+class CoffeeMaker {
+ private final Lazy<Heater> heater; // Create a possibly costly heater only when we use it.
+ private final Pump pump;
+
+ @Inject CoffeeMaker(Lazy<Heater> heater, Pump pump) {
+ this.heater = heater;
+ this.pump = pump;
+ }
+
+ public void brew() {
+ heater.get().on();
+ pump.pump();
+ System.out.println(" [_]P coffee! [_]P ");
+ heater.get().off();
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/DripCoffeeModule.java b/examples/simple/src/main/java/coffee/DripCoffeeModule.java
new file mode 100644
index 0000000..e50d249
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/DripCoffeeModule.java
@@ -0,0 +1,12 @@
+package coffee;
+
+import dagger.Module;
+import dagger.Provides;
+import javax.inject.Singleton;
+
+@Module(includes = PumpModule.class)
+class DripCoffeeModule {
+ @Provides @Singleton Heater provideHeater() {
+ return new ElectricHeater();
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/ElectricHeater.java b/examples/simple/src/main/java/coffee/ElectricHeater.java
new file mode 100644
index 0000000..fbab399
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/ElectricHeater.java
@@ -0,0 +1,18 @@
+package coffee;
+
+class ElectricHeater implements Heater {
+ boolean heating;
+
+ @Override public void on() {
+ System.out.println("~ ~ ~ heating ~ ~ ~");
+ this.heating = true;
+ }
+
+ @Override public void off() {
+ this.heating = false;
+ }
+
+ @Override public boolean isHot() {
+ return heating;
+ }
+}
diff --git a/examples/simple/src/main/java/coffee/Heater.java b/examples/simple/src/main/java/coffee/Heater.java
new file mode 100644
index 0000000..b5ddb6b
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/Heater.java
@@ -0,0 +1,7 @@
+package coffee;
+
+interface Heater {
+ void on();
+ void off();
+ boolean isHot();
+}
diff --git a/examples/simple/src/main/java/coffee/Pump.java b/examples/simple/src/main/java/coffee/Pump.java
new file mode 100644
index 0000000..e394349
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/Pump.java
@@ -0,0 +1,5 @@
+package coffee;
+
+interface Pump {
+ void pump();
+}
diff --git a/examples/simple/src/main/java/coffee/PumpModule.java b/examples/simple/src/main/java/coffee/PumpModule.java
new file mode 100644
index 0000000..df00b86
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/PumpModule.java
@@ -0,0 +1,10 @@
+package coffee;
+
+import dagger.Binds;
+import dagger.Module;
+
+@Module
+abstract class PumpModule {
+ @Binds
+ abstract Pump providePump(Thermosiphon pump);
+}
diff --git a/examples/simple/src/main/java/coffee/Thermosiphon.java b/examples/simple/src/main/java/coffee/Thermosiphon.java
new file mode 100644
index 0000000..c9f9828
--- /dev/null
+++ b/examples/simple/src/main/java/coffee/Thermosiphon.java
@@ -0,0 +1,18 @@
+package coffee;
+
+import javax.inject.Inject;
+
+class Thermosiphon implements Pump {
+ private final Heater heater;
+
+ @Inject
+ Thermosiphon(Heater heater) {
+ this.heater = heater;
+ }
+
+ @Override public void pump() {
+ if (heater.isHot()) {
+ System.out.println("=> => pumping => =>");
+ }
+ }
+}
diff --git a/gwt/BUILD b/gwt/BUILD
index 5aa9110..da73013 100644
--- a/gwt/BUILD
+++ b/gwt/BUILD
@@ -15,12 +15,10 @@
# Description:
# GWT-specific files for Dagger
-load("@rules_java//java:defs.bzl", "java_library")
-load("//tools:maven.bzl", "pom_file")
-load("//:build_defs.bzl", "POM_VERSION")
-
package(default_visibility = ["//:src"])
+load("//tools:maven.bzl", "pom_file", "POM_VERSION")
+
java_library(
name = "gwt",
resource_strip_prefix = "gwt/",
diff --git a/java/dagger/BUILD b/java/dagger/BUILD
index aaebade..3485431 100644
--- a/java/dagger/BUILD
+++ b/java/dagger/BUILD
@@ -15,17 +15,14 @@
# Description:
# A JSR-330 compliant dependency injection system for android and java
-load("@rules_java//java:defs.bzl", "java_library")
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
- "POM_VERSION",
"SOURCE_7_TARGET_7",
)
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-package(default_visibility = ["//:src"])
+load("//tools:maven.bzl", "POM_VERSION", "pom_file")
java_library(
name = "core",
@@ -50,6 +47,8 @@
srcs = glob(["**/*"]),
)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
javadoc_library(
name = "core-javadoc",
srcs = [":javadoc-srcs"],
diff --git a/java/dagger/Provides.java b/java/dagger/Provides.java
index 5d7827b..a60be3b 100644
--- a/java/dagger/Provides.java
+++ b/java/dagger/Provides.java
@@ -30,11 +30,11 @@
*
* <h3>Nullability</h3>
*
- * <p>Dagger forbids injecting {@code null} by default. Component implementations that invoke
+ * <p>Dagger forbids injecting {@code null} by default. Component implemenations that invoke
* {@code @Provides} methods that return {@code null} will throw a {@link NullPointerException}
* immediately thereafter. {@code @Provides} methods may opt into allowing {@code null} by
* annotating the method with any {@code @Nullable} annotation like
- * {@code javax.annotation.Nullable} or {@code androidx.annotation.Nullable}.
+ * {@code javax.annotation.Nullable} or {@code android.support.annotation.Nullable}.
*
* <p>If a {@code @Provides} method is marked {@code @Nullable}, Dagger will <em>only</em>
* allow injection into sites that are marked {@code @Nullable} as well. A component that
diff --git a/java/dagger/android/AndroidInjection.java b/java/dagger/android/AndroidInjection.java
index f3296c6..2f4fb4c 100644
--- a/java/dagger/android/AndroidInjection.java
+++ b/java/dagger/android/AndroidInjection.java
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2017 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,71 +39,99 @@
* otherwise throws an {@link IllegalArgumentException}.
*
* @throws RuntimeException if the {@link Application} doesn't implement {@link
- * HasAndroidInjector}.
+ * HasAndroidInjector} or {@link HasActivityInjector}.
*/
public static void inject(Activity activity) {
checkNotNull(activity, "activity");
Application application = activity.getApplication();
- if (!(application instanceof HasAndroidInjector)) {
+ AndroidInjector<? super Activity> injector;
+ if (application instanceof HasAndroidInjector) {
+ injector = ((HasAndroidInjector) application).androidInjector();
+ checkNotNull(injector, "%s.androidInjector() returned null", application.getClass());
+ } else if (application instanceof HasActivityInjector) {
+ injector = ((HasActivityInjector) application).activityInjector();
+ checkNotNull(injector, "%s.activityInjector() returned null", application.getClass());
+ } else {
throw new RuntimeException(
String.format(
- "%s does not implement %s",
+ "%s does not implement %s or %s",
application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName()));
+ HasAndroidInjector.class.getCanonicalName(),
+ HasActivityInjector.class.getCanonicalName()));
}
- inject(activity, (HasAndroidInjector) application);
+ injector.inject(activity);
}
/**
* Injects {@code fragment} if an associated {@link AndroidInjector} implementation can be found,
* otherwise throws an {@link IllegalArgumentException}.
*
- * <p>Uses the following algorithm to find the appropriate {@code AndroidInjector<Fragment>} to
- * use to inject {@code fragment}:
+ * <p>Uses the following algorithm to find the appropriate {@link AndroidInjector} to use to
+ * inject {@code fragment}:
*
* <ol>
- * <li>Walks the parent-fragment hierarchy to find the a fragment that implements {@link
- * HasAndroidInjector}, and if none do
+ * <li>Walks the parent-fragment hierarchy to find a fragment that implements {@link
+ * HasAndroidInjector} or {@link HasFragmentInjector}, and if none do
* <li>Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements
- * {@link HasAndroidInjector}, and if not
- * <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}.
+ * {@link HasAndroidInjector} or {@link HasFragmentInjector}, and if not
+ * <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}
+ * {@link HasFragmentInjector}.
* </ol>
*
- * If none of them implement {@link HasAndroidInjector}, a {@link IllegalArgumentException} is
- * thrown.
+ * If none of them implement {@link HasAndroidInjector} or {@link HasFragmentInjector}, a {@link
+ * IllegalArgumentException} is thrown.
*
* @throws IllegalArgumentException if no parent fragment, activity, or application implements
- * {@link HasAndroidInjector}.
+ * {@link HasAndroidInjector} or {@link HasFragmentInjector}.
*/
public static void inject(Fragment fragment) {
checkNotNull(fragment, "fragment");
- HasAndroidInjector hasAndroidInjector = findHasAndroidInjectorForFragment(fragment);
+
+ Object hasInjector = findHasFragmentInjector(fragment);
+ AndroidInjector<? super Fragment> injector;
+ if (hasInjector instanceof HasAndroidInjector) {
+ injector = ((HasAndroidInjector) hasInjector).androidInjector();
+ checkNotNull(injector, "%s.androidInjector() returned null", hasInjector.getClass());
+ } else if (hasInjector instanceof HasFragmentInjector) {
+ injector = ((HasFragmentInjector) hasInjector).fragmentInjector();
+ checkNotNull(injector, "%s.fragmentInjector() returned null", hasInjector.getClass());
+ } else {
+ throw new RuntimeException(
+ String.format(
+ "%s does not implement %s or %s",
+ hasInjector.getClass().getCanonicalName(),
+ HasAndroidInjector.class.getCanonicalName(),
+ HasFragmentInjector.class.getCanonicalName()));
+ }
+
if (Log.isLoggable(TAG, DEBUG)) {
Log.d(
TAG,
String.format(
"An injector for %s was found in %s",
fragment.getClass().getCanonicalName(),
- hasAndroidInjector.getClass().getCanonicalName()));
+ hasInjector.getClass().getCanonicalName()));
}
- inject(fragment, hasAndroidInjector);
+ injector.inject(fragment);
}
- private static HasAndroidInjector findHasAndroidInjectorForFragment(Fragment fragment) {
+ private static Object findHasFragmentInjector(Fragment fragment) {
Fragment parentFragment = fragment;
while ((parentFragment = parentFragment.getParentFragment()) != null) {
- if (parentFragment instanceof HasAndroidInjector) {
- return (HasAndroidInjector) parentFragment;
+ if (parentFragment instanceof HasAndroidInjector
+ || parentFragment instanceof HasFragmentInjector) {
+ return parentFragment;
}
}
Activity activity = fragment.getActivity();
- if (activity instanceof HasAndroidInjector) {
- return (HasAndroidInjector) activity;
+ if (activity instanceof HasAndroidInjector || activity instanceof HasFragmentInjector) {
+ return activity;
}
- if (activity.getApplication() instanceof HasAndroidInjector) {
- return (HasAndroidInjector) activity.getApplication();
+ Application application = activity.getApplication();
+ if (application instanceof HasAndroidInjector || application instanceof HasFragmentInjector) {
+ return application;
}
throw new IllegalArgumentException(
String.format("No injector was found for %s", fragment.getClass().getCanonicalName()));
@@ -114,20 +142,28 @@
* otherwise throws an {@link IllegalArgumentException}.
*
* @throws RuntimeException if the {@link Application} doesn't implement {@link
- * HasAndroidInjector}.
+ * HasAndroidInjector} or {@link HasServiceInjector}.
*/
public static void inject(Service service) {
checkNotNull(service, "service");
Application application = service.getApplication();
- if (!(application instanceof HasAndroidInjector)) {
+ AndroidInjector<? super Service> injector;
+ if (application instanceof HasAndroidInjector) {
+ injector = ((HasAndroidInjector) application).androidInjector();
+ checkNotNull(injector, "%s.androidInjector() returned null", application.getClass());
+ } else if (application instanceof HasServiceInjector) {
+ injector = ((HasServiceInjector) application).serviceInjector();
+ checkNotNull(injector, "%s.serviceInjector() returned null", application.getClass());
+ } else {
throw new RuntimeException(
String.format(
- "%s does not implement %s",
+ "%s does not implement %s or %s",
application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName()));
+ HasAndroidInjector.class.getCanonicalName(),
+ HasServiceInjector.class.getCanonicalName()));
}
- inject(service, (HasAndroidInjector) application);
+ injector.inject(service);
}
/**
@@ -135,21 +171,32 @@
* be found, otherwise throws an {@link IllegalArgumentException}.
*
* @throws RuntimeException if the {@link Application} from {@link
- * Context#getApplicationContext()} doesn't implement {@link HasAndroidInjector}.
+ * Context#getApplicationContext()} doesn't implement {@link HasAndroidInjector} or {@link
+ * HasBroadcastReceiverInjector}.
*/
public static void inject(BroadcastReceiver broadcastReceiver, Context context) {
checkNotNull(broadcastReceiver, "broadcastReceiver");
checkNotNull(context, "context");
+
Application application = (Application) context.getApplicationContext();
- if (!(application instanceof HasAndroidInjector)) {
+ AndroidInjector<? super BroadcastReceiver> injector;
+ if (application instanceof HasAndroidInjector) {
+ injector = ((HasAndroidInjector) application).androidInjector();
+ checkNotNull(injector, "%s.androidInjector() returned null", application.getClass());
+ } else if (application instanceof HasBroadcastReceiverInjector) {
+ injector = ((HasBroadcastReceiverInjector) application).broadcastReceiverInjector();
+ checkNotNull(
+ injector, "%s.broadcastReceiverInjector() returned null", application.getClass());
+ } else {
throw new RuntimeException(
String.format(
- "%s does not implement %s",
+ "%s does not implement %s or %s",
application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName()));
+ HasAndroidInjector.class.getCanonicalName(),
+ HasBroadcastReceiverInjector.class.getCanonicalName()));
}
- inject(broadcastReceiver, (HasAndroidInjector) application);
+ injector.inject(broadcastReceiver);
}
/**
@@ -157,28 +204,29 @@
* found, otherwise throws an {@link IllegalArgumentException}.
*
* @throws RuntimeException if the {@link Application} doesn't implement {@link
- * HasAndroidInjector}.
+ * HasAndroidInjector} or {@link HasContentProviderInjector}.
*/
public static void inject(ContentProvider contentProvider) {
checkNotNull(contentProvider, "contentProvider");
Application application = (Application) contentProvider.getContext().getApplicationContext();
- if (!(application instanceof HasAndroidInjector)) {
+
+ AndroidInjector<? super ContentProvider> injector;
+ if (application instanceof HasAndroidInjector) {
+ injector = ((HasAndroidInjector) application).androidInjector();
+ checkNotNull(injector, "%s.androidInjector() returned null", application.getClass());
+ } else if (application instanceof HasContentProviderInjector) {
+ injector = ((HasContentProviderInjector) application).contentProviderInjector();
+ checkNotNull(injector, "%s.contentProviderInjector() returned null", application.getClass());
+ } else {
throw new RuntimeException(
String.format(
- "%s does not implement %s",
+ "%s does not implement %s or %s",
application.getClass().getCanonicalName(),
- HasAndroidInjector.class.getCanonicalName()));
+ HasAndroidInjector.class.getCanonicalName(),
+ HasBroadcastReceiverInjector.class.getCanonicalName()));
}
- inject(contentProvider, (HasAndroidInjector) application);
- }
-
- private static void inject(Object target, HasAndroidInjector hasAndroidInjector) {
- AndroidInjector<Object> androidInjector = hasAndroidInjector.androidInjector();
- checkNotNull(
- androidInjector, "%s.androidInjector() returned null", hasAndroidInjector.getClass());
-
- androidInjector.inject(target);
+ injector.inject(contentProvider);
}
private AndroidInjection() {}
diff --git a/java/dagger/android/AndroidInjectionKey.java b/java/dagger/android/AndroidInjectionKey.java
index ff4a1f6..d4a5d72 100644
--- a/java/dagger/android/AndroidInjectionKey.java
+++ b/java/dagger/android/AndroidInjectionKey.java
@@ -28,7 +28,11 @@
* #value() value} of the annotation is the canonical name of the class that will be passed to
* {@link AndroidInjector#inject(Object)}.
*
- * <p>All key strings will be obfuscated by ProGuard/R8 if the named class is obfuscated.
+ * <p>All key strings will be obfuscated by ProGuard/R8/AppReduce if the named class is obfuscated.
+ *
+ * <p>
+ * You should only use this annotation if you are using a version of ProGuard/R8/AppReduce that
+ * supports the {@code -identifiernamestring} flag.
*/
@Beta
@MapKey
diff --git a/java/dagger/android/BUILD b/java/dagger/android/BUILD
index f0cea41..a88d16e 100644
--- a/java/dagger/android/BUILD
+++ b/java/dagger/android/BUILD
@@ -15,18 +15,15 @@
# Description:
# Public Dagger API for Android
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
- "POM_VERSION",
"SOURCE_7_TARGET_7",
)
-load("//tools:dejetify.bzl", "dejetified_library")
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-package(default_visibility = ["//:src"])
+load("//tools:maven.bzl", "POM_VERSION", "pom_file")
# Work around b/70476182 which prevents Kythe from connecting :producers to the .java files it
# contains.
@@ -45,18 +42,24 @@
srcs = SRCS,
javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
manifest = "AndroidManifest.xml",
- plugins = [
- "//java/dagger/android/internal/proguard:plugin",
- ],
+ proguard_specs = ["proguard.cfg"],
tags = ["maven_coordinates=com.google.dagger:dagger-android:" + POM_VERSION],
- exports = [
- "//java/dagger/lint:lint-android-artifact-lib",
- ],
deps = [
+ ":manual-maven-deps",
"//:dagger_with_compiler",
"@google_bazel_common//third_party/java/auto:value",
"@google_bazel_common//third_party/java/error_prone:annotations",
- "@maven//:androidx_annotation_annotation",
+ ],
+)
+
+# Our pom.xml generator does not have a way to add manual maven deps. This target exports the
+# targets that don't have the necessary maven_coordinates tags.
+android_library(
+ name = "manual-maven-deps",
+ tags = ["maven_coordinates=com.android.support:support-annotations:25.0.0"],
+ visibility = ["//visibility:private"],
+ exports = [
+ "@androidsdk//com.android.support:support-annotations-25.0.0",
],
)
@@ -76,35 +79,12 @@
targets = [":android"],
)
-dejetified_library(
- name = "dejetified-android",
- input = ":android.aar",
- output = "android-legacy.aar",
-)
-
-android_library(
- name = "legacy-deps",
- tags = ["maven_coordinates=com.google.dagger:dagger-android-legacy:" + POM_VERSION],
- exports = [
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@maven//:com_android_support_support_annotations",
- ],
-)
-
-pom_file(
- name = "legacy-pom",
- artifact_id = "dagger-android-legacy",
- artifact_name = "Dagger Android Legacy",
- packaging = "aar",
- targets = [":legacy-deps"],
-)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
javadoc_library(
name = "android-javadoc",
srcs = [":android-srcs"],
- android_api_level = 30,
+ android_api_level = 26,
exclude_packages = ["dagger.android.internal"],
root_packages = ["dagger.android"],
deps = [":android"],
diff --git a/java/dagger/android/DaggerActivity.java b/java/dagger/android/DaggerActivity.java
index 9f37223..43708f3 100644
--- a/java/dagger/android/DaggerActivity.java
+++ b/java/dagger/android/DaggerActivity.java
@@ -19,7 +19,7 @@
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
-import androidx.annotation.Nullable;
+import android.support.annotation.Nullable;
import dagger.internal.Beta;
import javax.inject.Inject;
diff --git a/java/dagger/android/DaggerBroadcastReceiver.java b/java/dagger/android/DaggerBroadcastReceiver.java
index 2efd724..d39aa86 100644
--- a/java/dagger/android/DaggerBroadcastReceiver.java
+++ b/java/dagger/android/DaggerBroadcastReceiver.java
@@ -19,7 +19,7 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import androidx.annotation.CallSuper;
+import android.support.annotation.CallSuper;
import dagger.internal.Beta;
/**
diff --git a/java/dagger/android/DaggerContentProvider.java b/java/dagger/android/DaggerContentProvider.java
index e1d3f54..4aad485 100644
--- a/java/dagger/android/DaggerContentProvider.java
+++ b/java/dagger/android/DaggerContentProvider.java
@@ -17,7 +17,7 @@
package dagger.android;
import android.content.ContentProvider;
-import androidx.annotation.CallSuper;
+import android.support.annotation.CallSuper;
import dagger.internal.Beta;
/** A {@link ContentProvider} that injects its members in {@link #onCreate()}. */
diff --git a/java/dagger/android/HasActivityInjector.java b/java/dagger/android/HasActivityInjector.java
new file mode 100644
index 0000000..136bbad
--- /dev/null
+++ b/java/dagger/android/HasActivityInjector.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.android;
+
+import android.app.Activity;
+import dagger.internal.Beta;
+
+/** Provides an {@link AndroidInjector} of {@link Activity}s. */
+@Beta
+public interface HasActivityInjector {
+
+ /** Returns an {@link AndroidInjector} of {@link Activity}s. */
+ AndroidInjector<Activity> activityInjector();
+}
diff --git a/java/dagger/android/HasBroadcastReceiverInjector.java b/java/dagger/android/HasBroadcastReceiverInjector.java
new file mode 100644
index 0000000..b2aa992
--- /dev/null
+++ b/java/dagger/android/HasBroadcastReceiverInjector.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.android;
+
+import android.content.BroadcastReceiver;
+import dagger.internal.Beta;
+
+/** Provides an {@link AndroidInjector} of {@link BroadcastReceiver}s. */
+@Beta
+public interface HasBroadcastReceiverInjector {
+
+ /** Returns an {@link AndroidInjector} of {@link BroadcastReceiver}s. */
+ AndroidInjector<BroadcastReceiver> broadcastReceiverInjector();
+}
diff --git a/java/dagger/android/HasContentProviderInjector.java b/java/dagger/android/HasContentProviderInjector.java
new file mode 100644
index 0000000..997ddb8
--- /dev/null
+++ b/java/dagger/android/HasContentProviderInjector.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.android;
+
+import android.content.ContentProvider;
+import dagger.internal.Beta;
+
+/** Provides an {@link AndroidInjector} of {@link ContentProvider}s. */
+@Beta
+public interface HasContentProviderInjector {
+
+ /** Returns an {@link AndroidInjector} of {@link ContentProvider}s. */
+ AndroidInjector<ContentProvider> contentProviderInjector();
+}
diff --git a/java/dagger/android/HasFragmentInjector.java b/java/dagger/android/HasFragmentInjector.java
new file mode 100644
index 0000000..564f32d
--- /dev/null
+++ b/java/dagger/android/HasFragmentInjector.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.android;
+
+import android.app.Fragment;
+import dagger.internal.Beta;
+
+/** Provides an {@link AndroidInjector} of {@link Fragment}s. */
+@Beta
+public interface HasFragmentInjector {
+
+ /** Returns an {@link AndroidInjector} of {@link Fragment}s. */
+ AndroidInjector<Fragment> fragmentInjector();
+}
diff --git a/java/dagger/android/HasServiceInjector.java b/java/dagger/android/HasServiceInjector.java
new file mode 100644
index 0000000..d1c6a6c
--- /dev/null
+++ b/java/dagger/android/HasServiceInjector.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 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.android;
+
+import android.app.Service;
+import dagger.internal.Beta;
+
+/** Provides an {@link AndroidInjector} of {@link Service}s. */
+@Beta
+public interface HasServiceInjector {
+
+ /** Returns an {@link AndroidInjector} of {@link Service}s. */
+ AndroidInjector<Service> serviceInjector();
+}
diff --git a/java/dagger/android/internal/AndroidInjectionKeys.java b/java/dagger/android/internal/AndroidInjectionKeys.java
index 1425350..f30b92c 100644
--- a/java/dagger/android/internal/AndroidInjectionKeys.java
+++ b/java/dagger/android/internal/AndroidInjectionKeys.java
@@ -20,7 +20,6 @@
* An internal implementation detail of Dagger's generated code. This is not guaranteed to remain
* consistent from version to version.
*/
-@GenerateAndroidInjectionProguardRules
public final class AndroidInjectionKeys {
/**
* Accepts the fully qualified name of a class that is injected with {@code dagger.android}.
diff --git a/java/dagger/android/internal/GenerateAndroidInjectionProguardRules.java b/java/dagger/android/internal/GenerateAndroidInjectionProguardRules.java
deleted file mode 100644
index 46bbb66..0000000
--- a/java/dagger/android/internal/GenerateAndroidInjectionProguardRules.java
+++ /dev/null
@@ -1,32 +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.android.internal;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Our proguard rules generator needs one annotation to hook into for it to run, so we use this
- * internally on {@link dagger.android.internal.AndroidInjectionKeys} as a throwaway for it to run.
- * It has no other purpose.
- */
-@Target(TYPE)
-@Retention(SOURCE)
-@interface GenerateAndroidInjectionProguardRules {}
diff --git a/java/dagger/android/internal/proguard/BUILD b/java/dagger/android/internal/proguard/BUILD
deleted file mode 100644
index a11d0c0..0000000
--- a/java/dagger/android/internal/proguard/BUILD
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Internal Proguard Processor
-
-load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "DOCLINT_REFERENCES")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "proguard-processor",
- srcs = ["ProguardProcessor.java"],
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- deps = [
- "@google_bazel_common//third_party/java/auto:service",
- ],
-)
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.android.internal.proguard.ProguardProcessor",
- deps = [":proguard-processor"],
-)
diff --git a/java/dagger/android/internal/proguard/ProguardProcessor.java b/java/dagger/android/internal/proguard/ProguardProcessor.java
deleted file mode 100644
index 49274e9..0000000
--- a/java/dagger/android/internal/proguard/ProguardProcessor.java
+++ /dev/null
@@ -1,93 +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.android.internal.proguard;
-
-import static javax.tools.StandardLocation.CLASS_OUTPUT;
-
-import com.google.auto.service.AutoService;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.TypeElement;
-
-/**
- * An {@linkplain Processor annotation processor} to generate dagger-android's specific proguard
- * needs. This is only intended to run over the dagger-android project itself, as the alternative is
- * to create an intermediary java_library for proguard rules to be consumed by the project.
- *
- * <p>Basic structure looks like this:
- *
- * <pre><code>
- * resources/META-INF/com.android.tools/proguard/dagger-android.pro
- * resources/META-INF/com.android.tools/r8/dagger-android.pro
- * resources/META-INF/proguard/dagger-android.pro
- * </code></pre>
- */
-@AutoService(Processor.class)
-@SupportedAnnotationTypes(ProguardProcessor.GENERATE_RULES_ANNOTATION_NAME)
-public final class ProguardProcessor extends AbstractProcessor {
-
- static final String GENERATE_RULES_ANNOTATION_NAME =
- "dagger.android.internal.GenerateAndroidInjectionProguardRules";
-
- @Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- roundEnv
- .getElementsAnnotatedWith(
- processingEnv.getElementUtils().getTypeElement(GENERATE_RULES_ANNOTATION_NAME))
- .forEach(element -> generate());
-
- return false;
- }
-
- private void generate() {
- Filer filer = processingEnv.getFiler();
-
- String errorProneRule = "-dontwarn com.google.errorprone.annotations.**\n";
- String androidInjectionKeysRule =
- "-identifiernamestring class dagger.android.internal.AndroidInjectionKeys {\n"
- + " java.lang.String of(java.lang.String);\n"
- + "}\n";
-
- writeFile(filer, "com.android.tools/proguard", errorProneRule);
- writeFile(filer, "com.android.tools/r8", errorProneRule + androidInjectionKeysRule);
- writeFile(filer, "proguard", errorProneRule);
- }
-
- private static void writeFile(Filer filer, String intermediatePath, String contents) {
- try (Writer writer =
- filer
- .createResource(
- CLASS_OUTPUT, "", "META-INF/" + intermediatePath + "/dagger-android.pro")
- .openWriter()) {
- writer.write(contents);
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latestSupported();
- }
-}
diff --git a/java/dagger/android/processor/AndroidProcessor.java b/java/dagger/android/processor/AndroidProcessor.java
index ad7f08e..5c17341 100644
--- a/java/dagger/android/processor/AndroidProcessor.java
+++ b/java/dagger/android/processor/AndroidProcessor.java
@@ -17,18 +17,23 @@
package dagger.android.processor;
import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.StandardLocation.CLASS_OUTPUT;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.common.BasicAnnotationProcessor;
import com.google.auto.service.AutoService;
import com.google.common.base.Ascii;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.googlejavaformat.java.filer.FormattingFiler;
+import java.io.IOException;
+import java.io.Writer;
import java.util.Set;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
@@ -93,6 +98,29 @@
}
@Override
+ protected void postRound(RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver() && useStringKeys()) {
+ try (Writer writer = createProguardFile()){
+ writer.write(
+ Joiner.on("\n")
+ .join(
+ "-identifiernamestring class dagger.android.internal.AndroidInjectionKeys {",
+ " java.lang.String of(java.lang.String);",
+ "}"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private Writer createProguardFile() throws IOException {
+ return processingEnv
+ .getFiler()
+ .createResource(CLASS_OUTPUT, "", "META-INF/proguard/dagger.android.AndroidInjectionKeys")
+ .openWriter();
+ }
+
+ @Override
public Set<String> getSupportedOptions() {
return ImmutableSet.of(FLAG_EXPERIMENTAL_USE_STRING_KEYS);
}
diff --git a/java/dagger/android/processor/BUILD b/java/dagger/android/processor/BUILD
index 7e63c76..5754143 100644
--- a/java/dagger/android/processor/BUILD
+++ b/java/dagger/android/processor/BUILD
@@ -15,17 +15,14 @@
# Description:
# Public Dagger API for Android
-load("@rules_java//java:defs.bzl", "java_import", "java_library", "java_plugin")
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
- "POM_VERSION",
)
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
-package(default_visibility = ["//:src"])
+load("//tools:maven.bzl", "POM_VERSION", "pom_file")
filegroup(
name = "srcs",
@@ -38,15 +35,15 @@
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
tags = ["maven_coordinates=com.google.dagger:dagger-android-processor:" + POM_VERSION],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/auto:service",
"@google_bazel_common//third_party/java/auto:value",
- "@maven//:com_google_auto_auto_common",
+ "@google_bazel_common//third_party/java/auto:common",
"@google_bazel_common//third_party/java/incap",
"@google_bazel_common//third_party/java/javapoet",
"@google_bazel_common//third_party/java/google_java_format",
"//java/dagger:core",
+ "//java/dagger/model",
"//java/dagger/spi",
# https://github.com/bazelbuild/bazel/issues/2517
":dagger-android-jar",
@@ -81,6 +78,8 @@
deps = [":processor"],
)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
javadoc_library(
name = "processor-javadoc",
srcs = [":srcs"],
diff --git a/java/dagger/android/proguard.cfg b/java/dagger/android/proguard.cfg
new file mode 100644
index 0000000..bd8ffbf
--- /dev/null
+++ b/java/dagger/android/proguard.cfg
@@ -0,0 +1 @@
+-dontwarn com.google.errorprone.annotations.**
diff --git a/java/dagger/android/support/AndroidSupportInjection.java b/java/dagger/android/support/AndroidSupportInjection.java
index c77e297..1624345 100644
--- a/java/dagger/android/support/AndroidSupportInjection.java
+++ b/java/dagger/android/support/AndroidSupportInjection.java
@@ -20,7 +20,8 @@
import static dagger.internal.Preconditions.checkNotNull;
import android.app.Activity;
-import androidx.fragment.app.Fragment;
+import android.app.Application;
+import android.support.v4.app.Fragment;
import android.util.Log;
import dagger.android.AndroidInjector;
import dagger.android.HasAndroidInjector;
@@ -35,59 +36,72 @@
* Injects {@code fragment} if an associated {@link AndroidInjector} implementation can be found,
* otherwise throws an {@link IllegalArgumentException}.
*
- * <p>Uses the following algorithm to find the appropriate {@code AndroidInjector<Fragment>} to
- * use to inject {@code fragment}:
+ * <p>Uses the following algorithm to find the appropriate {@link AndroidInjector} to use to
+ * inject {@code fragment}:
*
* <ol>
- * <li>Walks the parent-fragment hierarchy to find the a fragment that implements {@link
- * HasAndroidInjector}, and if none do
+ * <li>Walks the parent-fragment hierarchy to find a fragment that implements {@link
+ * HasAndroidInjector} or {@link HasSupportFragmentInjector}, and if none do
* <li>Uses the {@code fragment}'s {@link Fragment#getActivity() activity} if it implements
- * {@link HasAndroidInjector}, and if not
- * <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}.
+ * {@link HasAndroidInjector} or {@link HasSupportFragmentInjector}, and if not
+ * <li>Uses the {@link android.app.Application} if it implements {@link HasAndroidInjector}
+ * {@link HasSupportFragmentInjector}.
* </ol>
*
- * If none of them implement {@link HasAndroidInjector}, a {@link IllegalArgumentException} is
- * thrown.
+ * If none of them implement {@link HasAndroidInjector} or {@link HasSupportFragmentInjector}, a
+ * {@link IllegalArgumentException} is thrown.
*
* @throws IllegalArgumentException if no parent fragment, activity, or application implements
- * {@link HasAndroidInjector}.
+ * {@link HasAndroidInjector} or {@link HasSupportFragmentInjector}.
*/
public static void inject(Fragment fragment) {
checkNotNull(fragment, "fragment");
- HasAndroidInjector hasAndroidInjector = findHasAndroidInjectorForFragment(fragment);
+
+ Object hasInjector = findHasSupportFragmentInjector(fragment);
+ AndroidInjector<? super Fragment> injector;
+ if (hasInjector instanceof HasAndroidInjector) {
+ injector = ((HasAndroidInjector) hasInjector).androidInjector();
+ checkNotNull(injector, "%s.androidInjector() returned null", hasInjector.getClass());
+ } else if (hasInjector instanceof HasSupportFragmentInjector) {
+ injector = ((HasSupportFragmentInjector) hasInjector).supportFragmentInjector();
+ checkNotNull(injector, "%s.supportFragmentInjector() returned null", hasInjector.getClass());
+ } else {
+ throw new RuntimeException(
+ String.format(
+ "%s does not implement %s or %s",
+ hasInjector.getClass().getCanonicalName(),
+ HasAndroidInjector.class.getCanonicalName(),
+ HasSupportFragmentInjector.class.getCanonicalName()));
+ }
+
if (Log.isLoggable(TAG, DEBUG)) {
Log.d(
TAG,
String.format(
"An injector for %s was found in %s",
fragment.getClass().getCanonicalName(),
- hasAndroidInjector.getClass().getCanonicalName()));
+ hasInjector.getClass().getCanonicalName()));
}
- inject(fragment, hasAndroidInjector);
+ injector.inject(fragment);
}
- private static void inject(Object target, HasAndroidInjector hasAndroidInjector) {
- AndroidInjector<Object> androidInjector = hasAndroidInjector.androidInjector();
- checkNotNull(
- androidInjector, "%s.androidInjector() returned null", hasAndroidInjector.getClass());
-
- androidInjector.inject(target);
- }
-
- private static HasAndroidInjector findHasAndroidInjectorForFragment(Fragment fragment) {
+ private static Object findHasSupportFragmentInjector(Fragment fragment) {
Fragment parentFragment = fragment;
while ((parentFragment = parentFragment.getParentFragment()) != null) {
- if (parentFragment instanceof HasAndroidInjector) {
- return (HasAndroidInjector) parentFragment;
+ if (parentFragment instanceof HasAndroidInjector
+ || parentFragment instanceof HasSupportFragmentInjector) {
+ return parentFragment;
}
}
Activity activity = fragment.getActivity();
- if (activity instanceof HasAndroidInjector) {
- return (HasAndroidInjector) activity;
+ if (activity instanceof HasAndroidInjector || activity instanceof HasSupportFragmentInjector) {
+ return activity;
}
- if (activity.getApplication() instanceof HasAndroidInjector) {
- return (HasAndroidInjector) activity.getApplication();
+ Application application = activity.getApplication();
+ if (application instanceof HasAndroidInjector
+ || application instanceof HasSupportFragmentInjector) {
+ return application;
}
throw new IllegalArgumentException(
String.format("No injector was found for %s", fragment.getClass().getCanonicalName()));
diff --git a/java/dagger/android/support/BUILD b/java/dagger/android/support/BUILD
index 03846b5..749d541 100644
--- a/java/dagger/android/support/BUILD
+++ b/java/dagger/android/support/BUILD
@@ -15,17 +15,11 @@
# Description:
# Public Dagger API for Android that interacts with the Android support libraries
-load(
- "//:build_defs.bzl",
- "POM_VERSION",
- "SOURCE_7_TARGET_7",
-)
-load("//tools:dejetify.bzl", "dejetified_library")
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
package(default_visibility = ["//:src"])
+load("//:build_defs.bzl", "SOURCE_7_TARGET_7")
+load("//tools:maven.bzl", "pom_file", "POM_VERSION")
+
filegroup(
name = "support-srcs",
srcs = glob(["*.java"]),
@@ -38,12 +32,27 @@
manifest = "AndroidManifest.xml",
tags = ["maven_coordinates=com.google.dagger:dagger-android-support:" + POM_VERSION],
deps = [
+ ":manual-maven-deps",
"//:dagger_with_compiler",
"//java/dagger/android",
"@google_bazel_common//third_party/java/error_prone:annotations",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_appcompat_appcompat",
- "@maven//:androidx_fragment_fragment",
+ ],
+)
+
+# Our pom.xml generator does not have a way to add manual maven deps. This target exports the
+# targets that don't have the necessary maven_coordinates tags.
+android_library(
+ name = "manual-maven-deps",
+ tags = [
+ "maven_coordinates=com.android.support:appcompat-v7:25.0.0",
+ "maven_coordinates=com.android.support:support-annotations:25.0.0",
+ "maven_coordinates=com.android.support:support-fragment:25.0.0",
+ ],
+ visibility = ["//visibility:private"],
+ exports = [
+ "@androidsdk//com.android.support:appcompat-v7-25.0.0",
+ "@androidsdk//com.android.support:support-annotations-25.0.0",
+ "@androidsdk//com.android.support:support-fragment-25.0.0",
],
)
@@ -55,37 +64,12 @@
targets = [":support"],
)
-dejetified_library(
- name = "dejetified-support",
- input = ":support.aar",
- output = "support-legacy.aar",
-)
-
-android_library(
- name = "legacy-deps",
- tags = ["maven_coordinates=com.google.dagger:dagger-android-support-legacy:" + POM_VERSION],
- exports = [
- "//:dagger_with_compiler",
- "//java/dagger/android:legacy-deps",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@maven//:com_android_support_appcompat_v7",
- "@maven//:com_android_support_support_annotations",
- "@maven//:com_android_support_support_fragment",
- ],
-)
-
-pom_file(
- name = "legacy-pom",
- artifact_id = "dagger-android-support-legacy",
- artifact_name = "Dagger Android Legacy Support",
- packaging = "aar",
- targets = [":legacy-deps"],
-)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
javadoc_library(
name = "support-javadoc",
srcs = [":support-srcs"],
- android_api_level = 30,
+ android_api_level = 26,
root_packages = ["dagger.android.support"],
deps = [":support"],
)
diff --git a/java/dagger/android/support/DaggerAppCompatActivity.java b/java/dagger/android/support/DaggerAppCompatActivity.java
index da5b173..ccc4faa 100644
--- a/java/dagger/android/support/DaggerAppCompatActivity.java
+++ b/java/dagger/android/support/DaggerAppCompatActivity.java
@@ -17,10 +17,8 @@
package dagger.android.support;
import android.os.Bundle;
-import androidx.annotation.ContentView;
-import androidx.annotation.LayoutRes;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
import dagger.android.AndroidInjection;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
@@ -38,15 +36,6 @@
@Inject DispatchingAndroidInjector<Object> androidInjector;
- public DaggerAppCompatActivity() {
- super();
- }
-
- @ContentView
- public DaggerAppCompatActivity(@LayoutRes int contentLayoutId) {
- super(contentLayoutId);
- }
-
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
diff --git a/java/dagger/android/support/DaggerAppCompatDialogFragment.java b/java/dagger/android/support/DaggerAppCompatDialogFragment.java
index 7a5a76d..1efaeec 100644
--- a/java/dagger/android/support/DaggerAppCompatDialogFragment.java
+++ b/java/dagger/android/support/DaggerAppCompatDialogFragment.java
@@ -17,8 +17,8 @@
package dagger.android.support;
import android.content.Context;
-import androidx.fragment.app.Fragment;
-import androidx.appcompat.app.AppCompatDialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.AppCompatDialogFragment;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasAndroidInjector;
diff --git a/java/dagger/android/support/DaggerDialogFragment.java b/java/dagger/android/support/DaggerDialogFragment.java
index 8b0bf23..69b90bc 100644
--- a/java/dagger/android/support/DaggerDialogFragment.java
+++ b/java/dagger/android/support/DaggerDialogFragment.java
@@ -17,8 +17,8 @@
package dagger.android.support;
import android.content.Context;
-import androidx.fragment.app.DialogFragment;
-import androidx.fragment.app.Fragment;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasAndroidInjector;
diff --git a/java/dagger/android/support/DaggerFragment.java b/java/dagger/android/support/DaggerFragment.java
index 8874511..332cdaa 100644
--- a/java/dagger/android/support/DaggerFragment.java
+++ b/java/dagger/android/support/DaggerFragment.java
@@ -17,9 +17,7 @@
package dagger.android.support;
import android.content.Context;
-import androidx.annotation.ContentView;
-import androidx.annotation.LayoutRes;
-import androidx.fragment.app.Fragment;
+import android.support.v4.app.Fragment;
import dagger.android.AndroidInjector;
import dagger.android.DispatchingAndroidInjector;
import dagger.android.HasAndroidInjector;
@@ -36,15 +34,6 @@
@Inject DispatchingAndroidInjector<Object> androidInjector;
- public DaggerFragment() {
- super();
- }
-
- @ContentView
- public DaggerFragment(@LayoutRes int contentLayoutId) {
- super(contentLayoutId);
- }
-
@Override
public void onAttach(Context context) {
AndroidSupportInjection.inject(this);
diff --git a/java/dagger/android/support/HasSupportFragmentInjector.java b/java/dagger/android/support/HasSupportFragmentInjector.java
new file mode 100644
index 0000000..e80609e
--- /dev/null
+++ b/java/dagger/android/support/HasSupportFragmentInjector.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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.android.support;
+
+import android.support.v4.app.Fragment;
+import dagger.android.AndroidInjector;
+import dagger.internal.Beta;
+
+/** Provides an {@link AndroidInjector} of {@link Fragment}s. */
+@Beta
+public interface HasSupportFragmentInjector {
+
+ /** Returns an {@link AndroidInjector} of {@link Fragment}s. */
+ AndroidInjector<Fragment> supportFragmentInjector();
+}
diff --git a/java/dagger/assisted/Assisted.java b/java/dagger/assisted/Assisted.java
deleted file mode 100644
index 59d8eec..0000000
--- a/java/dagger/assisted/Assisted.java
+++ /dev/null
@@ -1,82 +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.assisted;
-
-import static java.lang.annotation.ElementType.PARAMETER;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates a parameter within an {@link AssistedInject}-annotated constructor.
- *
- * <p>See {@link AssistedInject}.
- */
-@Documented
-@Retention(RUNTIME)
-@Target(PARAMETER)
-public @interface Assisted {
-
- /**
- * Returns an identifier for an {@link Assisted} parameter.
- *
- * <p>Within an {@link AssistedInject} constructor, each {@link Assisted} parameter must be
- * uniquely defined by the combination of its identifier and type. If no identifier is specified,
- * the default identifier is an empty string. Thus, the following parameters are equivalent within
- * an {@link AssistedInject} constructor:
- *
- * <ul>
- * <li> {@code @Assisted Foo foo}
- * <li> {@code @Assisted("") Foo foo}
- * </ul>
- *
- * <p>Within an {@link AssistedFactory} method, each parameter must match an {@link Assisted}
- * parameter in the associated {@link AssistedInject} constructor (i.e. identifier + type).
- * A parameter with no {@code @Assisted} annotation will be assigned the default identifier. Thus,
- * the following parameters are equivalent within an {@link AssistedFactory} method:
- *
- * <ul>
- * <li> {@code Foo foo}
- * <li> {@code @Assisted Foo foo}
- * <li> {@code @Assisted("") Foo foo}
- * </ul>
- *
- * <p>Example:
- *
- * <pre><code>
- * final class DataService {
- * {@literal @}AssistedInject
- * DataService(
- * BindingFromDagger bindingFromDagger,
- * {@literal @}Assisted String name,
- * {@literal @}Assisted("id") String id,
- * {@literal @}Assisted("repo") String repo) {}
- * }
- *
- * {@literal @}AssistedFactory
- * interface DataServiceFactory {
- * DataService create(
- * String name,
- * {@literal @}Assisted("id") String id,
- * {@literal @}Assisted("repo") String repo);
- * }
- * </code></pre>
- */
- String value() default "";
-}
diff --git a/java/dagger/assisted/AssistedFactory.java b/java/dagger/assisted/AssistedFactory.java
deleted file mode 100644
index 4eba9a7..0000000
--- a/java/dagger/assisted/AssistedFactory.java
+++ /dev/null
@@ -1,47 +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.assisted;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates an abstract class or interface used to create an instance of a type via an {@link
- * AssistedInject} constructor.
- *
- * <p>An {@link AssistedFactory}-annotated type must obey the following constraints:
- *
- * <ul>
- * <li>The type must be an abstract class or interface,
- * <li>The type must contain exactly one abstract, non-default method whose
- * <ul>
- * <li>return type must exactly match the type of an assisted injection type, and
- * <li>parameters must match the exact list of {@link Assisted} parameters in the assisted
- * injection type's constructor (and in the same order).
- * </ul>
- * </ul>
- *
- * See {@link AssistedInject}
- */
-@Documented
-@Retention(RUNTIME)
-@Target(TYPE)
-public @interface AssistedFactory {}
diff --git a/java/dagger/assisted/AssistedInject.java b/java/dagger/assisted/AssistedInject.java
deleted file mode 100644
index fadd46d..0000000
--- a/java/dagger/assisted/AssistedInject.java
+++ /dev/null
@@ -1,80 +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.assisted;
-
-import static java.lang.annotation.ElementType.CONSTRUCTOR;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotates the constuctor of a type that will be created via assisted injection.
- *
- * <p>Note that an assisted injection type cannot be scoped. In addition, assisted injection
- * requires the use of a factory annotated with {@link AssistedFactory} (see the example below).
- *
- * <p>Example usage:
- *
- * <p>Suppose we have a type, {@code DataService}, that has two dependencies: {@code DataFetcher}
- * and {@code Config}. When creating {@code DataService}, we would like to pass in an instance of
- * {@code Config} manually rather than having Dagger create it for us. This can be done using
- * assisted injection.
- *
- * <p>To start, we annotate the {@code DataService} constructor with {@link AssistedInject} and we
- * annotate the {@code Config} parameter with {@link Assisted}, as shown below:
- *
- * <pre><code>
- * final class DataService {
- * private final DataFetcher dataFetcher;
- * private final Config config;
- *
- * {@literal @}AssistedInject
- * DataService(DataFetcher dataFetcher, {@literal @}Assisted Config config) {
- * this.dataFetcher = dataFetcher;
- * this.config = config;
- * }
- * }
- * </code></pre>
- *
- * <p>Next, we define a factory for the assisted type, {@code DataService}, and annotate it with
- * {@link AssistedFactory}. The factory must contain a single abstract, non-default method which
- * takes in all of the assisted parameters (in order) and returns the assisted type.
- *
- * <pre><code>
- * {@literal @}AssistedFactory
- * interface DataServiceFactory {
- * DataService create(Config config);
- * }
- * </code></pre>
- *
- * <p>Dagger will generate an implementation of the factory and bind it to the factory type. The
- * factory can then be used to create an instance of the assisted type:
- *
- * <pre><code>
- * class MyApplication {
- * {@literal @}Inject DataServiceFactory dataServiceFactory;
- *
- * dataService = dataServiceFactory.create(new Config(...));
- * }
- * </code></pre>
- */
-@Documented
-@Retention(RUNTIME)
-@Target(CONSTRUCTOR)
-public @interface AssistedInject {}
diff --git a/java/dagger/assisted/package-info.java b/java/dagger/assisted/package-info.java
deleted file mode 100644
index 9b8b7f0..0000000
--- a/java/dagger/assisted/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-/**
- * This package contains the API for Dagger's assisted injection.
- *
- * TODO(bcorso): Link to dagger.dev documentation.
- */
-package dagger.assisted;
diff --git a/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java b/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java
index bc0be48..e98fe9b 100644
--- a/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java
+++ b/java/dagger/errorprone/AndroidSupportInjectionModuleMigrator.java
@@ -19,6 +19,7 @@
import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION;
import com.google.errorprone.BugPattern;
+import com.google.errorprone.BugPattern.ProvidesFix;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MemberSelectTreeMatcher;
@@ -34,6 +35,7 @@
/** A refactoring to update AndroidInjector bindings to their new form. */
@BugPattern(
name = "AndroidSupportInjectionModuleMigrator",
+ providesFix = ProvidesFix.REQUIRES_HUMAN_ATTENTION,
summary = "Inlines usages of AndroidSupportInjectionModule to AndroidInjectionModule",
explanation =
"AndroidSupportInjectionModule is now an empty module and acts as an alias for "
diff --git a/java/dagger/errorprone/BUILD b/java/dagger/errorprone/BUILD
index 9c3707f..408925a 100644
--- a/java/dagger/errorprone/BUILD
+++ b/java/dagger/errorprone/BUILD
@@ -1,8 +1,6 @@
# Description:
# ErrorProne refactorings and static analysis for Dagger
-load("@rules_java//java:defs.bzl", "java_library")
-
package(default_visibility = ["//:src"])
java_library(
@@ -10,8 +8,8 @@
srcs = glob(["*.java"]),
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:collect",
"@bazel_tools//tools/jdk:langtools-neverlink",
"@google_bazel_common//third_party/java/error_prone:check_api",
+ "@google_bazel_common//third_party/java/guava",
],
)
diff --git a/java/dagger/example/BUILD b/java/dagger/example/BUILD
deleted file mode 100644
index 1973229..0000000
--- a/java/dagger/example/BUILD
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2017 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 examples.
-
-package(default_visibility = ["//:src"])
diff --git a/java/dagger/example/android/simple/AndroidManifest.xml b/java/dagger/example/android/simple/AndroidManifest.xml
new file mode 100644
index 0000000..711fb1e
--- /dev/null
+++ b/java/dagger/example/android/simple/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<!--
+ ~ Copyright (C) 2017 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="dagger.example.android.simple">
+
+ <uses-sdk
+ android:minSdkVersion="14"
+ android:targetSdkVersion="24"/>
+
+ <application android:name=".SimpleApplication" android:label="@string/appName">
+ <activity android:name=".MainActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/java/dagger/example/android/simple/BUILD b/java/dagger/example/android/simple/BUILD
new file mode 100644
index 0000000..7396744
--- /dev/null
+++ b/java/dagger/example/android/simple/BUILD
@@ -0,0 +1,42 @@
+# Copyright (C) 2017 The Dagger Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Description:
+# A skeletal application that demonstates wiring for an injected Application and Actiity.
+
+package(default_visibility = ["//:src"])
+
+android_library(
+ name = "simple_lib",
+ srcs = glob(["*.java"]),
+ manifest = "AndroidManifest.xml",
+ resource_files = glob(["res/**"]),
+ deps = [
+ "//:android",
+ "//:android-support",
+ "//:dagger_with_compiler",
+ "@androidsdk//com.android.support:appcompat-v7-25.0.0",
+ "@androidsdk//com.android.support:support-annotations-25.0.0",
+ "@androidsdk//com.android.support:support-fragment-25.0.0",
+ ],
+)
+
+android_binary(
+ name = "simple",
+ aapt_version = "aapt",
+ manifest = "AndroidManifest.xml",
+ deps = [
+ ":simple_lib",
+ ],
+)
diff --git a/java/dagger/example/android/simple/BuildModule.java b/java/dagger/example/android/simple/BuildModule.java
new file mode 100644
index 0000000..40ac8ee
--- /dev/null
+++ b/java/dagger/example/android/simple/BuildModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.example.android.simple;
+
+import static android.os.Build.MODEL;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+final class BuildModule {
+ @Provides
+ @Model
+ static String provideModel() {
+ return MODEL;
+ }
+}
diff --git a/java/dagger/example/android/simple/MainActivity.java b/java/dagger/example/android/simple/MainActivity.java
new file mode 100644
index 0000000..f2aab2d
--- /dev/null
+++ b/java/dagger/example/android/simple/MainActivity.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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.example.android.simple;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.TextView;
+import dagger.Binds;
+import dagger.android.AndroidInjector;
+import dagger.android.support.DaggerAppCompatActivity;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+import javax.inject.Inject;
+
+/**
+ * The main activity application. It can be injected with any binding from both {@link Component}
+ * and {@link dagger.example.android.simple.SimpleApplication.Component}.
+ */
+public class MainActivity extends DaggerAppCompatActivity {
+ @dagger.Subcomponent
+ interface Component extends AndroidInjector<MainActivity> {
+
+ @dagger.Subcomponent.Builder
+ abstract class Builder extends AndroidInjector.Builder<MainActivity> {}
+ }
+
+ @dagger.Module(subcomponents = Component.class)
+ abstract class Module {
+
+ @Binds
+ @IntoMap
+ @ClassKey(MainActivity.class)
+ abstract AndroidInjector.Factory<?> bind(Component.Builder builder);
+ }
+
+ private static final String TAG = MainActivity.class.getSimpleName();
+
+ @Inject @Model String model;
+
+ @Inject
+ void logInjection() {
+ Log.i(TAG, "Injecting " + MainActivity.class.getSimpleName());
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_main);
+
+ TextView greeting = (TextView) findViewById(R.id.greeting);
+ String text = getResources().getString(R.string.welcome, model);
+ greeting.setText(text);
+ }
+}
diff --git a/java/dagger/example/android/simple/Model.java b/java/dagger/example/android/simple/Model.java
new file mode 100644
index 0000000..c52bb98
--- /dev/null
+++ b/java/dagger/example/android/simple/Model.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 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.example.android.simple;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
+@Qualifier
+@Retention(RUNTIME)
+@Documented
+@interface Model {}
diff --git a/java/dagger/example/android/simple/SimpleApplication.java b/java/dagger/example/android/simple/SimpleApplication.java
new file mode 100644
index 0000000..ae3d42d
--- /dev/null
+++ b/java/dagger/example/android/simple/SimpleApplication.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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.example.android.simple;
+
+import android.util.Log;
+import dagger.android.AndroidInjectionModule;
+import dagger.android.AndroidInjector;
+import dagger.android.DaggerApplication;
+import javax.inject.Inject;
+
+/**
+ * A simple, skeletal application that demonstrates a dependency-injected application using the
+ * utilities in {@code dagger.android}.
+ */
+public class SimpleApplication extends DaggerApplication {
+ private static final String TAG = SimpleApplication.class.getSimpleName();
+
+ @dagger.Component(
+ modules = {AndroidInjectionModule.class, MainActivity.Module.class, BuildModule.class})
+ /* @ApplicationScoped and/or @Singleton */
+ interface Component extends AndroidInjector<SimpleApplication> {
+ @dagger.Component.Builder
+ abstract class Builder extends AndroidInjector.Builder<SimpleApplication> {}
+ }
+
+ @Inject
+ void logInjection() {
+ Log.i(TAG, "Injecting " + SimpleApplication.class.getSimpleName());
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ protected AndroidInjector<SimpleApplication> applicationInjector() {
+ return DaggerSimpleApplication_Component.builder().create(this);
+ }
+}
diff --git a/java/dagger/example/android/simple/res/layout/activity_main.xml b/java/dagger/example/android/simple/res/layout/activity_main.xml
new file mode 100644
index 0000000..37add1f
--- /dev/null
+++ b/java/dagger/example/android/simple/res/layout/activity_main.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 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.
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/background_light">
+
+ <TextView
+ android:id="@+id/greeting"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentTop="true"
+ android:textColor="@android:color/primary_text_light"
+ style="@style/TextAppearance.AppCompat.Display4"
+ />
+</RelativeLayout>
diff --git a/java/dagger/example/android/simple/res/values/strings.xml b/java/dagger/example/android/simple/res/values/strings.xml
new file mode 100644
index 0000000..c4ba1fd
--- /dev/null
+++ b/java/dagger/example/android/simple/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="appName">Simple Dagger</string>
+ <string name="welcome">Hello, %s!</string>
+</resources>
\ No newline at end of file
diff --git a/java/dagger/example/atm/AccountModule.java b/java/dagger/example/atm/AccountModule.java
deleted file mode 100644
index 3ff5a75..0000000
--- a/java/dagger/example/atm/AccountModule.java
+++ /dev/null
@@ -1,30 +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.example.atm;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.example.atm.Database.Account;
-
-/** Bindings for the {@link Account} of the currently signed-in user. */
-@Module
-interface AccountModule {
- @Provides
- static Account account(Database database, @Username String username) {
- return database.getAccount(username);
- }
-}
diff --git a/java/dagger/example/atm/AmountsModule.java b/java/dagger/example/atm/AmountsModule.java
deleted file mode 100644
index 87e5e01..0000000
--- a/java/dagger/example/atm/AmountsModule.java
+++ /dev/null
@@ -1,38 +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.example.atm;
-
-import dagger.Module;
-import dagger.Provides;
-import java.math.BigDecimal;
-
-/** Configures various amounts of money the application uses to control transactions. */
-@Module
-abstract class AmountsModule {
-
- @Provides
- @MinimumBalance
- static BigDecimal minimumBalance() {
- return BigDecimal.ZERO;
- }
-
- @Provides
- @MaximumWithdrawal
- static BigDecimal maximumWithdrawal() {
- return new BigDecimal(1000);
- }
-}
diff --git a/java/dagger/example/atm/BUILD b/java/dagger/example/atm/BUILD
deleted file mode 100644
index d1ff505..0000000
--- a/java/dagger/example/atm/BUILD
+++ /dev/null
@@ -1,33 +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.
-
-# Description:
-# An example of using dagger in a computerized fake ATM. The User's Guide (https://dagger.dev/users-guide)
-# is a walkthrough that ultimately builds this example.
-
-load("@rules_java//java:defs.bzl", "java_binary", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "atm",
- srcs = glob(["*.java"]),
- deps = ["//:dagger_with_compiler"],
-)
-
-java_binary(
- name = "CommandLineAtm",
- main_class = "dagger.example.atm.CommandLineAtm",
- runtime_deps = [":atm"],
-)
diff --git a/java/dagger/example/atm/BigDecimalCommand.java b/java/dagger/example/atm/BigDecimalCommand.java
deleted file mode 100644
index 29bd6f5..0000000
--- a/java/dagger/example/atm/BigDecimalCommand.java
+++ /dev/null
@@ -1,56 +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.example.atm;
-
-import java.math.BigDecimal;
-
-/**
- * Abstract {@link Command} that expects a single argument that can be converted to {@link
- * BigDecimal}.
- */
-abstract class BigDecimalCommand extends SingleArgCommand {
-
- private final Outputter outputter;
-
- protected BigDecimalCommand(Outputter outputter) {
- this.outputter = outputter;
- }
-
- @Override
- protected final Result handleArg(String arg) {
- BigDecimal amount = tryParse(arg);
- if (amount == null) {
- outputter.output(arg + " is not a valid number");
- } else if (amount.signum() <= 0) {
- outputter.output("amount must be positive");
- } else {
- handleAmount(amount);
- }
- return Result.handled();
- }
-
- private static BigDecimal tryParse(String arg) {
- try {
- return new BigDecimal(arg);
- } catch (NumberFormatException e) {
- return null;
- }
- }
-
- /** Handles the given (positive) {@code amount} of money. */
- protected abstract void handleAmount(BigDecimal amount);
-}
diff --git a/java/dagger/example/atm/Command.java b/java/dagger/example/atm/Command.java
deleted file mode 100644
index a3ff0d0..0000000
--- a/java/dagger/example/atm/Command.java
+++ /dev/null
@@ -1,82 +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.example.atm;
-
-import java.util.List;
-import java.util.Optional;
-
-/** A text-based command handler. */
-interface Command {
- /**
- * Processes and optionally acts upon the given {@code input}.
- *
- * @return a {@link Result} indicating how the input was handled
- */
- Result handleInput(List<String> input);
-
- /**
- * A command result, which has a {@link Status} and optionally a new {@link CommandRouter} that
- * will handle subsequent commands.
- */
- final class Result {
- private final Status status;
- private final Optional<CommandRouter> nestedCommandRouter;
-
- private Result(Status status, Optional<CommandRouter> nestedCommandRouter) {
- this.status = status;
- this.nestedCommandRouter = nestedCommandRouter;
- }
-
- static Result invalid() {
- return new Result(Status.INVALID, Optional.empty());
- }
-
- static Result handled() {
- return new Result(Status.HANDLED, Optional.empty());
- }
-
- static Result inputCompleted() {
- return new Result(Status.INPUT_COMPLETED, Optional.empty());
- }
-
- static Result enterNestedCommandSet(CommandRouter nestedCommandRouter) {
- return new Result(Status.HANDLED, Optional.of(nestedCommandRouter));
- }
-
- Status status() {
- return status;
- }
-
- Optional<CommandRouter> nestedCommandRouter() {
- return nestedCommandRouter;
- }
- }
-
- enum Status {
- /** The command or its arguments were invalid. */
- INVALID,
-
- /** The command handled the input and no other commands should attempt to handle it. */
- HANDLED,
-
- // TODO(ronshapiro): maybe call this TERMINATED? If so, maybe this should be called
- // ContinueStatus?
- /** The command handled the input and no further inputs should be submitted. */
- INPUT_COMPLETED,
- ;
- }
-}
diff --git a/java/dagger/example/atm/CommandLineAtm.java b/java/dagger/example/atm/CommandLineAtm.java
deleted file mode 100644
index be5cbe6..0000000
--- a/java/dagger/example/atm/CommandLineAtm.java
+++ /dev/null
@@ -1,36 +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.example.atm;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.util.Scanner;
-
-/** Main class for the command-line ATM. */
-class CommandLineAtm {
- public static void main(String[] args) {
- Scanner scanner = new Scanner(System.in, UTF_8.name());
- CommandProcessor commandProcessor = CommandProcessorFactory.create().commandProcessor();
-
- while (scanner.hasNextLine()) {
- Command.Status commandStatus = commandProcessor.process(scanner.nextLine());
- if (commandStatus.equals(Command.Status.INPUT_COMPLETED)) {
- break;
- }
- }
- }
-}
diff --git a/java/dagger/example/atm/CommandProcessor.java b/java/dagger/example/atm/CommandProcessor.java
deleted file mode 100644
index 3b52d73..0000000
--- a/java/dagger/example/atm/CommandProcessor.java
+++ /dev/null
@@ -1,67 +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.example.atm;
-
-import dagger.example.atm.Command.Result;
-import dagger.example.atm.Command.Status;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Processes successive commands by delegating to a {@link CommandRouter}.
- *
- * <p>Whereas {@link CommandRouter} routes an input string to a particular {@link Command}, this
- * class maintains inter-command state to determine which {@link CommandRouter} should route
- * successive commands.
- *
- * <p>This class is {@link Singleton} scoped because it has mutable state ({@code
- * commandRouterStack}), and all users of {@link CommandProcessor} must use the same instance.
- */
-@Singleton
-final class CommandProcessor {
- private final Deque<CommandRouter> commandRouterStack = new ArrayDeque<>();
-
- @Inject
- CommandProcessor(CommandRouter firstCommandRouter) {
- commandRouterStack.push(firstCommandRouter);
- }
-
- Status process(String input) {
- if (commandRouterStack.isEmpty()) {
- throw new IllegalStateException("No command router is available!");
- }
-
- Result result = commandRouterStack.peek().route(input);
- switch (result.status()) {
- case INPUT_COMPLETED:
- commandRouterStack.pop();
- return commandRouterStack.isEmpty() ? Status.INPUT_COMPLETED : Status.HANDLED;
- case HANDLED:
- // TODO(ronshapiro): We currently have a case of using a subcomponent for nested commands,
- // which requires maintaining a binding indicating whether we are in the subcomponent are
- // not. We can include another example where there's a CommandRouter that is created from an
- // entirely different component, that way there are no inherited commands.
- result.nestedCommandRouter().ifPresent(commandRouterStack::push);
- // fall through
- case INVALID:
- return result.status();
- }
- throw new AssertionError(result.status());
- }
-}
diff --git a/java/dagger/example/atm/CommandProcessorFactory.java b/java/dagger/example/atm/CommandProcessorFactory.java
deleted file mode 100644
index a449703..0000000
--- a/java/dagger/example/atm/CommandProcessorFactory.java
+++ /dev/null
@@ -1,44 +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.example.atm;
-
-import dagger.Component;
-import javax.inject.Singleton;
-
-/**
- * Hand-written API for interfacing with Dagger. The command-line ATM needs a single class to
- * execute: {@link CommandProcessor}.
- *
- * <p>The list of {@code modules} declares where Dagger should look, besides {@link
- * javax.inject.Inject}-annotated constructors, to help instantiate {@link CommandProcessor} and its
- * dependencies.
- */
-@Singleton
-@Component(
- modules = {
- CommandsModule.class,
- InMemoryDatabaseModule.class,
- UserCommandsRouter.InstallationModule.class,
- SystemOutModule.class,
- })
-interface CommandProcessorFactory {
- CommandProcessor commandProcessor();
-
- static CommandProcessorFactory create() {
- return DaggerCommandProcessorFactory.create();
- }
-}
diff --git a/java/dagger/example/atm/CommandRouter.java b/java/dagger/example/atm/CommandRouter.java
deleted file mode 100644
index ef75220..0000000
--- a/java/dagger/example/atm/CommandRouter.java
+++ /dev/null
@@ -1,66 +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.example.atm;
-
-import dagger.example.atm.Command.Result;
-import dagger.example.atm.Command.Status;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import javax.inject.Inject;
-
-/** Routes individual text commands to the appropriate {@link Command}(s). */
-final class CommandRouter {
- private final Map<String, Command> commands;
- private final Outputter outputter;
-
- @Inject
- CommandRouter(Map<String, Command> commands, Outputter outputter) {
- this.commands = commands;
- this.outputter = outputter;
- }
-
- /**
- * Calls {@link Command#handleInput(String) command.handleInput(input)} on this router's
- * {@linkplain #commands commands}.
- */
- Result route(String input) {
- List<String> splitInput = split(input);
- if (splitInput.isEmpty()) {
- return invalidCommand(input);
- }
-
- String commandKey = splitInput.get(0);
- Command command = commands.get(commandKey);
- if (command == null) {
- return invalidCommand(input);
- }
-
- List<String> args = splitInput.subList(1, splitInput.size());
- Result result = command.handleInput(args);
- return result.status().equals(Status.INVALID) ? invalidCommand(input) : result;
- }
-
- private Result invalidCommand(String input) {
- outputter.output(String.format("couldn't understand \"%s\". please try again.", input));
- return Result.invalid();
- }
-
- private static List<String> split(String input) {
- return Arrays.asList(input.trim().split("\\s+"));
- }
-}
diff --git a/java/dagger/example/atm/CommandsModule.java b/java/dagger/example/atm/CommandsModule.java
deleted file mode 100644
index 266af12..0000000
--- a/java/dagger/example/atm/CommandsModule.java
+++ /dev/null
@@ -1,45 +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.example.atm;
-
-import dagger.Binds;
-import dagger.BindsOptionalOf;
-import dagger.Module;
-import dagger.example.atm.Database.Account;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-
-/** Installs basic commands. */
-@Module
-interface CommandsModule {
- @Binds
- @IntoMap
- @StringKey("hello")
- Command helloWorld(HelloWorldCommand command);
-
- @Binds
- @IntoMap
- @StringKey("login")
- Command login(LoginCommand command);
-
- /**
- * Declare an optional binding for {@link Account}. This allows other bindings to change their
- * behavior depending on whether an {@link Account} is bound in the current (sub)component.
- */
- @BindsOptionalOf
- Account loggedInAccount();
-}
diff --git a/java/dagger/example/atm/Database.java b/java/dagger/example/atm/Database.java
deleted file mode 100644
index f6c0eda..0000000
--- a/java/dagger/example/atm/Database.java
+++ /dev/null
@@ -1,35 +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.example.atm;
-
-import java.math.BigDecimal;
-
-/** An ATM database. */
-interface Database {
- Account getAccount(String username);
-
- /** An individual user's account. */
- interface Account {
- String username();
-
- void deposit(BigDecimal amount);
-
- void withdraw(BigDecimal amount);
-
- BigDecimal balance();
- }
-}
diff --git a/java/dagger/example/atm/DepositCommand.java b/java/dagger/example/atm/DepositCommand.java
deleted file mode 100644
index 9a5e2e2..0000000
--- a/java/dagger/example/atm/DepositCommand.java
+++ /dev/null
@@ -1,43 +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.example.atm;
-
-import dagger.example.atm.Database.Account;
-import java.math.BigDecimal;
-import javax.inject.Inject;
-
-/** Deposits money to the ATM. */
-final class DepositCommand extends BigDecimalCommand {
- private final Outputter outputter;
- private final Account account;
- private final WithdrawalLimiter withdrawalLimiter;
-
- @Inject
- DepositCommand(Outputter outputter, Account account, WithdrawalLimiter withdrawalLimiter) {
- super(outputter);
- this.outputter = outputter;
- this.account = account;
- this.withdrawalLimiter = withdrawalLimiter;
- }
-
- @Override
- protected void handleAmount(BigDecimal amount) {
- account.deposit(amount);
- withdrawalLimiter.recordDeposit(amount);
- outputter.output("your new balance is: " + account.balance());
- }
-}
diff --git a/java/dagger/example/atm/HelloWorldCommand.java b/java/dagger/example/atm/HelloWorldCommand.java
deleted file mode 100644
index f39d585..0000000
--- a/java/dagger/example/atm/HelloWorldCommand.java
+++ /dev/null
@@ -1,38 +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.example.atm;
-
-import java.util.List;
-import javax.inject.Inject;
-
-final class HelloWorldCommand implements Command {
- private final Outputter outputter;
-
- @Inject
- HelloWorldCommand(Outputter outputter) {
- this.outputter = outputter;
- }
-
- @Override
- public Result handleInput(List<String> args) {
- if (!args.isEmpty()) {
- return Result.invalid();
- }
- outputter.output("howdy!");
- return Result.handled();
- }
-}
diff --git a/java/dagger/example/atm/InMemoryDatabase.java b/java/dagger/example/atm/InMemoryDatabase.java
deleted file mode 100644
index 801d827..0000000
--- a/java/dagger/example/atm/InMemoryDatabase.java
+++ /dev/null
@@ -1,75 +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.example.atm;
-
-import java.math.BigDecimal;
-import java.util.HashMap;
-import java.util.Map;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** A database that stores all of its data in memory. */
-@Singleton
-final class InMemoryDatabase implements Database {
- private final Map<String, Account> accounts = new HashMap<>();
-
- @Inject
- InMemoryDatabase() {}
-
- @Override
- public Account getAccount(String username) {
- return accounts.computeIfAbsent(username, InMemoryAccount::new);
- }
-
- private static final class InMemoryAccount implements Account {
- private final String username;
- private BigDecimal balance = BigDecimal.ZERO;
-
- InMemoryAccount(String username) {
- this.username = username;
- }
-
- @Override
- public String username() {
- return username;
- }
-
- @Override
- public void deposit(BigDecimal amount) {
- checkNonNegative(amount, "deposit");
- balance = balance.add(amount);
- }
-
- @Override
- public void withdraw(BigDecimal amount) {
- checkNonNegative(amount, "withdraw");
- balance = balance.subtract(amount);
- }
-
- private void checkNonNegative(BigDecimal amount, String action) {
- if (amount.signum() == -1) {
- throw new IllegalArgumentException(
- String.format("Cannot %s negative amounts: %s", action, amount));
- }
- }
-
- @Override
- public BigDecimal balance() {
- return balance;
- }
- }
-}
diff --git a/java/dagger/example/atm/InMemoryDatabaseModule.java b/java/dagger/example/atm/InMemoryDatabaseModule.java
deleted file mode 100644
index bf4be67..0000000
--- a/java/dagger/example/atm/InMemoryDatabaseModule.java
+++ /dev/null
@@ -1,26 +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.example.atm;
-
-import dagger.Binds;
-import dagger.Module;
-
-@Module
-interface InMemoryDatabaseModule {
- @Binds
- Database inMemory(InMemoryDatabase database);
-}
diff --git a/java/dagger/example/atm/LoginCommand.java b/java/dagger/example/atm/LoginCommand.java
deleted file mode 100644
index 4978cb5..0000000
--- a/java/dagger/example/atm/LoginCommand.java
+++ /dev/null
@@ -1,55 +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.example.atm;
-
-import dagger.example.atm.Database.Account;
-import java.util.Optional;
-import javax.inject.Inject;
-
-/** Logs in a user, allowing them to interact with the ATM. */
-final class LoginCommand extends SingleArgCommand {
- private final Outputter outputter;
- private final Optional<Account> account;
- private final UserCommandsRouter.Factory userCommandsFactory;
-
- @Inject
- LoginCommand(
- Outputter outputter,
- Optional<Account> account,
- UserCommandsRouter.Factory userCommandsFactory) {
- this.outputter = outputter;
- this.account = account;
- this.userCommandsFactory = userCommandsFactory;
- }
-
- @Override
- public Result handleArg(String username) {
- // If an Account binding exists, that means there is a user logged in. Don't allow a login
- // command if we already have someone logged in!
- if (account.isPresent()) {
- String loggedInUser = account.get().username();
- outputter.output(loggedInUser + " is already logged in");
- if (!loggedInUser.equals(username)) {
- outputter.output("run `logout` first before trying to log in another user");
- }
- return Result.handled();
- } else {
- UserCommandsRouter userCommands = userCommandsFactory.create(username);
- return Result.enterNestedCommandSet(userCommands.router());
- }
- }
-}
diff --git a/java/dagger/example/atm/LogoutCommand.java b/java/dagger/example/atm/LogoutCommand.java
deleted file mode 100644
index 811d4b3..0000000
--- a/java/dagger/example/atm/LogoutCommand.java
+++ /dev/null
@@ -1,43 +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.example.atm;
-
-import dagger.example.atm.Database.Account;
-import java.util.List;
-import javax.inject.Inject;
-
-/** Logs out the current user. */
-final class LogoutCommand implements Command {
-
- private final Outputter outputter;
- private final Account account;
-
- @Inject
- LogoutCommand(Outputter outputter, Account account) {
- this.outputter = outputter;
- this.account = account;
- }
-
- @Override
- public Result handleInput(List<String> input) {
- if (!input.isEmpty()) {
- return Result.invalid();
- }
- outputter.output("logged out " + account.username());
- return Result.inputCompleted();
- }
-}
diff --git a/java/dagger/example/atm/MaximumWithdrawal.java b/java/dagger/example/atm/MaximumWithdrawal.java
deleted file mode 100644
index d41c559..0000000
--- a/java/dagger/example/atm/MaximumWithdrawal.java
+++ /dev/null
@@ -1,31 +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.example.atm;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * Qualifier for the maximum amount that can be withdrawn from an account in a single transaction.
- */
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-@interface MaximumWithdrawal {}
diff --git a/java/dagger/example/atm/MinimumBalance.java b/java/dagger/example/atm/MinimumBalance.java
deleted file mode 100644
index bbb0ed1..0000000
--- a/java/dagger/example/atm/MinimumBalance.java
+++ /dev/null
@@ -1,29 +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.example.atm;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifier for the minimum balance an account may have. */
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-@interface MinimumBalance {}
diff --git a/java/dagger/example/atm/Outputter.java b/java/dagger/example/atm/Outputter.java
deleted file mode 100644
index 3d8de8a..0000000
--- a/java/dagger/example/atm/Outputter.java
+++ /dev/null
@@ -1,22 +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.example.atm;
-
-/** Writes to a user interface. */
-interface Outputter {
- void output(String output);
-}
diff --git a/java/dagger/example/atm/PerSession.java b/java/dagger/example/atm/PerSession.java
deleted file mode 100644
index 22faba5..0000000
--- a/java/dagger/example/atm/PerSession.java
+++ /dev/null
@@ -1,29 +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.example.atm;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/** A scope for instances that should be retained within a user session. */
-@Retention(RUNTIME)
-@Scope
-@Documented
-@interface PerSession {}
diff --git a/java/dagger/example/atm/SingleArgCommand.java b/java/dagger/example/atm/SingleArgCommand.java
deleted file mode 100644
index 81e5f65..0000000
--- a/java/dagger/example/atm/SingleArgCommand.java
+++ /dev/null
@@ -1,31 +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.example.atm;
-
-import java.util.List;
-
-/** Abstract command that accepts a single argument. */
-abstract class SingleArgCommand implements Command {
-
- @Override
- public final Result handleInput(List<String> input) {
- return input.size() == 1 ? handleArg(input.get(0)) : Result.invalid();
- }
-
- /** Handles the single argument to the command. */
- protected abstract Result handleArg(String arg);
-}
diff --git a/java/dagger/example/atm/SystemOutModule.java b/java/dagger/example/atm/SystemOutModule.java
deleted file mode 100644
index 3c22941..0000000
--- a/java/dagger/example/atm/SystemOutModule.java
+++ /dev/null
@@ -1,28 +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.example.atm;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class SystemOutModule {
- @Provides
- static Outputter textOutputter() {
- return System.out::println;
- }
-}
diff --git a/java/dagger/example/atm/UserCommandsModule.java b/java/dagger/example/atm/UserCommandsModule.java
deleted file mode 100644
index bee4450..0000000
--- a/java/dagger/example/atm/UserCommandsModule.java
+++ /dev/null
@@ -1,41 +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.example.atm;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-
-/** Commands that are only applicable when a user is logged in. */
-@Module
-interface UserCommandsModule {
- @Binds
- @IntoMap
- @StringKey("deposit")
- Command deposit(DepositCommand command);
-
- @Binds
- @IntoMap
- @StringKey("withdraw")
- Command withdraw(WithdrawCommand command);
-
- @Binds
- @IntoMap
- @StringKey("logout")
- Command logout(LogoutCommand command);
-}
diff --git a/java/dagger/example/atm/UserCommandsRouter.java b/java/dagger/example/atm/UserCommandsRouter.java
deleted file mode 100644
index 7d65989..0000000
--- a/java/dagger/example/atm/UserCommandsRouter.java
+++ /dev/null
@@ -1,35 +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.example.atm;
-
-import dagger.BindsInstance;
-import dagger.Module;
-import dagger.Subcomponent;
-
-@PerSession
-@Subcomponent(modules = {AccountModule.class, AmountsModule.class, UserCommandsModule.class})
-interface UserCommandsRouter {
- CommandRouter router();
-
- @Subcomponent.Factory
- interface Factory {
- UserCommandsRouter create(@BindsInstance @Username String username);
- }
-
- @Module(subcomponents = UserCommandsRouter.class)
- interface InstallationModule {}
-}
diff --git a/java/dagger/example/atm/Username.java b/java/dagger/example/atm/Username.java
deleted file mode 100644
index 7972844..0000000
--- a/java/dagger/example/atm/Username.java
+++ /dev/null
@@ -1,29 +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.example.atm;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifier for the currently logged-in user. */
-@Retention(RUNTIME)
-@Qualifier
-@Documented
-@interface Username {}
diff --git a/java/dagger/example/atm/WithdrawCommand.java b/java/dagger/example/atm/WithdrawCommand.java
deleted file mode 100644
index 7e0cf04..0000000
--- a/java/dagger/example/atm/WithdrawCommand.java
+++ /dev/null
@@ -1,67 +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.example.atm;
-
-import dagger.example.atm.Database.Account;
-import java.math.BigDecimal;
-import javax.inject.Inject;
-
-/** Withdraws money from the ATM. */
-final class WithdrawCommand extends BigDecimalCommand {
- private final Outputter outputter;
- private final Account account;
- private final BigDecimal minimumBalance;
- private final WithdrawalLimiter withdrawalLimiter;
-
- @Inject
- WithdrawCommand(
- Outputter outputter,
- Account account,
- @MinimumBalance BigDecimal minimumBalance,
- WithdrawalLimiter withdrawalLimiter) {
- super(outputter);
- this.outputter = outputter;
- this.account = account;
- this.minimumBalance = minimumBalance;
- this.withdrawalLimiter = withdrawalLimiter;
- }
-
- @Override
- protected void handleAmount(BigDecimal amount) {
- BigDecimal remainingWithdrawalLimit = withdrawalLimiter.remainingWithdrawalLimit();
- if (amount.compareTo(remainingWithdrawalLimit) > 0) {
- outputter.output(
- String.format(
- "you may not withdraw %s; you may withdraw %s more in this session",
- amount, remainingWithdrawalLimit));
- return;
- }
-
- BigDecimal newBalance = account.balance().subtract(amount);
- if (newBalance.compareTo(minimumBalance) < 0) {
- outputter.output(
- String.format(
- "you don't have sufficient funds to withdraw %s. "
- + "your balance is %s and the minimum balance is %s",
- amount, account.balance(), minimumBalance));
- } else {
- account.withdraw(amount);
- withdrawalLimiter.recordWithdrawal(amount);
- outputter.output("your new balance is: " + account.balance());
- }
- }
-}
diff --git a/java/dagger/example/atm/WithdrawalLimiter.java b/java/dagger/example/atm/WithdrawalLimiter.java
deleted file mode 100644
index c473b68..0000000
--- a/java/dagger/example/atm/WithdrawalLimiter.java
+++ /dev/null
@@ -1,43 +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.example.atm;
-
-import java.math.BigDecimal;
-import javax.inject.Inject;
-
-/** Maintains the withdrawal amount available within a user session. */
-@PerSession
-final class WithdrawalLimiter {
- private BigDecimal remainingWithdrawalLimit;
-
- @Inject
- WithdrawalLimiter(@MaximumWithdrawal BigDecimal maximumWithdrawal) {
- this.remainingWithdrawalLimit = maximumWithdrawal;
- }
-
- void recordDeposit(BigDecimal amount) {
- remainingWithdrawalLimit = remainingWithdrawalLimit.add(amount);
- }
-
- void recordWithdrawal(BigDecimal amount) {
- remainingWithdrawalLimit = remainingWithdrawalLimit.subtract(amount);
- }
-
- BigDecimal remainingWithdrawalLimit() {
- return remainingWithdrawalLimit;
- }
-}
diff --git a/java/dagger/example/atm/build.gradle b/java/dagger/example/atm/build.gradle
deleted file mode 100644
index 2e6d3f4..0000000
--- a/java/dagger/example/atm/build.gradle
+++ /dev/null
@@ -1,44 +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.
- */
-
-plugins {
- id 'java'
- id 'application'
-}
-
-repositories {
- mavenCentral()
-}
-
-sourceSets {
- main {
- java {
- srcDir '.'
- }
- }
-}
-
-dependencies {
- implementation 'com.google.dagger:dagger:2.23.2'
- annotationProcessor 'com.google.dagger:dagger-compiler:2.23.2'
-}
-
-mainClassName = 'dagger.example.atm.CommandLineAtm'
-
-// Run with: `gradle run -q --console=plain`
-run {
- standardInput = System.in
-}
diff --git a/java/dagger/example/atm/gradlew b/java/dagger/example/atm/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/java/dagger/example/atm/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/java/dagger/example/atm/gradlew.bat b/java/dagger/example/atm/gradlew.bat
deleted file mode 100644
index 9991c50..0000000
--- a/java/dagger/example/atm/gradlew.bat
+++ /dev/null
@@ -1,100 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/java/dagger/example/atm/settings.gradle b/java/dagger/example/atm/settings.gradle
deleted file mode 100644
index a6f2e01..0000000
--- a/java/dagger/example/atm/settings.gradle
+++ /dev/null
@@ -1,17 +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.
- */
-
-rootProject.name = 'dagger-tutorial-atm'
diff --git a/java/dagger/example/gradle/android/simple/app/build.gradle b/java/dagger/example/gradle/android/simple/app/build.gradle
deleted file mode 100644
index d8f6346..0000000
--- a/java/dagger/example/gradle/android/simple/app/build.gradle
+++ /dev/null
@@ -1,41 +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.
- */
-
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.example.gradle.android.simple"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
-}
-
-dependencies {
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- implementation 'com.google.dagger:dagger-android-support:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
-
- // To help us catch usages of Guava APIs for Java 8 in the '-jre' variant.
- annotationProcessor'com.google.guava:guava:28.1-android'
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml b/java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml
deleted file mode 100644
index cc666d2..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- ~ Copyright (C) 2017 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.example.gradle.android.simple">
-
- <application
- android:name=".SimpleApplication"
- android:label="@string/appName"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".SimpleActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/BuildModule.java b/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/BuildModule.java
deleted file mode 100644
index f6317c2..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/BuildModule.java
+++ /dev/null
@@ -1,31 +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.example.gradle.android.simple;
-
-import static android.os.Build.MODEL;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class BuildModule {
- @Provides
- @Model
- static String provideModel() {
- return MODEL;
- }
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/Model.java b/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/Model.java
deleted file mode 100644
index 30a973e..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/Model.java
+++ /dev/null
@@ -1,29 +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.example.gradle.android.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface Model {}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java b/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java
deleted file mode 100644
index 734590a..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleActivity.java
+++ /dev/null
@@ -1,73 +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.example.gradle.android.simple;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.TextView;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjector;
-import dagger.android.support.DaggerAppCompatActivity;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import javax.inject.Inject;
-
-/**
- * The main activity of the application.
- *
- * <p>It can be injected with any binding from both {@link SimpleActivityComponent} and {@link
- * SimpleApplication.SimpleComponent}.
- */
-public class SimpleActivity extends DaggerAppCompatActivity {
- @Subcomponent
- interface SimpleActivityComponent extends AndroidInjector<SimpleActivity> {
-
- @Subcomponent.Factory
- interface Factory extends AndroidInjector.Factory<SimpleActivity> {}
- }
-
- @Module(subcomponents = SimpleActivityComponent.class)
- abstract static class InjectorModule {
-
- @Binds
- @IntoMap
- @ClassKey(SimpleActivity.class)
- abstract AndroidInjector.Factory<?> bind(SimpleActivityComponent.Factory factory);
- }
-
- private static final String TAG = SimpleActivity.class.getSimpleName();
-
- @Inject @Model String model;
-
- @Inject
- void logInjection() {
- Log.i(TAG, "Injecting");
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- TextView greeting = (TextView) findViewById(R.id.greeting);
- String text = getResources().getString(R.string.welcome, model);
- greeting.setText(text);
- }
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java b/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java
deleted file mode 100644
index e2e34ea..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/java/dagger/example/gradle/android/simple/SimpleApplication.java
+++ /dev/null
@@ -1,61 +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.example.gradle.android.simple;
-
-import android.util.Log;
-import dagger.Component;
-import dagger.android.AndroidInjectionModule;
-import dagger.android.AndroidInjector;
-import dagger.android.DaggerApplication;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A simple, skeletal application that demonstrates a dependency-injected application using the
- * utilities in {@code dagger.android}.
- */
-public class SimpleApplication extends DaggerApplication {
- private static final String TAG = SimpleApplication.class.getSimpleName();
-
- @Singleton
- @Component(
- modules = {
- AndroidInjectionModule.class,
- SimpleActivity.InjectorModule.class,
- BuildModule.class
- }
- )
- interface SimpleComponent extends AndroidInjector<SimpleApplication> {
- @Component.Factory
- interface Factory extends AndroidInjector.Factory<SimpleApplication> {}
- }
-
- @Inject
- void logInjection() {
- Log.i(TAG, "Injecting " + SimpleApplication.class.getSimpleName());
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- }
-
- @Override
- protected AndroidInjector<SimpleApplication> applicationInjector() {
- return DaggerSimpleApplication_SimpleComponent.factory().create(this);
- }
-}
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml b/java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 18a547b..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-</RelativeLayout>
diff --git a/java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml b/java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml
deleted file mode 100644
index f45fd41..0000000
--- a/java/dagger/example/gradle/android/simple/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="appName">Simple Dagger Android</string>
- <string name="welcome">Hello, %s!</string>
-</resources>
diff --git a/java/dagger/example/gradle/android/simple/build.gradle b/java/dagger/example/gradle/android/simple/build.gradle
deleted file mode 100644
index 50f8f0b..0000000
--- a/java/dagger/example/gradle/android/simple/build.gradle
+++ /dev/null
@@ -1,35 +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.
- */
-
-buildscript {
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
-
diff --git a/java/dagger/example/gradle/android/simple/gradle.properties b/java/dagger/example/gradle/android/simple/gradle.properties
deleted file mode 100644
index 2d8d1e4..0000000
--- a/java/dagger/example/gradle/android/simple/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-android.useAndroidX=true
\ No newline at end of file
diff --git a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.jar b/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.properties b/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/java/dagger/example/gradle/android/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/java/dagger/example/gradle/android/simple/gradlew b/java/dagger/example/gradle/android/simple/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/java/dagger/example/gradle/android/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/java/dagger/example/gradle/android/simple/settings.gradle b/java/dagger/example/gradle/android/simple/settings.gradle
deleted file mode 100644
index c5a07bc..0000000
--- a/java/dagger/example/gradle/android/simple/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-include ':app'
-rootProject.name='Simple Dagger Android'
\ No newline at end of file
diff --git a/java/dagger/example/gradle/simple/SimpleApplication.java b/java/dagger/example/gradle/simple/SimpleApplication.java
deleted file mode 100644
index 11552f8..0000000
--- a/java/dagger/example/gradle/simple/SimpleApplication.java
+++ /dev/null
@@ -1,48 +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.example.gradle.simple;
-
-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();
- }
-}
diff --git a/java/dagger/example/gradle/simple/build.gradle b/java/dagger/example/gradle/simple/build.gradle
deleted file mode 100644
index c9e59ef..0000000
--- a/java/dagger/example/gradle/simple/build.gradle
+++ /dev/null
@@ -1,40 +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.
- */
-
-plugins {
- id 'java'
- id 'application'
-}
-
-repositories {
- mavenCentral()
- mavenLocal()
-}
-
-sourceSets {
- main {
- java {
- srcDir '.'
- }
- }
-}
-
-dependencies {
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
-}
-
-mainClassName = 'dagger.example.gradle.simple.SimpleApplication'
\ No newline at end of file
diff --git a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar b/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties b/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/java/dagger/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/java/dagger/example/gradle/simple/gradlew b/java/dagger/example/gradle/simple/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/java/dagger/example/gradle/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/java/dagger/example/spi/BUILD b/java/dagger/example/spi/BUILD
index bd889c3..84b4a87 100644
--- a/java/dagger/example/spi/BUILD
+++ b/java/dagger/example/spi/BUILD
@@ -15,20 +15,17 @@
# Description:
# An example of the dagger.spi.BindingGraphPlugin usage
-load("@rules_java//java:defs.bzl", "java_plugin")
-
package(default_visibility = ["//:src"])
java_plugin(
name = "binding-graph-visualizer",
srcs = glob(["*.java"]),
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
+ "//java/dagger/model",
"//java/dagger/spi",
"@google_bazel_common//third_party/java/auto:service",
"@google_bazel_common//third_party/java/error_prone:annotations",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
],
)
diff --git a/java/dagger/grpc/server/BUILD b/java/dagger/grpc/server/BUILD
index d9a2f97..1c57807 100644
--- a/java/dagger/grpc/server/BUILD
+++ b/java/dagger/grpc/server/BUILD
@@ -1,17 +1,10 @@
# A framework supporting Dagger-injected gRPC servers.
-load("@rules_java//java:defs.bzl", "java_library")
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "DOCLINT_REFERENCES",
- "POM_VERSION",
-)
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
package(default_visibility = ["//:src"])
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "DOCLINT_REFERENCES")
+load("//tools:maven.bzl", "pom_file", "POM_VERSION")
+
ANNOTATIONS_SRCS = [
"CallScoped.java",
"ForGrpcService.java",
@@ -41,13 +34,12 @@
exports = [":annotations"],
deps = [
"//:dagger_with_compiler",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"@google_bazel_common//third_party/java/auto:value",
"@google_bazel_common//third_party/java/grpc:context",
"@google_bazel_common//third_party/java/grpc:core",
"@google_bazel_common//third_party/java/grpc:netty",
"@google_bazel_common//third_party/java/grpc:protobuf",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr330_inject",
"@google_bazel_common//third_party/java/protobuf",
],
@@ -72,6 +64,8 @@
srcs = glob(["*.java"]),
)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
javadoc_library(
name = "javadoc",
srcs = [":javadoc-srcs"],
diff --git a/java/dagger/grpc/server/README.md b/java/dagger/grpc/server/README.md
index a864f36..5fe8d5c 100644
--- a/java/dagger/grpc/server/README.md
+++ b/java/dagger/grpc/server/README.md
@@ -7,4 +7,4 @@
It is in development, and is planned for open-source release as part of Dagger.
-See user documentation at https://dagger.dev/dev-guide/grpc.
+See user documentation at https://dagger.dev/grpc.
diff --git a/java/dagger/grpc/server/processor/BUILD b/java/dagger/grpc/server/processor/BUILD
index dd33651..ce02b06 100644
--- a/java/dagger/grpc/server/processor/BUILD
+++ b/java/dagger/grpc/server/processor/BUILD
@@ -1,14 +1,8 @@
-load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
-load(
- "//:build_defs.bzl",
- "DOCLINT_HTML_AND_SYNTAX",
- "POM_VERSION",
-)
-load("//tools:maven.bzl", "pom_file")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-
package(default_visibility = ["//:src"])
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
+load("//tools:maven.bzl", "pom_file", "POM_VERSION")
+
java_library(
name = "processor",
srcs = glob(["*.java"]),
@@ -17,14 +11,12 @@
deps = [
"//:dagger_with_compiler",
"//java/dagger/grpc/server:annotations",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:io",
+ "@google_bazel_common//third_party/java/auto:common",
"@google_bazel_common//third_party/java/auto:service",
"@google_bazel_common//third_party/java/google_java_format",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
"@google_bazel_common//third_party/java/jsr250_annotations",
- "@maven//:com_google_auto_auto_common",
],
)
@@ -47,6 +39,8 @@
srcs = glob(["*.java"]),
)
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
javadoc_library(
name = "javadoc",
srcs = [":javadoc-srcs"],
diff --git a/java/dagger/grpc/server/processor/GrpcServiceProcessor.java b/java/dagger/grpc/server/processor/GrpcServiceProcessor.java
index 9b74454..e361fdb 100644
--- a/java/dagger/grpc/server/processor/GrpcServiceProcessor.java
+++ b/java/dagger/grpc/server/processor/GrpcServiceProcessor.java
@@ -40,7 +40,7 @@
/**
* Generates code from types annotated with {@link GrpcService @GrpcService}.
*
- * @see <a href="https://dagger.dev/dev-guide/grpc">https://dagger.dev/dev-guide/grpc</a>
+ * @see <a href="https://dagger.dev/grpc">https://dagger.dev/grpc</a>
*/
@AutoService(Processor.class)
public class GrpcServiceProcessor extends BasicAnnotationProcessor implements ProcessingStep {
diff --git a/java/dagger/hilt/BUILD b/java/dagger/hilt/BUILD
deleted file mode 100644
index 94af18a..0000000
--- a/java/dagger/hilt/BUILD
+++ /dev/null
@@ -1,240 +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.
-
-load("//tools:maven.bzl", "gen_maven_artifact")
-load("//:build_defs.bzl", "POM_VERSION_ALPHA")
-
-# Description:
-# A library that wraps the Dagger API to make DI usage and testing easier.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "install_in",
- srcs = ["InstallIn.java"],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/aggregateddeps:plugin",
- ],
- exports = [
- "//java/dagger/hilt/processor/internal/aggregateddeps:annotation",
- ],
- deps = [
- ":generates_root_input",
- ":package_info",
- ],
-)
-
-java_library(
- name = "entry_point",
- srcs = [
- "EntryPoint.java",
- "EntryPoints.java",
- ],
- exported_plugins = [
- # This is required so that we can fail if @InstallIn is missing.
- # TODO(bcorso): Consider using a separate processor to validate @EntryPoint.
- "//java/dagger/hilt/processor/internal/aggregateddeps:plugin",
- ],
- deps = [
- ":generates_root_input",
- ":package_info",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:generated_component",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
-
-java_library(
- name = "generates_root_input",
- srcs = [
- "GeneratesRootInput.java",
- ],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor",
- ],
- exports = [
- "//java/dagger/hilt/internal/generatesrootinput",
- ],
- deps = [
- ":package_info",
- ],
-)
-
-java_library(
- name = "define_component",
- srcs = [
- "DefineComponent.java",
- ],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/definecomponent:processor",
- ],
- exports = [
- "//java/dagger/hilt/internal/definecomponent",
- ],
- deps = [
- ":generates_root_input",
- ":package_info",
- "//java/dagger/hilt/internal/definecomponent",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
- deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
-
-filegroup(
- name = "javadoc-srcs",
- srcs = [
- ":hilt_android_filegroup",
- ":hilt_android_testing_filegroup",
- ":hilt_filegroup",
- ":hilt_testing_filegroup",
- ],
-)
-
-filegroup(
- name = "hilt_filegroup",
- 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",
- ],
-)
-
-filegroup(
- name = "hilt_testing_filegroup",
- srcs = [
- "//java/dagger/hilt/testing:srcs_filegroup",
- ],
-)
-
-filegroup(
- name = "hilt_android_filegroup",
- srcs = [
- "//java/dagger/hilt/android:srcs_filegroup",
- "//java/dagger/hilt/android/components:srcs_filegroup",
- "//java/dagger/hilt/android/internal:srcs_filegroup",
- "//java/dagger/hilt/android/internal/builders:srcs_filegroup",
- "//java/dagger/hilt/android/internal/lifecycle:srcs_filegroup",
- "//java/dagger/hilt/android/internal/managers:srcs_filegroup",
- "//java/dagger/hilt/android/internal/migration:srcs_filegroup",
- "//java/dagger/hilt/android/internal/modules:srcs_filegroup",
- "//java/dagger/hilt/android/lifecycle:srcs_filegroup",
- "//java/dagger/hilt/android/migration:srcs_filegroup",
- "//java/dagger/hilt/android/plugin:srcs_filegroup",
- "//java/dagger/hilt/android/qualifiers:srcs_filegroup",
- "//java/dagger/hilt/android/scopes:srcs_filegroup",
- ],
-)
-
-filegroup(
- name = "hilt_android_testing_filegroup",
- srcs = [
- "//java/dagger/hilt/android/internal/testing:srcs_filegroup",
- "//java/dagger/hilt/android/testing:srcs_filegroup",
- ],
-)
-
-filegroup(
- name = "hilt_processing_filegroup",
- srcs = [
- "//java/dagger/hilt/android/processor:srcs_filegroup",
- "//java/dagger/hilt/android/processor/internal:srcs_filegroup",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:srcs_filegroup",
- "//java/dagger/hilt/android/processor/internal/bindvalue:srcs_filegroup",
- "//java/dagger/hilt/android/processor/internal/customtestapplication:srcs_filegroup",
- "//java/dagger/hilt/android/processor/internal/uninstallmodules:srcs_filegroup",
- "//java/dagger/hilt/android/processor/internal/viewmodel:srcs_filegroup",
- "//java/dagger/hilt/processor:srcs_filegroup",
- "//java/dagger/hilt/processor/internal:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/aggregateddeps:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/aliasof:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/definecomponent:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/disableinstallincheck:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/generatesrootinput:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/originatingelement:srcs_filegroup",
- "//java/dagger/hilt/processor/internal/root:srcs_filegroup",
- ],
-)
-
-java_library(
- name = "artifact-core-lib",
- tags = ["maven_coordinates=com.google.dagger:hilt-core:" + POM_VERSION_ALPHA],
- exports = [
- ":define_component",
- ":entry_point",
- ":generates_root_input",
- ":install_in",
- ":package_info",
- "//java/dagger:core",
- "//java/dagger/hilt/components",
- "//java/dagger/hilt/migration:alias_of",
- "//java/dagger/hilt/migration:disable_install_in_check",
- ],
-)
-
-gen_maven_artifact(
- name = "artifact-core",
- artifact_coordinates = "com.google.dagger:hilt-core:" + POM_VERSION_ALPHA,
- artifact_name = "Hilt Core",
- artifact_target = ":artifact-core-lib",
- artifact_target_libs = [
- "//java/dagger/hilt:define_component",
- "//java/dagger/hilt:entry_point",
- "//java/dagger/hilt:generates_root_input",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt:package_info",
- "//java/dagger/hilt/codegen:originating_element",
- "//java/dagger/hilt/codegen:package_info",
- "//java/dagger/hilt/components",
- "//java/dagger/hilt/components:package_info",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:generated_component",
- "//java/dagger/hilt/internal:preconditions",
- "//java/dagger/hilt/internal:unsafe_casts",
- "//java/dagger/hilt/internal/aliasof",
- "//java/dagger/hilt/internal/definecomponent",
- "//java/dagger/hilt/internal/generatesrootinput",
- "//java/dagger/hilt/migration:alias_of",
- "//java/dagger/hilt/migration:disable_install_in_check",
- "//java/dagger/hilt/migration:package_info",
- "//java/dagger/hilt/processor/internal/aggregateddeps:annotation",
- ],
- artifact_target_maven_deps = [
- "com.google.code.findbugs:jsr305",
- "com.google.dagger:dagger",
- "javax.inject:javax.inject",
- ],
- artifact_target_maven_deps_banned = [
- "com.google.guava:guava",
- "javax.annotation:jsr250-api",
- ],
- javadoc_exclude_packages = [
- "dagger.hilt.internal",
- ],
- javadoc_root_packages = [
- "dagger.hilt",
- ],
- javadoc_srcs = [
- "//java/dagger/hilt:hilt_filegroup",
- ],
-)
diff --git a/java/dagger/hilt/DefineComponent.java b/java/dagger/hilt/DefineComponent.java
deleted file mode 100644
index fcd572c..0000000
--- a/java/dagger/hilt/DefineComponent.java
+++ /dev/null
@@ -1,68 +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;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.internal.definecomponent.DefineComponentNoParent;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Defines a Hilt component.
- *
- * <p>Example defining a root component, {@code ParentComponent}:
- *
- * <pre><code>
- * {@literal @}ParentScoped
- * {@literal @}DefineComponent
- * interface ParentComponent {}
- * </code></pre>
- *
- * <p>Example defining a child component, {@code ChildComponent}:
- *
- * <pre><code>
- * {@literal @}ChildScoped
- * {@literal @}DefineComponent(parent = ParentComponent.class)
- * interface ChildComponent {}
- * </code></pre>
- */
-@Retention(CLASS)
-@Target(TYPE)
-@GeneratesRootInput
-public @interface DefineComponent {
- /** Returns the parent of this component, if it exists. */
- Class<?> parent() default DefineComponentNoParent.class;
-
- /**
- * Defines a builder for a Hilt component.
- *
- * <pre><code>
- * {@literal @}DefineComponent.Builder
- * interface ParentComponentBuilder {
- * ParentComponentBuilder seedData(SeedData seed);
- * ParentComponent build();
- * }
- * </code></pre>
- */
- // TODO(bcorso): Consider making this a top-level class to hint that it doesn't need to be nested.
- @Retention(CLASS)
- @Target(TYPE)
- @GeneratesRootInput
- public @interface Builder {}
-}
diff --git a/java/dagger/hilt/EntryPoint.java b/java/dagger/hilt/EntryPoint.java
deleted file mode 100644
index e216e77..0000000
--- a/java/dagger/hilt/EntryPoint.java
+++ /dev/null
@@ -1,50 +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;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for marking an interface as an entry point into a generated component. This annotation
- * must be used with {@link dagger.hilt.InstallIn} to indicate which component(s) should have this
- * entry point. When assembling components, Hilt will make the indicated components extend the
- * interface marked with this annotation.
- *
- * <p>To use the annotated interface to access Dagger objects, use {@link dagger.hilt.EntryPoints}.
- *
- * <p>Example usage:
- *
- * <pre><code>
- * {@literal @}EntryPoint
- * {@literal @}InstallIn(SingletonComponent.class)
- * public interface FooEntryPoint {
- * Foo getFoo();
- * }
- *
- * Foo foo = EntryPoints.get(component, FooEntryPoint.class).getFoo();
- * </code></pre>
- *
- * @see <a href="https://dagger.dev/hilt/entry-points">Entry points</a>
- */
-@Retention(CLASS)
-@Target(ElementType.TYPE)
-@GeneratesRootInput
-public @interface EntryPoint {}
diff --git a/java/dagger/hilt/EntryPoints.java b/java/dagger/hilt/EntryPoints.java
deleted file mode 100644
index 32e2312..0000000
--- a/java/dagger/hilt/EntryPoints.java
+++ /dev/null
@@ -1,56 +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;
-
-import dagger.hilt.internal.GeneratedComponent;
-import dagger.hilt.internal.GeneratedComponentManager;
-import javax.annotation.Nonnull;
-
-/** Static utility methods for accessing objects through entry points. */
-public final class EntryPoints {
-
- /**
- * Returns the entry point interface given a component or component manager. Note that this
- * performs an unsafe cast and so callers should be sure that the given component/component
- * manager matches the entry point interface that is given.
- *
- * @param component The Hilt-generated component instance. For convenience, also takes component
- * manager instances as well.
- * @param entryPoint The interface marked with {@link dagger.hilt.EntryPoint}. The {@link
- * dagger.hilt.InstallIn} annotation on this entry point should match the component argument
- * above.
- */
- // Note that the input is not statically declared to be a Component or ComponentManager to make
- // this method easier to use, since most code will use this with an Application or Activity type.
- @Nonnull
- public static <T> T get(Object component, Class<T> entryPoint) {
- if (component instanceof GeneratedComponent) {
- // Unsafe cast. There is no way for this method to know that the correct component was used.
- return entryPoint.cast(component);
- } else if (component instanceof GeneratedComponentManager) {
- // Unsafe cast. There is no way for this method to know that the correct component was used.
- return entryPoint.cast(((GeneratedComponentManager<?>) component).generatedComponent());
- } else {
- throw new IllegalStateException(
- String.format(
- "Given component holder %s does not implement %s or %s",
- component.getClass(), GeneratedComponent.class, GeneratedComponentManager.class));
- }
- }
-
- private EntryPoints() {}
-}
diff --git a/java/dagger/hilt/GeneratesRootInput.java b/java/dagger/hilt/GeneratesRootInput.java
deleted file mode 100644
index ffd786f..0000000
--- a/java/dagger/hilt/GeneratesRootInput.java
+++ /dev/null
@@ -1,28 +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;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/** For annotating annotations that generate input for the {@link GenerateComponents}. */
-// TODO(danysantiago): Rename to GenerateComponentsInput
-@Target(ElementType.ANNOTATION_TYPE)
-@Retention(RetentionPolicy.CLASS)
-public @interface GeneratesRootInput {}
diff --git a/java/dagger/hilt/InstallIn.java b/java/dagger/hilt/InstallIn.java
deleted file mode 100644
index 9148c82..0000000
--- a/java/dagger/hilt/InstallIn.java
+++ /dev/null
@@ -1,51 +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;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that declares which component(s) the annotated class should be included in when
- * Hilt generates the components. This may only be used with classes annotated with
- * {@literal @}{@link dagger.Module} or {@literal @}{@link dagger.hilt.EntryPoint}.
- *
- * <p>Example usage for installing a module in the generated {@code ApplicationComponent}:
- *
- * <pre><code>
- * {@literal @}Module
- * {@literal @}InstallIn(SingletonComponent.class)
- * public final class FooModule {
- * {@literal @}Provides
- * static Foo provideFoo() {
- * return new Foo();
- * }
- * }
- * </code></pre>
- *
- * @see <a href="https://dagger.dev/hilt/modules">Hilt Modules</a>
- */
-@Retention(CLASS)
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface InstallIn {
- Class<?>[] value();
-}
diff --git a/java/dagger/hilt/README.md b/java/dagger/hilt/README.md
deleted file mode 100644
index 911e466..0000000
--- a/java/dagger/hilt/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Hilt
-
-Hilt provides a standard way to incorporate Dagger dependency injection into an
-Android application. For more information, see https://dagger.dev/hilt.
diff --git a/java/dagger/hilt/android/ActivityRetainedLifecycle.java b/java/dagger/hilt/android/ActivityRetainedLifecycle.java
deleted file mode 100644
index 5e2d7cd..0000000
--- a/java/dagger/hilt/android/ActivityRetainedLifecycle.java
+++ /dev/null
@@ -1,61 +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;
-
-import android.app.Activity;
-import androidx.annotation.MainThread;
-import androidx.annotation.NonNull;
-
-/**
- * A <code>ActivityRetainedLifecycle</code> class is associated with the lifecycle of the {@link
- * dagger.hilt.android.components.ActivityRetainedComponent}.
- */
-public interface ActivityRetainedLifecycle {
-
- /**
- * Adds a new {@link OnClearedListener} for receiving a callback when the activity retained
- * instances will no longer be needed and destroyed.
- *
- * @param listener The listener that should be added.
- */
- @MainThread
- void addOnClearedListener(@NonNull OnClearedListener listener);
-
- /**
- * Removes a {@link OnClearedListener} previously added via {@link
- * #addOnClearedListener(OnClearedListener)}.
- *
- * @param listener The listener that should be removed.
- */
- @MainThread
- void removeOnClearedListener(@NonNull OnClearedListener listener);
-
- /**
- * Listener for receiving a callback for when the {@link
- * dagger.hilt.android.components.ActivityRetainedComponent} will no longer be used and destroyed.
- */
- interface OnClearedListener {
-
- /**
- * Called when the activity retained instances will no longer be used and destroyed.
- *
- * <p>Specifically this will be invoked during {@link Activity#onDestroy()} when {@link
- * Activity#isChangingConfigurations} is false.
- */
- void onCleared();
- }
-}
diff --git a/java/dagger/hilt/android/AndroidEntryPoint.java b/java/dagger/hilt/android/AndroidEntryPoint.java
deleted file mode 100644
index 8c56116..0000000
--- a/java/dagger/hilt/android/AndroidEntryPoint.java
+++ /dev/null
@@ -1,72 +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;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Marks an Android component class to be setup for injection with the standard Hilt Dagger Android
- * components. Currently, this supports activities, fragments, views, services, and broadcast
- * receivers.
- *
- * <p>This annotation will generate a base class that the annotated class should extend, either
- * directly or via the Hilt Gradle Plugin. This base class will take care of injecting members into
- * the Android class as well as handling instantiating the proper Hilt components at the right point
- * in the lifecycle. The name of the base class will be "Hilt_<annotated class name>".
- *
- * <p>Example usage (with the Hilt Gradle Plugin):
- *
- * <pre><code>
- * {@literal @}AndroidEntryPoint
- * public final class FooActivity extends FragmentActivity {
- * {@literal @}Inject Foo foo;
- *
- * {@literal @}Override
- * public void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState); // The foo field is injected in super.onCreate()
- * }
- * }
- * </code></pre>
- *
- * <p>Example usage (without the Hilt Gradle Plugin):
- *
- * <pre><code>
- * {@literal @}AndroidEntryPoint(FragmentActivity.class)
- * public final class FooActivity extends Hilt_FooActivity {
- * {@literal @}Inject Foo foo;
- *
- * {@literal @}Override
- * public void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState); // The foo field is injected in super.onCreate()
- * }
- * }
- * </code></pre>
- *
- * @see HiltAndroidApp
- */
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface AndroidEntryPoint {
-
- /**
- * The base class for the generated Hilt class. When applying the Hilt Gradle Plugin this value
- * is not necessary and will be inferred from the current superclass.
- */
- Class<?> value() default Void.class;
-}
diff --git a/java/dagger/hilt/android/AndroidManifest.xml b/java/dagger/hilt/android/AndroidManifest.xml
deleted file mode 100644
index 3a7b087..0000000
--- a/java/dagger/hilt/android/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android">
- <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/java/dagger/hilt/android/BUILD b/java/dagger/hilt/android/BUILD
deleted file mode 100644
index 47d7e67..0000000
--- a/java/dagger/hilt/android/BUILD
+++ /dev/null
@@ -1,193 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A library based on Hilt that provides standard components and automated injection for Android.
-load("//:build_defs.bzl", "POM_VERSION_ALPHA")
-load("//tools:maven.bzl", "gen_maven_artifact")
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "android_entry_point",
- srcs = [
- "AndroidEntryPoint.java",
- "WithFragmentBindings.java",
- ],
- exported_plugins = [
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:plugin",
- ],
- exports = [
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/internal/builders",
- "//java/dagger/hilt/android/internal/managers",
- "//java/dagger/hilt/android/internal/managers:component_supplier",
- "//java/dagger/hilt/android/internal/modules",
- "//java/dagger/hilt/android/lifecycle",
- "//java/dagger/hilt/codegen:originating_element",
- "//java/dagger/hilt/internal:component_entry_point",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:generated_entry_point",
- "//java/dagger/hilt/internal:preconditions",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_fragment_fragment",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-android_library(
- name = "hilt_android_app",
- srcs = ["HiltAndroidApp.java"],
- exported_plugins = [
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:plugin",
- "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin",
- "//java/dagger/hilt/processor/internal/root:plugin",
- ],
- exports = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/internal/managers",
- "//java/dagger/hilt/android/internal/managers:component_supplier",
- "//java/dagger/hilt/android/internal/modules",
- "//java/dagger/hilt/codegen:originating_element",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:generated_component",
- "//java/dagger/hilt/internal:generated_entry_point",
- "//java/dagger/hilt/migration:disable_install_in_check",
- "@maven//:androidx_annotation_annotation",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-android_library(
- name = "entry_point_accessors",
- srcs = ["EntryPointAccessors.java"],
- deps = [
- ":package_info",
- "//java/dagger/hilt:entry_point",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@maven//:androidx_fragment_fragment",
- ],
-)
-
-android_library(
- name = "activity_retained_lifecycle",
- srcs = ["ActivityRetainedLifecycle.java"],
- deps = [
- ":package_info",
- "@maven//:androidx_annotation_annotation",
- ],
-)
-
-android_library(
- name = "artifact-lib",
- tags = ["maven_coordinates=com.google.dagger:hilt-android:" + POM_VERSION_ALPHA],
- exports = [
- ":android_entry_point",
- ":entry_point_accessors",
- ":hilt_android_app",
- ":package_info",
- "//java/dagger/hilt:artifact-core-lib",
- "//java/dagger/hilt/android/migration:optional_inject",
- "//java/dagger/lint:lint-android-artifact-lib",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
- deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
-
-gen_maven_artifact(
- name = "artifact",
- artifact_coordinates = "com.google.dagger:hilt-android:" + POM_VERSION_ALPHA,
- artifact_name = "Hilt Android",
- artifact_target = ":artifact-lib",
- artifact_target_libs = [
- ":entry_point_accessors",
- "//java/dagger/hilt/android:activity_retained_lifecycle",
- "//java/dagger/hilt/android:android_entry_point",
- "//java/dagger/hilt/android:hilt_android_app",
- "//java/dagger/hilt/android:package_info",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/components:view_model_component",
- "//java/dagger/hilt/android/components:package_info",
- "//java/dagger/hilt/android/internal",
- "//java/dagger/hilt/android/internal/builders",
- "//java/dagger/hilt/android/internal/lifecycle",
- "//java/dagger/hilt/android/internal/managers",
- "//java/dagger/hilt/android/internal/managers:component_supplier",
- "//java/dagger/hilt/android/internal/migration:injected_by_hilt",
- "//java/dagger/hilt/android/internal/modules",
- "//java/dagger/hilt/android/lifecycle",
- "//java/dagger/hilt/android/migration:optional_inject",
- "//java/dagger/hilt/android/migration:package_info",
- "//java/dagger/hilt/android/qualifiers",
- "//java/dagger/hilt/android/qualifiers:package_info",
- "//java/dagger/hilt/android/scopes",
- "//java/dagger/hilt/android/scopes:activity_retained_scoped",
- "//java/dagger/hilt/android/scopes:view_model_scoped",
- "//java/dagger/hilt/android/scopes:package_info",
- "//java/dagger/hilt/internal:component_entry_point",
- "//java/dagger/hilt/internal:generated_entry_point",
- ],
- artifact_target_maven_deps = [
- "androidx.activity:activity",
- "androidx.annotation:annotation",
- "androidx.fragment:fragment",
- "androidx.lifecycle:lifecycle-viewmodel",
- "androidx.lifecycle:lifecycle-viewmodel-savedstate",
- "androidx.savedstate:savedstate",
- "com.google.code.findbugs:jsr305",
- "com.google.dagger:dagger-lint-aar",
- "com.google.dagger:dagger",
- "com.google.dagger:hilt-core",
- "javax.inject:javax.inject",
- ],
- artifact_target_maven_deps_banned = [
- "com.google.guava:guava",
- "javax.annotation:jsr250-api",
- ],
- javadoc_android_api_level = 30,
- javadoc_exclude_packages = [
- "dagger.hilt.android.internal",
- ],
- javadoc_root_packages = [
- "dagger.hilt.android",
- ],
- javadoc_srcs = [
- "//java/dagger/hilt:hilt_android_filegroup",
- ],
- manifest = "AndroidManifest.xml",
- packaging = "aar",
- proguard_specs = [
- "//java/dagger/hilt/android/lifecycle:proguard-rules.pro",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/EntryPointAccessors.java b/java/dagger/hilt/android/EntryPointAccessors.java
deleted file mode 100644
index 6145af1..0000000
--- a/java/dagger/hilt/android/EntryPointAccessors.java
+++ /dev/null
@@ -1,67 +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;
-
-import android.app.Activity;
-import android.content.Context;
-import androidx.fragment.app.Fragment;
-import android.view.View;
-import dagger.hilt.EntryPoints;
-import javax.annotation.Nonnull;
-
-/** Static utility methods for dealing with entry points for standard Android components. */
-public final class EntryPointAccessors {
-
- /**
- * Returns the entry point interface from an application. The context can be any context derived
- * from the application context. May only be used with entry point interfaces installed in the
- * ApplicationComponent.
- */
- @Nonnull
- public static <T> T fromApplication(Context context, Class<T> entryPoint) {
- return EntryPoints.get(context.getApplicationContext(), entryPoint);
- }
-
- /**
- * Returns the entry point interface from an activity. May only be used with entry point
- * interfaces installed in the ActivityComponent.
- */
- @Nonnull
- public static <T> T fromActivity(Activity activity, Class<T> entryPoint) {
- return EntryPoints.get(activity, entryPoint);
- }
-
- /**
- * Returns the entry point interface from a fragment. May only be used with entry point interfaces
- * installed in the FragmentComponent.
- */
- @Nonnull
- public static <T> T fromFragment(Fragment fragment, Class<T> entryPoint) {
- return EntryPoints.get(fragment, entryPoint);
- }
-
- /**
- * Returns the entry point interface from a view. May only be used with entry point interfaces
- * installed in the ViewComponent or ViewNoFragmentComponent.
- */
- @Nonnull
- public static <T> T fromView(View view, Class<T> entryPoint) {
- return EntryPoints.get(view, entryPoint);
- }
-
- private EntryPointAccessors() {}
-}
diff --git a/java/dagger/hilt/android/HiltAndroidApp.java b/java/dagger/hilt/android/HiltAndroidApp.java
deleted file mode 100644
index 0c2ca0f..0000000
--- a/java/dagger/hilt/android/HiltAndroidApp.java
+++ /dev/null
@@ -1,84 +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;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Annotation for marking the {@link android.app.Application} class where the Dagger components
- * should be generated. Since all components will be built in the same compilation as the annotated
- * application, all modules and entry points that should be installed in the component need to be
- * transitive compilation dependencies of the annotated application.
- *
- * <p>Usage of this annotation is similar to {@link dagger.hilt.android.AndroidEntryPoint} with the
- * only difference being that it only works on application classes and additionally triggers Dagger
- * component generation.
- *
- * <p>This annotation will generate a base class that the annotated class should extend, either
- * directly or via the Hilt Gradle Plugin. This base class will take care of injecting members into
- * the Android class as well as handling instantiating the proper Hilt components at the right point
- * in the lifecycle. The name of the base class will be "Hilt_<annotated class name>".
- *
- * <p>Example usage (with the Hilt Gradle Plugin):
- *
- * <pre><code>
- * {@literal @}HiltAndroidApp
- * public final class FooApplication extends Application {
- * {@literal @}Inject Foo foo;
- *
- * {@literal @}Override
- * public void onCreate() {
- * super.onCreate(); // The foo field is injected in super.onCreate()
- * }
- * }
- * </code></pre>
- *
- * <p>Example usage (without the Hilt Gradle Plugin):
- *
- * <pre><code>
- * {@literal @}HiltAndroidApp(Application.class)
- * public final class FooApplication extends Hilt_FooApplication {
- * {@literal @}Inject Foo foo;
- *
- * {@literal @}Override
- * public void onCreate() {
- * super.onCreate(); // The foo field is injected in super.onCreate()
- * }
- * }
- * </code></pre>
- *
- * @see AndroidEntryPoint
- */
-// Set the retention to RUNTIME because we check it via reflection in the HiltAndroidRule.
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface HiltAndroidApp {
- /**
- * The base class for the generated Hilt application. When applying the Hilt Gradle Plugin this
- * value is not necessary and will be inferred from the current superclass.
- */
- // TODO(erichang): It would be nice to make this Class<? extends Application> but then the default
- // would have to be Application which would make the default actually valid even without the
- // plugin. Maybe that is a good thing...but might be better to have users be explicit about the
- // base class they want.
- Class<?> value() default Void.class;
-}
diff --git a/java/dagger/hilt/android/WithFragmentBindings.java b/java/dagger/hilt/android/WithFragmentBindings.java
deleted file mode 100644
index 2b02498..0000000
--- a/java/dagger/hilt/android/WithFragmentBindings.java
+++ /dev/null
@@ -1,30 +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;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * Makes a View annotated with {@link AndroidEntryPoint} have access to fragment bindings.
- *
- * <p>By default, views annotated with {@literal @}AndroidEntryPoint do not have access to fragment
- * bindings and must use this annotation if fragment bindings are required. When this annotation is
- * used, this view must always be attached through a fragment.
- */
-@Target({ElementType.TYPE})
-public @interface WithFragmentBindings {}
diff --git a/java/dagger/hilt/android/components/ActivityComponent.java b/java/dagger/hilt/android/components/ActivityComponent.java
deleted file mode 100644
index 78f48cc..0000000
--- a/java/dagger/hilt/android/components/ActivityComponent.java
+++ /dev/null
@@ -1,25 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.ActivityScoped;
-
-/** A Hilt component that has the lifetime of the activity. */
-@ActivityScoped
-@DefineComponent(parent = ActivityRetainedComponent.class)
-public interface ActivityComponent {}
diff --git a/java/dagger/hilt/android/components/ActivityRetainedComponent.java b/java/dagger/hilt/android/components/ActivityRetainedComponent.java
deleted file mode 100644
index b3c340e..0000000
--- a/java/dagger/hilt/android/components/ActivityRetainedComponent.java
+++ /dev/null
@@ -1,26 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.ActivityRetainedScoped;
-import dagger.hilt.components.SingletonComponent;
-
-/** A Hilt component that has the lifetime of a configuration surviving activity. */
-@ActivityRetainedScoped
-@DefineComponent(parent = SingletonComponent.class)
-public interface ActivityRetainedComponent {}
diff --git a/java/dagger/hilt/android/components/BUILD b/java/dagger/hilt/android/components/BUILD
deleted file mode 100644
index 3a307d1..0000000
--- a/java/dagger/hilt/android/components/BUILD
+++ /dev/null
@@ -1,62 +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.
-
-# Description:
-# Hilt Android components
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "components",
- srcs = [
- "ActivityComponent.java",
- "ActivityRetainedComponent.java",
- "FragmentComponent.java",
- "ServiceComponent.java",
- "ViewComponent.java",
- "ViewWithFragmentComponent.java",
- ],
- exports = [
- "//java/dagger/hilt/components",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:define_component",
- "//java/dagger/hilt/android/scopes",
- "//java/dagger/hilt/android/scopes:activity_retained_scoped",
- "//java/dagger/hilt/components",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-android_library(
- name = "view_model_component",
- srcs = ["ViewModelComponent.java"],
- deps = [
- ":components",
- ":package_info",
- "//java/dagger/hilt:define_component",
- "//java/dagger/hilt/android/scopes:view_model_scoped",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/components/FragmentComponent.java b/java/dagger/hilt/android/components/FragmentComponent.java
deleted file mode 100644
index 6b088e6..0000000
--- a/java/dagger/hilt/android/components/FragmentComponent.java
+++ /dev/null
@@ -1,25 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.FragmentScoped;
-
-/** A Hilt component that has the lifetime of the fragment. */
-@FragmentScoped
-@DefineComponent(parent = ActivityComponent.class)
-public interface FragmentComponent {}
diff --git a/java/dagger/hilt/android/components/ServiceComponent.java b/java/dagger/hilt/android/components/ServiceComponent.java
deleted file mode 100644
index 0a3f6ea..0000000
--- a/java/dagger/hilt/android/components/ServiceComponent.java
+++ /dev/null
@@ -1,26 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.ServiceScoped;
-import dagger.hilt.components.SingletonComponent;
-
-/** A Hilt component that has the lifetime of the service. */
-@ServiceScoped
-@DefineComponent(parent = SingletonComponent.class)
-public interface ServiceComponent {}
diff --git a/java/dagger/hilt/android/components/ViewComponent.java b/java/dagger/hilt/android/components/ViewComponent.java
deleted file mode 100644
index 1f5b420..0000000
--- a/java/dagger/hilt/android/components/ViewComponent.java
+++ /dev/null
@@ -1,25 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.ViewScoped;
-
-/** A Hilt component that has the lifetime of the view. */
-@ViewScoped
-@DefineComponent(parent = ActivityComponent.class)
-public interface ViewComponent {}
diff --git a/java/dagger/hilt/android/components/ViewModelComponent.java b/java/dagger/hilt/android/components/ViewModelComponent.java
deleted file mode 100644
index 2ba2133..0000000
--- a/java/dagger/hilt/android/components/ViewModelComponent.java
+++ /dev/null
@@ -1,58 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.ViewModelScoped;
-
-/**
- * A Hilt component that has the lifetime of a single {@link androidx.lifecycle.ViewModel}.
- *
- * <p>This Hilt component is the source of {@link
- * dagger.hilt.android.lifecycle.HiltViewModel}-annotated {@link androidx.lifecycle.ViewModel}s
- * used by the {@link dagger.hilt.android.lifecycle.HiltViewModelFactory}. It contains a default
- * binding for the {@link androidx.lifecycle.SavedStateHandle} associated with the {@code
- * ViewModel} that can be used by other dependencies provided by the component.
- *
- * <p>Dependencies available in the {@link dagger.hilt.components.SingletonComponent} and {@link
- * ActivityRetainedComponent} are also available in this component since it is a child of {@code
- * ActivityRetainedComponent}.
- *
- * <p>Example usage:
- *
- * <pre>
- * @Module
- * @InstallIn(ViewModelComponent.class)
- * public final class ViewModelMovieModule {
- * @Provides
- * public static MovieRepository provideRepo(SavedStateHandle handle) {
- * return new MovieRepository(handle.getString("movie-id"));
- * }
- * }
- * </pre>
- *
- * <p>Dependencies in the {@code ViewModelComponent} can be scoped using the {@link ViewModelScoped}
- * annotation. This allows for a single instance of a dependency to be provided across the
- * dependencies of a single {@link dagger.hilt.android.lifecycle.HiltViewModel}-annotated {@code
- * ViewModel}.
- *
- * @see dagger.hilt.android.lifecycle.HiltViewModel
- * @see dagger.hilt.android.scopes.ViewModelScoped
- */
-@ViewModelScoped
-@DefineComponent(parent = ActivityRetainedComponent.class)
-public interface ViewModelComponent {}
diff --git a/java/dagger/hilt/android/components/ViewWithFragmentComponent.java b/java/dagger/hilt/android/components/ViewWithFragmentComponent.java
deleted file mode 100644
index be5f2e8..0000000
--- a/java/dagger/hilt/android/components/ViewWithFragmentComponent.java
+++ /dev/null
@@ -1,25 +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.components;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.scopes.ViewScoped;
-
-/** A Hilt component that has the lifetime of the view. */
-@ViewScoped
-@DefineComponent(parent = FragmentComponent.class)
-public interface ViewWithFragmentComponent {}
diff --git a/java/dagger/hilt/android/components/package-info.java b/java/dagger/hilt/android/components/package-info.java
deleted file mode 100644
index 9ac3686..0000000
--- a/java/dagger/hilt/android/components/package-info.java
+++ /dev/null
@@ -1,22 +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.
- */
-
-/**
- * This package contains Hilt's built-in {@link dagger.Component}s for Android.
- *
- * @see <a href="https://dagger.dev/hilt/components.md">Hilt Components</a>
- */
-package dagger.hilt.android.components;
diff --git a/java/dagger/hilt/android/example/BUILD b/java/dagger/hilt/android/example/BUILD
deleted file mode 100644
index 2a4c194..0000000
--- a/java/dagger/hilt/android/example/BUILD
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2017 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# A skeletal application that demonstrates wiring for an injected Application and Activity.
-
-package(default_visibility = ["//:src"])
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(
- ["**/*"],
- # Exclude Gradle build folder to enable working along side Bazel
- exclude = ["**/build/**"],
- ),
-)
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/build.gradle b/java/dagger/hilt/android/example/gradle/simple/app/build.gradle
deleted file mode 100644
index b3687ee..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/build.gradle
+++ /dev/null
@@ -1,76 +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.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.example.gradle.simple"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "dagger.hilt.android.example.gradle.simple.SimpleEmulatorTestRunner"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
- sourceSets {
- String sharedTestDir = 'src/sharedTest/java'
- test {
- java.srcDirs += sharedTestDir
- }
- androidTest {
- java.srcDirs += sharedTestDir
- }
- }
-}
-
-dependencies {
- implementation project(':feature')
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- testAnnotationProcessor 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- androidTestImplementation 'com.google.truth:truth:1.0.1'
- androidTestImplementation 'junit:junit:4.13'
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- androidTestAnnotationProcessor 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- // To help us catch usages of Guava APIs for Java 8 in the '-jre' variant.
- annotationProcessor'com.google.guava:guava:28.1-android'
- testAnnotationProcessor'com.google.guava:guava:28.1-android'
- androidTestAnnotationProcessor'com.google.guava:guava:28.1-android'
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java
deleted file mode 100644
index 28a7223..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SettingsActivityEmulatorTest.java
+++ /dev/null
@@ -1,60 +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.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@UninstallModules(ModelModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class SettingsActivityEmulatorTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @Model String fakeModel = "FakeModel";
-
- @Inject @Model String injectedModel;
-
- @Test
- public void testInjectedModel() throws Exception {
- assertThat(injectedModel).isNull();
- rule.inject();
- assertThat(injectedModel).isEqualTo("FakeModel");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SettingsActivity> scenario =
- ActivityScenario.launch(SettingsActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.greeter.greet())
- .isEqualTo("ProdUser, you are on build FakeModel."));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java
deleted file mode 100644
index cbf8f7f..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleActivityEmulatorTest.java
+++ /dev/null
@@ -1,59 +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.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@UninstallModules(UserNameModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class SimpleActivityEmulatorTest {
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @UserName String fakeUserName = "FakeUser";
-
- @Inject @UserName String injectedUserName;
-
- @Test
- public void testInjectedUserName() throws Exception {
- assertThat(injectedUserName).isNull();
- rule.inject();
- assertThat(injectedUserName).isEqualTo("FakeUser");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(
- activity -> assertThat(activity.greeter.greet()).isEqualTo("Hello, FakeUser!"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java b/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java
deleted file mode 100644
index daf046b..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/androidTest/java/dagger/hilt/android/example/gradle/simple/SimpleEmulatorTestRunner.java
+++ /dev/null
@@ -1,32 +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.example.gradle.simple;
-
-import android.app.Application;
-import android.content.Context;
-import androidx.test.runner.AndroidJUnitRunner;
-import dagger.hilt.android.testing.HiltTestApplication;
-
-/** A custom runner to setup the emulator application class for tests. */
-public final class SimpleEmulatorTestRunner extends AndroidJUnitRunner {
-
- @Override
- public Application newApplication(ClassLoader cl, String className, Context context)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- return super.newApplication(cl, HiltTestApplication.class.getName(), context);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 86460d8..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
- ~ Copyright (C) 2017 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simple">
-
- <application>
- <activity
- android:name=".Injection1Test$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false" />
- <activity
- android:name=".Injection2Test$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false"/>
- <activity
- android:name=".ActivityScenarioRuleTest$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false"/>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 662c5b4..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<!--
- ~ Copyright (C) 2017 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simple">
-
- <application android:name=".SimpleApplication" android:label="@string/appName">
- <activity
- android:name=".SimpleActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name=".SettingsActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false">
- </activity>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/Model.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/Model.java
deleted file mode 100644
index b4aec95..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/Model.java
+++ /dev/null
@@ -1,29 +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.example.gradle.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface Model {}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/ModelModule.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/ModelModule.java
deleted file mode 100644
index d933c81..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/ModelModule.java
+++ /dev/null
@@ -1,36 +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.example.gradle.simple;
-
-import static android.os.Build.MODEL;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-
-@Module
-@InstallIn(SingletonComponent.class)
-final class ModelModule {
- @Provides
- @Model
- static String provideModel() {
- return MODEL;
- }
-
- private ModelModule() {}
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java
deleted file mode 100644
index f508e48..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsActivity.java
+++ /dev/null
@@ -1,40 +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.example.gradle.simple;
-
-import android.os.Bundle;
-import android.widget.TextView;
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import javax.inject.Inject;
-
-/** The settings activity of the application. */
-@AndroidEntryPoint
-public class SettingsActivity extends AppCompatActivity {
- private static final String TAG = SettingsActivity.class.getSimpleName();
-
- @Inject SettingsGreeter greeter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_settings);
-
- ((TextView) findViewById(R.id.settings_greeting)).setText(greeter.greet());
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java
deleted file mode 100644
index 4f8ab14..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SettingsGreeter.java
+++ /dev/null
@@ -1,38 +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.example.gradle.simple;
-
-import android.app.Activity;
-import javax.inject.Inject;
-
-/** A class that returns a greeting for {@link SettingsActivity}. */
-final class SettingsGreeter {
- private final Activity activity;
- private final String userName;
- private final String model;
-
- @Inject
- SettingsGreeter(Activity activity, @UserName String userName, @Model String model) {
- this.activity = activity;
- this.userName = userName;
- this.model = model;
- }
-
- public String greet() {
- return activity.getResources().getString(R.string.settings_welcome, userName, model);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.java
deleted file mode 100644
index 70e2e57..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleActivity.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 dagger.hilt.android.example.gradle.simple;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.Button;
-import android.widget.TextView;
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.example.gradle.simple.feature.FeatureActivity;
-import javax.inject.Inject;
-
-/** The main activity of the application. */
-@AndroidEntryPoint
-public class SimpleActivity extends AppCompatActivity {
- private static final String TAG = SimpleActivity.class.getSimpleName();
-
- @Inject SimpleGreeter greeter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_main);
-
- ((TextView) findViewById(R.id.greeting)).setText(greeter.greet());
-
- Button featureButton = (Button) findViewById(R.id.goto_feature);
- featureButton.setOnClickListener(
- view -> startActivity(new Intent(this, FeatureActivity.class)));
-
- Button settingsButton = (Button) findViewById(R.id.goto_settings);
- settingsButton.setOnClickListener(
- view -> startActivity(new Intent(this, SettingsActivity.class)));
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleApplication.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleApplication.java
deleted file mode 100644
index a163d8c..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleApplication.java
+++ /dev/null
@@ -1,32 +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.example.gradle.simple;
-
-import android.app.Application;
-import dagger.hilt.android.HiltAndroidApp;
-import javax.inject.Inject;
-
-/**
- * A simple, skeletal application that demonstrates a dependency-injected application using the
- * utilities in {@code Hilt} in Android.
- */
-@HiltAndroidApp
-public class SimpleApplication extends Application {
-
- // Shows that we can inject SingletonComponent bindings into an application.
- @Inject @Model String model;
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleGreeter.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleGreeter.java
deleted file mode 100644
index 6c35600..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/SimpleGreeter.java
+++ /dev/null
@@ -1,36 +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.example.gradle.simple;
-
-import android.app.Activity;
-import javax.inject.Inject;
-
-/** A class that returns a greeting for {@link SimpleActivity}. */
-final class SimpleGreeter {
- private final Activity activity;
- private final String userName;
-
- @Inject
- SimpleGreeter(Activity activity, @UserName String userName) {
- this.activity = activity;
- this.userName = userName;
- }
-
- public String greet() {
- return activity.getResources().getString(R.string.welcome, userName);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java
deleted file mode 100644
index 173b163..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserName.java
+++ /dev/null
@@ -1,29 +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.example.gradle.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface UserName {}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java b/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java
deleted file mode 100644
index 3969b73..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/java/dagger/hilt/android/example/gradle/simple/UserNameModule.java
+++ /dev/null
@@ -1,34 +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.example.gradle.simple;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-
-@Module
-@InstallIn(ActivityComponent.class)
-final class UserNameModule {
- @UserName
- @Provides
- static String provideUserName() {
- return "ProdUser";
- }
-
- private UserNameModule() {}
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 8a23af5..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-
- <Button
- android:id="@+id/goto_settings"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/greeting"
- android:text="@string/navigateToSettings"
- />
-
- <Button
- android:id="@+id/goto_feature"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/goto_settings"
- android:text="@string/navigateToFeature"
- />
-</RelativeLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml
deleted file mode 100644
index 466856c..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/layout/activity_settings.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/settings_greeting"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/settings_welcome" />
-</FrameLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml b/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml
deleted file mode 100644
index f1b550c..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!--The app name [CHAR_LIMIT=20]-->
- <string name="appName">Simple Hilt Android</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s!</string>
-
- <!--The feature button message [CHAR_LIMIT=100]-->
- <string name="navigateToFeature">Navigate to a feature!</string>
-
- <!--The settings button message [CHAR_LIMIT=100]-->
- <string name="navigateToSettings">Navigate to settings!</string>
-
- <!--The feature button message [CHAR_LIMIT=100]-->
- <string name="settings_welcome">%1$s, you are on build %2$s.</string>
-</resources>
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java
deleted file mode 100644
index 7f1fcfc..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ActivityScenarioRuleTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static androidx.lifecycle.Lifecycle.State.RESUMED;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.ext.junit.rules.ActivityScenarioRule;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests that {@link ActivityScenarioRule} works with Hilt tests. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class ActivityScenarioRuleTest {
- private static final String STR_VALUE = "STR_VALUE";
-
- /** An activity to test injection. */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject String str;
- }
-
- @Rule(order = 0) public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
-
- @Rule(order = 1)
- public ActivityScenarioRule<TestActivity> scenarioRule =
- new ActivityScenarioRule<>(TestActivity.class);
-
- @BindValue String str = STR_VALUE;
-
- @Test
- public void testState() {
- assertThat(scenarioRule.getScenario().getState()).isEqualTo(RESUMED);
- }
-
- @Test
- public void testInjection() {
- scenarioRule
- .getScenario()
- .onActivity(activity -> assertThat(activity.str).isEqualTo(STR_VALUE));
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java
deleted file mode 100644
index 7abe3c2..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BindValueTest.java
+++ /dev/null
@@ -1,155 +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.example.gradle.simple;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.google.common.collect.ImmutableSet;
-import dagger.MapKey;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.BindElementsIntoSet;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.BindValueIntoMap;
-import dagger.hilt.android.testing.BindValueIntoSet;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class BindValueTest {
- private static final String BIND_VALUE_STRING = "BIND_VALUE_STRING";
- private static final String TEST_QUALIFIER = "TEST_QUALIFIER";
-
- private static final String SET_STRING_1 = "SetString1";
- private static final String SET_STRING_2 = "SetString2";
- private static final String SET_STRING_3 = "SetString3";
-
- private static final String KEY_1 = "Key1";
- private static final String KEY_2 = "Key2";
- private static final String VALUE_1 = "Value1";
- private static final String VALUE_2 = "Value2";
- private static final String VALUE_3 = "Value3";
-
- private static final Integer SET_INT_1 = 1;
- private static final Integer SET_INT_2 = 2;
- private static final Integer SET_INT_3 = 3;
-
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- interface BindValueEntryPoint {
- @Named(TEST_QUALIFIER)
- String bindValueString();
-
- Set<String> getStringSet();
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue
- @Named(TEST_QUALIFIER)
- String bindValueString = BIND_VALUE_STRING;
-
- @BindElementsIntoSet Set<String> bindElementsSet1 = ImmutableSet.of(SET_STRING_1);
- @BindElementsIntoSet Set<String> bindElementsSet2 = ImmutableSet.of(SET_STRING_2);
-
- @BindValueIntoMap
- @MyMapKey(KEY_1)
- String boundValue1 = VALUE_1;
-
- @BindValueIntoMap
- @MyMapKey(KEY_2)
- String boundValue2 = VALUE_2;
-
- @BindValueIntoSet Integer bindValueSetInt1 = SET_INT_1;
- @BindValueIntoSet Integer bindValueSetInt2 = SET_INT_2;
-
- @Inject Set<String> stringSet;
- @Inject Provider<Set<String>> providedStringSet;
- @Inject Provider<Map<String, String>> mapProvider;
- @Inject Set<Integer> intSet;
- @Inject Provider<Set<Integer>> providedIntSet;
-
- @Test
- public void testBindValueFieldIsProvided() throws Exception {
- assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING);
- assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING);
- }
-
- @Test
- public void testBindValueIsMutable() throws Exception {
- bindValueString = "newValue";
- assertThat(getBinding()).isEqualTo("newValue");
- }
-
- @Test
- public void testElementsIntoSet() throws Exception {
- rule.inject();
- // basic check that initial/default values are properly injected
- assertThat(providedStringSet.get()).containsExactly(SET_STRING_1, SET_STRING_2);
- // Test empty sets (something that cannot be done with @BindValueIntoSet)
- bindElementsSet1 = ImmutableSet.of();
- bindElementsSet2 = ImmutableSet.of();
- assertThat(providedStringSet.get()).isEmpty();
- // Test multiple elements in set.
- bindElementsSet1 = ImmutableSet.of(SET_STRING_1, SET_STRING_2, SET_STRING_3);
- assertThat(providedStringSet.get()).containsExactly(SET_STRING_1, SET_STRING_2, SET_STRING_3);
- }
-
- @Test
- public void testBindValueIntoMap() throws Exception {
- rule.inject();
- Map<String, String> oldMap = mapProvider.get();
- assertThat(oldMap).containsExactly(KEY_1, VALUE_1, KEY_2, VALUE_2);
- boundValue1 = VALUE_3;
- Map<String, String> newMap = mapProvider.get();
- assertThat(oldMap).containsExactly(KEY_1, VALUE_1, KEY_2, VALUE_2);
- assertThat(newMap).containsExactly(KEY_1, VALUE_3, KEY_2, VALUE_2);
- }
-
- @Test
- public void testBindValueIntoSet() throws Exception {
- rule.inject();
- // basic check that initial/default values are properly injected
- assertThat(providedIntSet.get()).containsExactly(SET_INT_1, SET_INT_2);
- bindValueSetInt1 = SET_INT_3;
- // change the value for bindValueSetString from 1 to 3
- assertThat(providedIntSet.get()).containsExactly(SET_INT_2, SET_INT_3);
- }
-
- @MapKey
- @interface MyMapKey {
- String value();
- }
-
- private static String getBinding() {
- return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString();
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BroadcastReceiverTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BroadcastReceiverTest.java
deleted file mode 100644
index 7585bbb..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/BroadcastReceiverTest.java
+++ /dev/null
@@ -1,202 +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.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A injection test of Broadcast receivers */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public class BroadcastReceiverTest {
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue final String valueToInject = "test value";
-
- @Test
- public void verifyReceiverInjectedValue() throws InterruptedException {
- Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- TestReceiverOne receiver = new TestReceiverOne();
- IntentFilter intentFilter = new IntentFilter("test-action");
- context.registerReceiver(receiver, intentFilter);
-
- Intent intent = new Intent();
- intent.setAction("test-action");
- context.sendBroadcast(intent);
-
- receiver.latch.await(2, TimeUnit.SECONDS);
- assertThat(receiver.injectedValue).isNotEmpty();
- }
-
- @Test
- public void verifyBaseReceiverInjectedValue() throws InterruptedException {
- Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- TestReceiverTwo receiver = new TestReceiverTwo();
- IntentFilter intentFilter = new IntentFilter("test-action");
- context.registerReceiver(receiver, intentFilter);
-
- Intent intent = new Intent();
- intent.setAction("test-action");
- context.sendBroadcast(intent);
-
- receiver.latch.await(2, TimeUnit.SECONDS);
- assertThat(receiver.injectedValue).isNotEmpty();
- }
-
- @Test
- public void verifyBaseReceiverIsNotDoubleInjected() throws InterruptedException {
- Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- TestReceiverThree receiver = new TestReceiverThree();
- IntentFilter intentFilter = new IntentFilter("test-action");
- context.registerReceiver(receiver, intentFilter);
-
- Intent intent = new Intent();
- intent.setAction("test-action");
- context.sendBroadcast(intent);
-
- receiver.latch.await(2, TimeUnit.SECONDS);
- assertThat(receiver.injectedValue).isNotEmpty();
- assertThat(receiver.onReceiveCalled).isEqualTo(1);
- }
-
- @Test
- public void verifyComplexReceiverInjectedValue() throws InterruptedException {
- Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- TestReceiverFour receiver = new TestReceiverFour();
- IntentFilter intentFilter = new IntentFilter("test-action");
- context.registerReceiver(receiver, intentFilter);
-
- Intent intent = new Intent();
- intent.setAction("test-action");
- context.sendBroadcast(intent);
-
- receiver.latch.await(2, TimeUnit.SECONDS);
- assertThat(receiver.injectedValue).isNotEmpty();
- }
-
- /** Test receiver */
- @AndroidEntryPoint
- static class TestReceiverOne extends BroadcastReceiver {
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- @Inject
- String injectedValue;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- latch.countDown();
- }
- }
-
- /** Test receiver */
- @AndroidEntryPoint
- static class TestReceiverTwo extends BaseReceiverAbstractMethod {
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- @Inject
- String injectedValue;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- latch.countDown();
- }
- }
-
- /** Test receiver */
- @AndroidEntryPoint
- static class TestReceiverThree extends BaseReceiverConcreteMethod {
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- @Inject
- String injectedValue;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- super.onReceive(context, intent);
- latch.countDown();
- }
- }
-
- /** Complex-ish test receiver */
- @AndroidEntryPoint
- static class TestReceiverFour extends BroadcastReceiver {
-
- final CountDownLatch latch = new CountDownLatch(1);
-
- @Inject String injectedValue;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- // Weird code, but it tests that the exception table and stack table frames are correctly
- // updated in a transformation.
- boolean var0;
- if (context != null) {
- var0 = false;
- Object var1 = context.getClass();
- try {
- throw new IllegalStateException();
- } catch (IllegalStateException ex) {
- var0 = true;
- }
- } else {
- BroadcastReceiver myself = this;
- var0 = false;
- }
- latch.countDown();
- }
- }
-
- /** Base test receiver */
- abstract static class BaseReceiverAbstractMethod extends BroadcastReceiver {
-
- }
-
- /** Base test receiver */
- abstract static class BaseReceiverConcreteMethod extends BroadcastReceiver {
-
- int onReceiveCalled = 0;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- onReceiveCalled++;
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java
deleted file mode 100644
index 0ebd150..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection1Test.java
+++ /dev/null
@@ -1,100 +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.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic injection APIs, and that bindings don't conflict with {@link Injection2Test}. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class Injection1Test {
- private static final String APPLICATION_QUALIFIER = "APPLICATION_QUALIFIER";
- private static final String ACTIVITY_QUALIFIER = "ACTIVITY_QUALIFIER";
- private static final String APPLICATION_VALUE = "Injection1Test_ApplicationValue";
- private static final String ACTIVITY_VALUE = "Injection1Test_ActivityValue";
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface TestApplicationModule {
- @Provides
- @Named(APPLICATION_QUALIFIER)
- static String provideString() {
- return APPLICATION_VALUE;
- }
- }
-
- @Module
- @InstallIn(ActivityComponent.class)
- interface TestActivityModule {
- @Provides
- @Named(ACTIVITY_QUALIFIER)
- static String provideString() {
- return ACTIVITY_VALUE;
- }
- }
-
- /** Test activity used to test activity injection */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject @Named(ACTIVITY_QUALIFIER) String activityValue;
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject @Named(APPLICATION_QUALIFIER) String applicationValue;
-
- @Test
- public void testApplicationInjection() throws Exception {
- assertThat(applicationValue).isNull();
- rule.inject();
- assertThat(applicationValue).isEqualTo(APPLICATION_VALUE);
- }
-
- @Test
- public void testActivityInjection() throws Exception {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.activityValue).isEqualTo(ACTIVITY_VALUE));
- }
- }
-
- @Test
- public void testSuperClassTransformation() {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_Injection1Test_TestActivity"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java
deleted file mode 100644
index 51d60b2..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/Injection2Test.java
+++ /dev/null
@@ -1,90 +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.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic injection APIs, and that bindings don't conflict with {@link Injection1Test}. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class Injection2Test {
- private static final String APPLICATION_QUALIFIER = "APPLICATION_QUALIFIER";
- private static final String ACTIVITY_QUALIFIER = "ACTIVITY_QUALIFIER";
- private static final String APPLICATION_VALUE = "Injection2Test_ApplicationValue";
- private static final String ACTIVITY_VALUE = "Injection2Test_ActivityValue";
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface TestApplicationModule {
- @Provides
- @Named(APPLICATION_QUALIFIER)
- static String provideString() {
- return APPLICATION_VALUE;
- }
- }
-
- @Module
- @InstallIn(ActivityComponent.class)
- interface TestActivityModule {
- @Provides
- @Named(ACTIVITY_QUALIFIER)
- static String provideString() {
- return ACTIVITY_VALUE;
- }
- }
-
- /** Test activity used to test activity injection */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject @Named(ACTIVITY_QUALIFIER) String activityValue;
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject @Named(APPLICATION_QUALIFIER) String applicationValue;
-
- @Test
- public void testApplicationInjection() throws Exception {
- assertThat(applicationValue).isNull();
- rule.inject();
- assertThat(applicationValue).isEqualTo(APPLICATION_VALUE);
- }
-
- @Test
- public void testActivityInjection() throws Exception {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.activityValue).isEqualTo(ACTIVITY_VALUE));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java
deleted file mode 100644
index 73daf8f..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/sharedTest/java/dagger/hilt/android/example/gradle/simple/ModuleTest.java
+++ /dev/null
@@ -1,157 +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.example.gradle.simple;
-
-import static org.junit.Assert.assertEquals;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic functionality of using modules in test. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class ModuleTest {
- @Rule public final HiltAndroidRule rules = new HiltAndroidRule(this);
-
- /** Qualifier for distinguishing test Strings, */
- @Qualifier
- @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
- public @interface TestQualifier {
- int value();
- }
-
- @Inject
- @TestQualifier(1)
- String testString1;
-
- @Inject
- @TestQualifier(2)
- String testString2;
-
- @Inject
- @TestQualifier(3)
- String testString3;
-
- @Inject
- @TestQualifier(4)
- String testString4;
-
- @Inject FooImpl fooImpl;
- @Inject Foo foo;
-
- /**
- * Module which is used to test if non-static test modules get registered in the component
- * correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public final class NonStaticModuleNonStaticProvides {
- @Provides
- @TestQualifier(1)
- String provideString() {
- return "1";
- }
- }
-
- /**
- * Module which is used to test if static test modules get registered in the component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public static final class StaticModuleStaticProvides {
- @Provides
- @TestQualifier(2)
- static String provideString() {
- return "2";
- }
-
- private StaticModuleStaticProvides() {}
- }
-
- /**
- * Module which is used to test if static test modules with a non-static methods get registered in
- * the component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public static final class StaticModuleNonStaticProvidesDefaultConstructor {
- @Provides
- @TestQualifier(3)
- String provideString() {
- return "3";
- }
- }
-
- /**
- * Module which is used to test if abstract test modules get registered in the component
- * correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public abstract static class AbstractModuleStaticProvides {
- @Provides
- @TestQualifier(4)
- static String provideString() {
- return "4";
- }
-
- private AbstractModuleStaticProvides() {}
- }
-
- /**
- * Module which is used to test if abstract test modules with a binds method get registered in the
- * component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public abstract static class AbstractModuleBindsMethod {
- @Binds
- abstract Foo foo(FooImpl fooImpl);
- }
-
- interface Foo {}
-
- @Singleton
- static final class FooImpl implements Foo {
- @Inject
- FooImpl() {}
- }
-
- @Test
- public void testInjection() throws Exception {
- rules.inject();
- assertEquals("1", testString1);
- assertEquals("2", testString2);
- assertEquals("3", testString3);
- assertEquals("4", testString4);
- assertEquals(fooImpl, foo);
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java
deleted file mode 100644
index f1e5f27..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SettingsActivityTest.java
+++ /dev/null
@@ -1,76 +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.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Build;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.HiltTestApplication;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** A simple test using Hilt. */
-@UninstallModules(ModelModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
-public final class SettingsActivityTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @Model String fakeModel = "FakeModel";
-
- @Inject @Model String injectedModel;
-
- @Test
- public void testInjectedModel() throws Exception {
- assertThat(injectedModel).isNull();
- rule.inject();
- assertThat(injectedModel).isEqualTo("FakeModel");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SettingsActivity> scenario =
- ActivityScenario.launch(SettingsActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.greeter.greet())
- .isEqualTo("ProdUser, you are on build FakeModel."));
- }
- }
-
- @Test
- public void testSuperClassTransformation() {
- try (ActivityScenario<SettingsActivity> scenario =
- ActivityScenario.launch(SettingsActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_SettingsActivity"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java b/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java
deleted file mode 100644
index 29b5f70..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/test/java/dagger/hilt/android/example/gradle/simple/SimpleActivityTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.example.gradle.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Build;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.HiltTestApplication;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** A simple test using Hilt. */
-@UninstallModules(UserNameModule.class)
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = Build.VERSION_CODES.P, application = HiltTestApplication.class)
-public final class SimpleActivityTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @UserName String fakeUserName = "FakeUser";
-
- @Inject @UserName String injectedUserName;
-
- @Test
- public void testInjectedUserName() throws Exception {
- assertThat(injectedUserName).isNull();
- rule.inject();
- assertThat(injectedUserName).isEqualTo("FakeUser");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(
- activity -> assertThat(activity.greeter.greet()).isEqualTo("Hello, FakeUser!"));
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties b/java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties
deleted file mode 100644
index 0234ffe..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/app/src/test/resources/dagger/hilt/android/example/gradle/simple/robolectric.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-sdk=28
-application=dagger.hilt.android.testing.HiltTestApplication
\ No newline at end of file
diff --git a/java/dagger/hilt/android/example/gradle/simple/build.gradle b/java/dagger/hilt/android/example/gradle/simple/build.gradle
deleted file mode 100644
index c0916a4..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/build.gradle
+++ /dev/null
@@ -1,41 +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.
- */
-
-buildscript {
- ext {
- kotlin_version = '1.3.61'
- agp_version = "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/build.gradle b/java/dagger/hilt/android/example/gradle/simple/feature/build.gradle
deleted file mode 100644
index 462aefc..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/build.gradle
+++ /dev/null
@@ -1,50 +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.
- */
-
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
-}
-
-kapt {
- correctErrorTypes true
-}
-
-dependencies {
- // This is api instead of implementation since Kotlin modules here consumed
- // by the app need to expose @kotlin.Metadata
- api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml
deleted file mode 100644
index f7919a9..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simple.feature">
- <application>
- <activity
- android:name=".FeatureActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true"/>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt
deleted file mode 100644
index 03b9ae9..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureActivity.kt
+++ /dev/null
@@ -1,46 +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.example.gradle.simple.feature
-
-import android.os.Bundle
-import android.widget.Button
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class FeatureActivity : AppCompatActivity() {
- @Inject lateinit var counter: FeatureCounter
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContentView(R.layout.activity_feature)
-
- findViewById<Button>(R.id.feature_button).setOnClickListener {
- counter.count++
- updateCountText()
- }
-
- updateCountText()
- }
-
- private fun updateCountText() {
- findViewById<TextView>(R.id.feature_count).text = "The count: ${counter.count}"
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureCounter.kt b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureCounter.kt
deleted file mode 100644
index 0fd3db3..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureCounter.kt
+++ /dev/null
@@ -1,19 +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.example.gradle.simple.feature
-
-class FeatureCounter(var count: Int)
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt
deleted file mode 100644
index 84ca99a..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/java/dagger/hilt/android/example/gradle/simple/feature/FeatureModule.kt
+++ /dev/null
@@ -1,31 +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.example.gradle.simple.feature
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityRetainedComponent
-import dagger.hilt.android.scopes.ActivityRetainedScoped
-
-@Module
-@InstallIn(ActivityRetainedComponent::class)
-object FeatureModule {
- @Provides
- @ActivityRetainedScoped
- fun provideData() = FeatureCounter(0)
-}
diff --git a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml b/java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml
deleted file mode 100644
index bf52431..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/feature/src/main/res/layout/activity_feature.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2017 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/feature_count"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-
- <Button
- android:id="@+id/feature_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/feature_count"
- android:text="Count++"
- />
-</RelativeLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradle.properties b/java/dagger/hilt/android/example/gradle/simple/gradle.properties
deleted file mode 100644
index 646c51b..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar b/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties b/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/example/gradle/simple/gradlew b/java/dagger/hilt/android/example/gradle/simple/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/java/dagger/hilt/android/example/gradle/simple/settings.gradle b/java/dagger/hilt/android/example/gradle/simple/settings.gradle
deleted file mode 100644
index 2ae0b0a..0000000
--- a/java/dagger/hilt/android/example/gradle/simple/settings.gradle
+++ /dev/null
@@ -1,3 +0,0 @@
-rootProject.name='Simple Hilt Android'
-include ':app'
-include ':feature'
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle
deleted file mode 100644
index bff4797..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/build.gradle
+++ /dev/null
@@ -1,58 +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.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'dagger.hilt.android.plugin'
-apply plugin: 'kotlin-kapt'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.example.gradle.simpleKotlin"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
-}
-
-dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.2.0'
-
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-android-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- // 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-android-compiler:LOCAL-SNAPSHOT'
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/debug/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 081c7ad..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simpleKotlin">
-
- <application>
- <activity android:name=".SimpleTest$TestActivity" android:exported="false"/>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 2e274ab..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.example.gradle.simpleKotlin">
-
- <application
- android:name=".KotlinApplication"
- android:allowBackup="true"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt
deleted file mode 100644
index 8a85040..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ActivityModule.kt
+++ /dev/null
@@ -1,31 +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.example.gradle.simpleKotlin
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityComponent
-
-@Module
-@InstallIn(ActivityComponent::class)
-object ActivityModule {
- @UserName
- @Provides
- fun provideUserName(): String {
- return "Android User"
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt
deleted file mode 100644
index 9ee904d..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/ApplicationModule.kt
+++ /dev/null
@@ -1,33 +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.example.gradle.simpleKotlin
-
-import android.os.Build
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-
-@Module
-@InstallIn(SingletonComponent::class)
-object ApplicationModule {
- @Provides
- @Model
- fun provideModel(): String {
- return Build.MODEL
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/KotlinApplication.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/KotlinApplication.kt
deleted file mode 100644
index 765fb36..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/KotlinApplication.kt
+++ /dev/null
@@ -1,30 +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.example.gradle.simpleKotlin
-
-import android.app.Application
-import dagger.hilt.android.HiltAndroidApp
-import javax.inject.Inject
-
-@HiltAndroidApp
-class KotlinApplication : Application() {
- // Shows that we can inject SingletonComponent bindings into an application.
- @Inject
- @Model
- @JvmField
- var model: String? = null
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt
deleted file mode 100644
index 564f05a..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/MainActivity.kt
+++ /dev/null
@@ -1,46 +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.example.gradle.simpleKotlin
-
-import android.os.Bundle
-import android.view.View
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class MainActivity : AppCompatActivity() {
- // Shows that we can inject Application/Activity bindings into an activity.
- @JvmField
- @Model
- @Inject
- var model: String? = null
-
- @JvmField
- @UserName
- @Inject
- var name: String? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- val greeting = findViewById<View>(R.id.greeting) as TextView
- val text = resources.getString(R.string.welcome, name, model)
- greeting.text = text
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/Model.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/Model.kt
deleted file mode 100644
index 4fe168d..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/Model.kt
+++ /dev/null
@@ -1,24 +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.example.gradle.simpleKotlin
-
-import javax.inject.Qualifier
-
-/** Qualifies bindings relating to [android.os.Build.MODEL]. */
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class Model
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/UserName.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/UserName.kt
deleted file mode 100644
index a061ab5..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/java/dagger/hilt/android/example/gradle/simpleKotlin/UserName.kt
+++ /dev/null
@@ -1,24 +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.example.gradle.simpleKotlin
-
-import javax.inject.Qualifier
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class UserName
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 0d7637d..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-</RelativeLayout>
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/values/strings.xml b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/values/strings.xml
deleted file mode 100644
index c1e4f27..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,23 +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.
- -->
-
-<resources>
- <!--The app name [CHAR_LIMIT=40]-->
- <string name="app_name">Simple Hilt Kotlin Android App</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s! You are on build %2$s.</string>
-</resources>
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt b/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt
deleted file mode 100644
index d52ff71..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/app/src/test/java/dagger/hilt/android/example/gradle/simpleKotlin/SimpleTest.kt
+++ /dev/null
@@ -1,71 +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.example.gradle.simpleKotlin
-
-import android.os.Build
-import androidx.appcompat.app.AppCompatActivity
-import androidx.test.core.app.ActivityScenario
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import dagger.hilt.android.testing.HiltTestApplication
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@HiltAndroidTest
-@RunWith(RobolectricTestRunner::class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = [Build.VERSION_CODES.P], application = HiltTestApplication::class)
-class SimpleTest {
- @Rule
- @JvmField
- var rule = HiltAndroidRule(this)
-
- @AndroidEntryPoint
- class TestActivity : AppCompatActivity()
-
- @Test
- fun verifyMainActivity() {
- ActivityScenario.launch(MainActivity::class.java).use { scenario ->
- scenario.onActivity { activity ->
- assertThat(activity::class.java.getSuperclass()?.getSimpleName())
- .isEqualTo("Hilt_MainActivity")
- assertThat(activity.model).isNotNull()
- assertThat(activity.name).isNotNull()
- }
- }
- }
-
- @Test
- fun verifyTestActivity() {
- ActivityScenario.launch(TestActivity::class.java).use { scenario ->
- scenario.onActivity { activity ->
- assertThat(activity::class.java.getSuperclass()?.getSimpleName())
- .isEqualTo("Hilt_SimpleTest_TestActivity")
- }
- }
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/build.gradle b/java/dagger/hilt/android/example/gradle/simpleKotlin/build.gradle
deleted file mode 100644
index 7a02482..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/build.gradle
+++ /dev/null
@@ -1,41 +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.
- */
-
-buildscript {
- ext {
- kotlin_version = '1.3.61'
- agp_version = "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties
deleted file mode 100644
index 646c51b..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jar b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradlew b/java/dagger/hilt/android/example/gradle/simpleKotlin/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle b/java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle
deleted file mode 100644
index e42f9d1..0000000
--- a/java/dagger/hilt/android/example/gradle/simpleKotlin/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-rootProject.name='Simple Kotlin Hilt Android'
-include ':app'
diff --git a/java/dagger/hilt/android/internal/BUILD b/java/dagger/hilt/android/internal/BUILD
deleted file mode 100644
index 57c84e3..0000000
--- a/java/dagger/hilt/android/internal/BUILD
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Internal Hilt Android utitlies
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "internal",
- srcs = ["ThreadUtil.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/internal/ThreadUtil.java b/java/dagger/hilt/android/internal/ThreadUtil.java
deleted file mode 100644
index d5b11f5..0000000
--- a/java/dagger/hilt/android/internal/ThreadUtil.java
+++ /dev/null
@@ -1,42 +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.internal;
-
-import android.os.Looper;
-
-/** Thread utility methods. */
-public final class ThreadUtil {
-
- private static Thread mainThread;
-
- private ThreadUtil() {}
-
- /** Returns true if the current thread is the Main thread. */
- public static boolean isMainThread() {
- if (mainThread == null) {
- mainThread = Looper.getMainLooper().getThread();
- }
- return Thread.currentThread() == mainThread;
- }
-
- /** Checks that the current thread is the Main thread. Otherwise throws an exception. */
- public static void ensureMainThread() {
- if (!isMainThread()) {
- throw new IllegalStateException("Must be called on the Main thread.");
- }
- }
-}
diff --git a/java/dagger/hilt/android/internal/builders/ActivityComponentBuilder.java b/java/dagger/hilt/android/internal/builders/ActivityComponentBuilder.java
deleted file mode 100644
index 5ea09db..0000000
--- a/java/dagger/hilt/android/internal/builders/ActivityComponentBuilder.java
+++ /dev/null
@@ -1,32 +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.internal.builders;
-
-import android.app.Activity;
-import dagger.BindsInstance;
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.ActivityComponent;
-
-/** Interface for creating an {@link ActivityComponent}. */
-@DefineComponent.Builder
-public interface ActivityComponentBuilder {
- ActivityComponentBuilder activity(
- @BindsInstance
- Activity activity);
-
- ActivityComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/builders/ActivityRetainedComponentBuilder.java b/java/dagger/hilt/android/internal/builders/ActivityRetainedComponentBuilder.java
deleted file mode 100644
index 110b3fe..0000000
--- a/java/dagger/hilt/android/internal/builders/ActivityRetainedComponentBuilder.java
+++ /dev/null
@@ -1,26 +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.internal.builders;
-
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.ActivityRetainedComponent;
-
-/** Interface for creating a {@link ActivityRetainedComponent}. */
-@DefineComponent.Builder
-public interface ActivityRetainedComponentBuilder {
- ActivityRetainedComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/builders/BUILD b/java/dagger/hilt/android/internal/builders/BUILD
deleted file mode 100644
index 0e282be..0000000
--- a/java/dagger/hilt/android/internal/builders/BUILD
+++ /dev/null
@@ -1,37 +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.
-
-# Description:
-# Hilt Android component builders
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "builders",
- srcs = glob(["*.java"]),
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt:define_component",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/components:view_model_component",
- "@maven//:androidx_activity_activity",
- "@maven//:androidx_fragment_fragment",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java b/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java
deleted file mode 100644
index 11cc89f..0000000
--- a/java/dagger/hilt/android/internal/builders/FragmentComponentBuilder.java
+++ /dev/null
@@ -1,29 +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.internal.builders;
-
-import androidx.fragment.app.Fragment;
-import dagger.BindsInstance;
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.FragmentComponent;
-
-/** Interface for creating a {@link FragmentComponent}. */
-@DefineComponent.Builder
-public interface FragmentComponentBuilder {
- FragmentComponentBuilder fragment(@BindsInstance Fragment fragment);
- FragmentComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/builders/ServiceComponentBuilder.java b/java/dagger/hilt/android/internal/builders/ServiceComponentBuilder.java
deleted file mode 100644
index 9b95d12..0000000
--- a/java/dagger/hilt/android/internal/builders/ServiceComponentBuilder.java
+++ /dev/null
@@ -1,29 +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.internal.builders;
-
-import android.app.Service;
-import dagger.BindsInstance;
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.ServiceComponent;
-
-/** Interface for creating a {@link ServiceComponent}. */
-@DefineComponent.Builder
-public interface ServiceComponentBuilder {
- ServiceComponentBuilder service(@BindsInstance Service service);
- ServiceComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/builders/ViewComponentBuilder.java b/java/dagger/hilt/android/internal/builders/ViewComponentBuilder.java
deleted file mode 100644
index f2e37b6..0000000
--- a/java/dagger/hilt/android/internal/builders/ViewComponentBuilder.java
+++ /dev/null
@@ -1,30 +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.internal.builders;
-
-import android.view.View;
-import dagger.BindsInstance;
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.ViewComponent;
-
-/** Interface for creating a {@link ViewComponent}. */
-@DefineComponent.Builder
-public interface ViewComponentBuilder {
- ViewComponentBuilder view(@BindsInstance View view);
-
- ViewComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/builders/ViewModelComponentBuilder.java b/java/dagger/hilt/android/internal/builders/ViewModelComponentBuilder.java
deleted file mode 100644
index e9acbb9..0000000
--- a/java/dagger/hilt/android/internal/builders/ViewModelComponentBuilder.java
+++ /dev/null
@@ -1,30 +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.internal.builders;
-
-import androidx.lifecycle.SavedStateHandle;
-import dagger.BindsInstance;
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.ViewModelComponent;
-
-/** Interface for creating a {@link ViewModelComponent}. */
-@DefineComponent.Builder
-public interface ViewModelComponentBuilder {
- ViewModelComponentBuilder savedStateHandle(@BindsInstance SavedStateHandle handle);
-
- ViewModelComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/builders/ViewWithFragmentComponentBuilder.java b/java/dagger/hilt/android/internal/builders/ViewWithFragmentComponentBuilder.java
deleted file mode 100644
index b15a8cc..0000000
--- a/java/dagger/hilt/android/internal/builders/ViewWithFragmentComponentBuilder.java
+++ /dev/null
@@ -1,30 +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.internal.builders;
-
-import android.view.View;
-import dagger.BindsInstance;
-import dagger.hilt.DefineComponent;
-import dagger.hilt.android.components.ViewWithFragmentComponent;
-
-/** Interface for creating a {@link ViewWithFragmentComponent}. */
-@DefineComponent.Builder
-public interface ViewWithFragmentComponentBuilder {
- ViewWithFragmentComponentBuilder view(@BindsInstance View view);
-
- ViewWithFragmentComponent build();
-}
diff --git a/java/dagger/hilt/android/internal/lifecycle/BUILD b/java/dagger/hilt/android/internal/lifecycle/BUILD
deleted file mode 100644
index b3ecfc2..0000000
--- a/java/dagger/hilt/android/internal/lifecycle/BUILD
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Hilt lifecycle ViewModel hooks.
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "lifecycle",
- srcs = glob(["*.java"]),
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/components:view_model_component",
- "//java/dagger/hilt/android/internal/builders",
- "//java/dagger/hilt/android/qualifiers",
- "@maven//:androidx_activity_activity",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_fragment_fragment",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- "@maven//:androidx_savedstate_savedstate",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/internal/lifecycle/DefaultActivityViewModelFactory.java b/java/dagger/hilt/android/internal/lifecycle/DefaultActivityViewModelFactory.java
deleted file mode 100644
index becce8c..0000000
--- a/java/dagger/hilt/android/internal/lifecycle/DefaultActivityViewModelFactory.java
+++ /dev/null
@@ -1,29 +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.internal.lifecycle;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.inject.Qualifier;
-
-/** Qualifier for the default view model factory used by @AndroidEntryPoint annotated activities. */
-@Qualifier
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
-public @interface DefaultActivityViewModelFactory {}
diff --git a/java/dagger/hilt/android/internal/lifecycle/DefaultFragmentViewModelFactory.java b/java/dagger/hilt/android/internal/lifecycle/DefaultFragmentViewModelFactory.java
deleted file mode 100644
index 9967053..0000000
--- a/java/dagger/hilt/android/internal/lifecycle/DefaultFragmentViewModelFactory.java
+++ /dev/null
@@ -1,29 +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.internal.lifecycle;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.inject.Qualifier;
-
-/** Qualifier for the default view model factory used by @AndroidEntryPoint annotated fragments. */
-@Qualifier
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
-public @interface DefaultFragmentViewModelFactory {}
diff --git a/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java b/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java
deleted file mode 100644
index 427822d..0000000
--- a/java/dagger/hilt/android/internal/lifecycle/DefaultViewModelFactories.java
+++ /dev/null
@@ -1,167 +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.internal.lifecycle;
-
-import android.app.Application;
-import androidx.lifecycle.SavedStateViewModelFactory;
-import androidx.lifecycle.ViewModelProvider;
-import android.os.Bundle;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.activity.ComponentActivity;
-import androidx.savedstate.SavedStateRegistryOwner;
-import dagger.Module;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.components.FragmentComponent;
-import dagger.hilt.android.internal.builders.ViewModelComponentBuilder;
-import dagger.multibindings.Multibinds;
-import java.util.Set;
-import javax.inject.Inject;
-
-/**
- * Modules and entry points for the default view model factory used by activities and fragments
- * annotated with @AndroidEntryPoint.
- *
- * <p>Entry points are used to acquire the factory because injected fields in the generated
- * activities and fragments are ignored by Dagger when using the transform due to the generated
- * class not being part of the hierarchy during compile time.
- */
-public final class DefaultViewModelFactories {
-
- /**
- * Retrieves the default view model factory for the activity.
- *
- * <p>Do not use except in Hilt generated code!
- */
- public static ViewModelProvider.Factory getActivityFactory(ComponentActivity activity) {
- return EntryPoints.get(activity, ActivityEntryPoint.class)
- .getHiltInternalFactoryFactory()
- .fromActivity(activity);
- }
-
- /**
- * Retrieves the default view model factory for the activity.
- *
- * <p>Do not use except in Hilt generated code!
- */
- public static ViewModelProvider.Factory getFragmentFactory(Fragment fragment) {
- return EntryPoints.get(fragment, FragmentEntryPoint.class)
- .getHiltInternalFactoryFactory()
- .fromFragment(fragment);
- }
-
- /** Internal factory for the Hilt ViewModel Factory. */
- public static final class InternalFactoryFactory {
-
- private final Application application;
- private final Set<String> keySet;
- private final ViewModelComponentBuilder viewModelComponentBuilder;
- @Nullable private final ViewModelProvider.Factory defaultActivityFactory;
- @Nullable private final ViewModelProvider.Factory defaultFragmentFactory;
-
- @Inject
- InternalFactoryFactory(
- Application application,
- @HiltViewModelMap.KeySet Set<String> keySet,
- ViewModelComponentBuilder viewModelComponentBuilder,
- // These default factory bindings are temporary for the transition of deprecating
- // the Hilt ViewModel extension for the built-in support
- @DefaultActivityViewModelFactory Set<ViewModelProvider.Factory> defaultActivityFactorySet,
- @DefaultFragmentViewModelFactory Set<ViewModelProvider.Factory> defaultFragmentFactorySet) {
- this.application = application;
- this.keySet = keySet;
- this.viewModelComponentBuilder = viewModelComponentBuilder;
- this.defaultActivityFactory = getFactoryFromSet(defaultActivityFactorySet);
- this.defaultFragmentFactory = getFactoryFromSet(defaultFragmentFactorySet);
- }
-
- ViewModelProvider.Factory fromActivity(ComponentActivity activity) {
- return getHiltViewModelFactory(activity,
- activity.getIntent() != null ? activity.getIntent().getExtras() : null,
- defaultActivityFactory);
- }
-
- ViewModelProvider.Factory fromFragment(Fragment fragment) {
- return getHiltViewModelFactory(fragment, fragment.getArguments(), defaultFragmentFactory);
- }
-
- private ViewModelProvider.Factory getHiltViewModelFactory(
- SavedStateRegistryOwner owner,
- @Nullable Bundle defaultArgs,
- @Nullable ViewModelProvider.Factory extensionDelegate) {
- ViewModelProvider.Factory delegate = extensionDelegate == null
- ? new SavedStateViewModelFactory(application, owner, defaultArgs)
- : extensionDelegate;
- return new HiltViewModelFactory(
- owner, defaultArgs, keySet, delegate, viewModelComponentBuilder);
- }
-
- @Nullable
- private static ViewModelProvider.Factory getFactoryFromSet(Set<ViewModelProvider.Factory> set) {
- // A multibinding set is used instead of BindsOptionalOf because Optional is not available in
- // Android until API 24 and we don't want to have Guava as a transitive dependency.
- if (set.isEmpty()) {
- return null;
- }
- if (set.size() > 1) {
- throw new IllegalStateException(
- "At most one default view model factory is expected. Found " + set);
- }
- ViewModelProvider.Factory factory = set.iterator().next();
- if (factory == null) {
- throw new IllegalStateException("Default view model factory must not be null.");
- }
- return factory;
- }
- }
-
- /** The activity module to declare the optional factories. */
- @Module
- @InstallIn(ActivityComponent.class)
- interface ActivityModule {
- @Multibinds
- @HiltViewModelMap.KeySet
- abstract Set<String> viewModelKeys();
-
- @Multibinds
- @DefaultActivityViewModelFactory
- Set<ViewModelProvider.Factory> defaultActivityViewModelFactory();
-
- @Multibinds
- @DefaultFragmentViewModelFactory
- Set<ViewModelProvider.Factory> defaultFragmentViewModelFactory();
- }
-
- /** The activity entry point to retrieve the factory. */
- @EntryPoint
- @InstallIn(ActivityComponent.class)
- public interface ActivityEntryPoint {
- InternalFactoryFactory getHiltInternalFactoryFactory();
- }
-
- /** The fragment entry point to retrieve the factory. */
- @EntryPoint
- @InstallIn(FragmentComponent.class)
- public interface FragmentEntryPoint {
- InternalFactoryFactory getHiltInternalFactoryFactory();
- }
-
- private DefaultViewModelFactories() {}
-}
diff --git a/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java b/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java
deleted file mode 100644
index 3b0d3bc..0000000
--- a/java/dagger/hilt/android/internal/lifecycle/HiltViewModelFactory.java
+++ /dev/null
@@ -1,112 +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.internal.lifecycle;
-
-import androidx.lifecycle.AbstractSavedStateViewModelFactory;
-import androidx.lifecycle.SavedStateHandle;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
-import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.savedstate.SavedStateRegistryOwner;
-import dagger.Module;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ViewModelComponent;
-import dagger.hilt.android.internal.builders.ViewModelComponentBuilder;
-import dagger.multibindings.Multibinds;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Provider;
-
-/**
- * View Model Provider Factory for the Hilt Extension.
- *
- * <p>A provider for this factory will be installed in the {@link
- * dagger.hilt.android.components.ActivityComponent} and {@link
- * dagger.hilt.android.components.FragmentComponent}. An instance of this factory will also be the
- * default factory by activities and fragments annotated with {@link
- * dagger.hilt.android.AndroidEntryPoint}.
- */
-public final class HiltViewModelFactory implements ViewModelProvider.Factory {
-
- /** Hilt entry point for getting the multi-binding map of ViewModels. */
- @EntryPoint
- @InstallIn(ViewModelComponent.class)
- public interface ViewModelFactoriesEntryPoint {
- @HiltViewModelMap
- Map<String, Provider<ViewModel>> getHiltViewModelMap();
- }
-
- /** Hilt module for providing the empty multi-binding map of ViewModels. */
- @Module
- @InstallIn(ViewModelComponent.class)
- interface ViewModelModule {
- @Multibinds
- @HiltViewModelMap
- Map<String, ViewModel> hiltViewModelMap();
- }
-
- private final Set<String> hiltViewModelKeys;
- private final ViewModelProvider.Factory delegateFactory;
- private final AbstractSavedStateViewModelFactory hiltViewModelFactory;
-
- public HiltViewModelFactory(
- @NonNull SavedStateRegistryOwner owner,
- @Nullable Bundle defaultArgs,
- @NonNull Set<String> hiltViewModelKeys,
- @NonNull ViewModelProvider.Factory delegateFactory,
- @NonNull ViewModelComponentBuilder viewModelComponentBuilder) {
- this.hiltViewModelKeys = hiltViewModelKeys;
- this.delegateFactory = delegateFactory;
- this.hiltViewModelFactory =
- new AbstractSavedStateViewModelFactory(owner, defaultArgs) {
- @NonNull
- @Override
- @SuppressWarnings("unchecked")
- protected <T extends ViewModel> T create(
- @NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle) {
- ViewModelComponent component =
- viewModelComponentBuilder.savedStateHandle(handle).build();
- Provider<? extends ViewModel> provider =
- EntryPoints.get(component, ViewModelFactoriesEntryPoint.class)
- .getHiltViewModelMap()
- .get(modelClass.getName());
- if (provider == null) {
- throw new IllegalStateException(
- "Expected the @HiltViewModel-annotated class '"
- + modelClass.getName()
- + "' to be available in the multi-binding of "
- + "@HiltViewModelMap but none was found.");
- }
- return (T) provider.get();
- }
- };
- }
-
- @NonNull
- @Override
- public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
- if (hiltViewModelKeys.contains(modelClass.getName())) {
- return hiltViewModelFactory.create(modelClass);
- } else {
- return delegateFactory.create(modelClass);
- }
- }
-}
diff --git a/java/dagger/hilt/android/internal/lifecycle/HiltViewModelMap.java b/java/dagger/hilt/android/internal/lifecycle/HiltViewModelMap.java
deleted file mode 100644
index 5d54e9c..0000000
--- a/java/dagger/hilt/android/internal/lifecycle/HiltViewModelMap.java
+++ /dev/null
@@ -1,39 +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.internal.lifecycle;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.inject.Qualifier;
-
-/**
- * Internal qualifier for the multibinding map of ViewModels used by the {@link
- * dagger.hilt.android.lifecycle.HiltViewModelFactory}.
- */
-@Qualifier
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.METHOD, ElementType.PARAMETER})
-public @interface HiltViewModelMap {
-
- /** Internal qualifier for the multibinding set of class names annotated with @ViewModelInject. */
- @Qualifier
- @Retention(RetentionPolicy.CLASS)
- @Target({ElementType.METHOD, ElementType.PARAMETER})
- @interface KeySet {}
-}
diff --git a/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java b/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java
deleted file mode 100644
index ef7aa3b..0000000
--- a/java/dagger/hilt/android/internal/managers/ActivityComponentManager.java
+++ /dev/null
@@ -1,92 +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.internal.managers;
-
-import android.app.Activity;
-import android.app.Application;
-import androidx.activity.ComponentActivity;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityRetainedComponent;
-import dagger.hilt.android.internal.builders.ActivityComponentBuilder;
-import dagger.hilt.internal.GeneratedComponentManager;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the Activity.
- *
- * <p>Note: This class is not typed since its type in generated code is always <?> or <Object>. This
- * is mainly due to the fact that we don't know the components at the time of generation, and
- * because even the injector interface type is not a valid type if we have a hilt base class.
- *
- */
-public class ActivityComponentManager implements GeneratedComponentManager<Object> {
- /** Entrypoint for {@link ActivityComponentBuilder}. */
- @EntryPoint
- @InstallIn(ActivityRetainedComponent.class)
- public interface ActivityComponentBuilderEntryPoint {
- ActivityComponentBuilder activityComponentBuilder();
- }
-
- private volatile Object component;
- private final Object componentLock = new Object();
-
- protected final Activity activity;
-
- private final GeneratedComponentManager<ActivityRetainedComponent>
- activityRetainedComponentManager;
-
- public ActivityComponentManager(Activity activity) {
- this.activity = activity;
- this.activityRetainedComponentManager =
- new ActivityRetainedComponentManager((ComponentActivity) activity);
- }
-
- @Override
- public Object generatedComponent() {
- if (component == null) {
- synchronized (componentLock) {
- if (component == null) {
- component = createComponent();
- }
- }
- }
- return component;
- }
-
- protected Object createComponent() {
- if (!(activity.getApplication() instanceof GeneratedComponentManager)) {
- if (Application.class.equals(activity.getApplication().getClass())) {
- throw new IllegalStateException(
- "Hilt Activity must be attached to an @HiltAndroidApp Application. "
- + "Did you forget to specify your Application's class name in your manifest's "
- + "<application />'s android:name attribute?");
- }
- throw new IllegalStateException(
- "Hilt Activity must be attached to an @AndroidEntryPoint Application. Found: "
- + activity.getApplication().getClass());
- }
-
- return EntryPoints.get(
- activityRetainedComponentManager, ActivityComponentBuilderEntryPoint.class)
- .activityComponentBuilder()
- .activity(activity)
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java b/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
deleted file mode 100644
index 2d4a72b..0000000
--- a/java/dagger/hilt/android/internal/managers/ActivityRetainedComponentManager.java
+++ /dev/null
@@ -1,168 +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.internal.managers;
-
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.activity.ComponentActivity;
-import dagger.Binds;
-import dagger.Module;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.ActivityRetainedLifecycle;
-import dagger.hilt.android.components.ActivityRetainedComponent;
-import dagger.hilt.android.internal.ThreadUtil;
-import dagger.hilt.android.internal.builders.ActivityRetainedComponentBuilder;
-import dagger.hilt.android.scopes.ActivityRetainedScoped;
-import dagger.hilt.components.SingletonComponent;
-import dagger.hilt.internal.GeneratedComponentManager;
-import java.util.HashSet;
-import java.util.Set;
-import javax.inject.Inject;
-
-/** A manager for the creation of components that survives activity configuration changes. */
-final class ActivityRetainedComponentManager
- implements GeneratedComponentManager<ActivityRetainedComponent> {
-
- /** Entry point for {@link ActivityRetainedComponentBuilder}. */
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- public interface ActivityRetainedComponentBuilderEntryPoint {
- ActivityRetainedComponentBuilder retainedComponentBuilder();
- }
-
- /** Entry point for {@link Lifecycle}. */
- @EntryPoint
- @InstallIn(ActivityRetainedComponent.class)
- public interface ActivityRetainedLifecycleEntryPoint {
- ActivityRetainedLifecycle getActivityRetainedLifecycle();
- }
-
- static final class ActivityRetainedComponentViewModel extends ViewModel {
- private final ActivityRetainedComponent component;
-
- ActivityRetainedComponentViewModel(ActivityRetainedComponent component) {
- this.component = component;
- }
-
- ActivityRetainedComponent getComponent() {
- return component;
- }
-
- @Override
- protected void onCleared() {
- super.onCleared();
- ActivityRetainedLifecycle lifecycle =
- EntryPoints.get(component, ActivityRetainedLifecycleEntryPoint.class)
- .getActivityRetainedLifecycle();
- ((ActivityRetainedComponentManager.Lifecycle) lifecycle).dispatchOnCleared();
- }
- }
-
- private final ViewModelProvider viewModelProvider;
-
- @Nullable private volatile ActivityRetainedComponent component;
- private final Object componentLock = new Object();
-
- ActivityRetainedComponentManager(ComponentActivity activity) {
- this.viewModelProvider =
- new ViewModelProvider(
- activity,
- new ViewModelProvider.Factory() {
- @NonNull
- @Override
- @SuppressWarnings("unchecked")
- public <T extends ViewModel> T create(@NonNull Class<T> aClass) {
- ActivityRetainedComponent component =
- EntryPoints.get(
- activity.getApplication(),
- ActivityRetainedComponentBuilderEntryPoint.class)
- .retainedComponentBuilder()
- .build();
- return (T) new ActivityRetainedComponentViewModel(component);
- }
- });
- }
-
- @Override
- public ActivityRetainedComponent generatedComponent() {
- if (component == null) {
- synchronized (componentLock) {
- if (component == null) {
- component = createComponent();
- }
- }
- }
- return component;
- }
-
- private ActivityRetainedComponent createComponent() {
- return viewModelProvider.get(ActivityRetainedComponentViewModel.class).getComponent();
- }
-
- /** The default implementation of {@link ActivityRetainedLifecycle}. */
- @ActivityRetainedScoped
- static final class Lifecycle implements ActivityRetainedLifecycle {
-
- private final Set<OnClearedListener> listeners = new HashSet<>();
- private boolean onClearedDispatched = false;
-
- @Inject
- Lifecycle() {}
-
- @Override
- public void addOnClearedListener(@NonNull OnClearedListener listener) {
- ThreadUtil.ensureMainThread();
- throwIfOnClearedDispatched();
- listeners.add(listener);
- }
-
- @Override
- public void removeOnClearedListener(@NonNull OnClearedListener listener) {
- ThreadUtil.ensureMainThread();
- throwIfOnClearedDispatched();
- listeners.remove(listener);
- }
-
- void dispatchOnCleared() {
- ThreadUtil.ensureMainThread();
- onClearedDispatched = true;
- for (OnClearedListener listener : listeners) {
- listener.onCleared();
- }
- }
-
- private void throwIfOnClearedDispatched() {
- if (onClearedDispatched) {
- throw new IllegalStateException(
- "There was a race between the call to add/remove an OnClearedListener and onCleared(). "
- + "This can happen when posting to the Main thread from a background thread, "
- + "which is not supported.");
- }
- }
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- abstract static class LifecycleModule {
- @Binds
- abstract ActivityRetainedLifecycle bind(Lifecycle impl);
- }
-}
diff --git a/java/dagger/hilt/android/internal/managers/ApplicationComponentManager.java b/java/dagger/hilt/android/internal/managers/ApplicationComponentManager.java
deleted file mode 100644
index bb645db..0000000
--- a/java/dagger/hilt/android/internal/managers/ApplicationComponentManager.java
+++ /dev/null
@@ -1,46 +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.internal.managers;
-
-import dagger.hilt.internal.GeneratedComponentManager;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the Application.
- */
-public final class ApplicationComponentManager implements GeneratedComponentManager<Object> {
- private volatile Object component;
- private final Object componentLock = new Object();
- private final ComponentSupplier componentCreator;
-
- public ApplicationComponentManager(ComponentSupplier componentCreator) {
- this.componentCreator = componentCreator;
- }
-
- @Override
- public Object generatedComponent() {
- if (component == null) {
- synchronized (componentLock) {
- if (component == null) {
- component = componentCreator.get();
- }
- }
- }
- return component;
- }
-}
diff --git a/java/dagger/hilt/android/internal/managers/BUILD b/java/dagger/hilt/android/internal/managers/BUILD
deleted file mode 100644
index 3bc8df1..0000000
--- a/java/dagger/hilt/android/internal/managers/BUILD
+++ /dev/null
@@ -1,60 +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.
-
-# Description:
-# Internal Hilt Android managers
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "component_supplier",
- srcs = ["ComponentSupplier.java"],
-)
-
-android_library(
- name = "managers",
- srcs = [
- "ActivityComponentManager.java",
- "ActivityRetainedComponentManager.java",
- "ApplicationComponentManager.java",
- "BroadcastReceiverComponentManager.java",
- "FragmentComponentManager.java",
- "ServiceComponentManager.java",
- "ViewComponentManager.java",
- ],
- deps = [
- ":component_supplier",
- "//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android:activity_retained_lifecycle",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/components:view_model_component",
- "//java/dagger/hilt/android/internal",
- "//java/dagger/hilt/android/internal/builders",
- "//java/dagger/hilt/android/scopes:activity_retained_scoped",
- "//java/dagger/hilt/android/scopes:view_model_scoped",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:preconditions",
- "@maven//:androidx_activity_activity",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_fragment_fragment",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java b/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java
deleted file mode 100644
index 471c31c..0000000
--- a/java/dagger/hilt/android/internal/managers/BroadcastReceiverComponentManager.java
+++ /dev/null
@@ -1,44 +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.internal.managers;
-
-import android.app.Application;
-import android.content.Context;
-import dagger.hilt.internal.GeneratedComponentManager;
-import dagger.hilt.internal.Preconditions;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the BroadcastReceiver.
- */
-public final class BroadcastReceiverComponentManager {
- @SuppressWarnings("unchecked")
- public static Object generatedComponent(Context context) {
- Application application = (Application) context.getApplicationContext();
-
- Preconditions.checkArgument(
- application instanceof GeneratedComponentManager,
- "Hilt BroadcastReceiver must be attached to an @AndroidEntryPoint Application. "
- + "Found: %s",
- application.getClass());
-
- return ((GeneratedComponentManager<?>) application).generatedComponent();
- }
-
- private BroadcastReceiverComponentManager() {}
-}
diff --git a/java/dagger/hilt/android/internal/managers/ComponentSupplier.java b/java/dagger/hilt/android/internal/managers/ComponentSupplier.java
deleted file mode 100644
index de702a9..0000000
--- a/java/dagger/hilt/android/internal/managers/ComponentSupplier.java
+++ /dev/null
@@ -1,26 +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.internal.managers;
-
-/**
- * Interface for supplying a component. This is separate from the Supplier interface so that
- * optimizers can strip this method (and therefore all the Dagger code) from the main dex even if a
- * Supplier is referenced in code kept in the main dex.
- */
-public interface ComponentSupplier {
- Object get();
-}
diff --git a/java/dagger/hilt/android/internal/managers/FragmentComponentManager.java b/java/dagger/hilt/android/internal/managers/FragmentComponentManager.java
deleted file mode 100644
index 40dd60a..0000000
--- a/java/dagger/hilt/android/internal/managers/FragmentComponentManager.java
+++ /dev/null
@@ -1,116 +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.internal.managers;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.os.Bundle;
-import androidx.fragment.app.Fragment;
-import android.view.LayoutInflater;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.internal.builders.FragmentComponentBuilder;
-import dagger.hilt.internal.GeneratedComponentManager;
-import dagger.hilt.internal.Preconditions;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the Fragment.
- *
- * <p>Note: This class is not typed since its type in generated code is always <?> or <Object>. This
- * is mainly due to the fact that we don't know the components at the time of generation, and
- * because even the injector interface type is not a valid type if we have a hilt base class.
- *
- */
-public class FragmentComponentManager implements GeneratedComponentManager<Object> {
- /** Entrypoint for {@link FragmentComponentBuilder}. */
- @EntryPoint
- @InstallIn(ActivityComponent.class)
- public interface FragmentComponentBuilderEntryPoint {
- FragmentComponentBuilder fragmentComponentBuilder();
- }
-
- private volatile Object component;
- private final Object componentLock = new Object();
- private final Fragment fragment;
-
- public FragmentComponentManager(Fragment fragment) {
- this.fragment = fragment;
- }
-
- @Override
- public Object generatedComponent() {
- if (component == null) {
- synchronized (componentLock) {
- if (component == null) {
- component = createComponent();
- }
- }
- }
- return component;
- }
-
- private Object createComponent() {
- Preconditions.checkNotNull(
- fragment.getHost(),
- "Hilt Fragments must be attached before creating the component.");
- Preconditions.checkState(
- fragment.getHost() instanceof GeneratedComponentManager,
- "Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: %s",
- fragment.getHost().getClass());
-
- validate(fragment);
-
- return EntryPoints.get(fragment.getHost(), FragmentComponentBuilderEntryPoint.class)
- .fragmentComponentBuilder()
- .fragment(fragment)
- .build();
- }
-
- /** Returns the fragments bundle, creating a new one if none exists. */
- public static final void initializeArguments(Fragment fragment) {
- Preconditions.checkNotNull(fragment);
- if (fragment.getArguments() == null) {
- fragment.setArguments(new Bundle());
- }
- }
-
- public static final Context findActivity(Context context) {
- while (context instanceof ContextWrapper
- && !(context instanceof Activity)) {
- context = ((ContextWrapper) context).getBaseContext();
- }
- return context;
- }
-
- public static ContextWrapper createContextWrapper(Context base, Fragment fragment) {
- return new ViewComponentManager.FragmentContextWrapper(base, fragment);
- }
-
- public static ContextWrapper createContextWrapper(
- LayoutInflater baseInflater, Fragment fragment) {
- return new ViewComponentManager.FragmentContextWrapper(baseInflater, fragment);
- }
-
- /** Called immediately before component creation to allow validation on the Fragment. */
- protected void validate(Fragment fragment) {
- }
-}
diff --git a/java/dagger/hilt/android/internal/managers/ServiceComponentManager.java b/java/dagger/hilt/android/internal/managers/ServiceComponentManager.java
deleted file mode 100644
index d5e7f15..0000000
--- a/java/dagger/hilt/android/internal/managers/ServiceComponentManager.java
+++ /dev/null
@@ -1,75 +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.internal.managers;
-
-import android.app.Application;
-import android.app.Service;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.internal.builders.ServiceComponentBuilder;
-import dagger.hilt.components.SingletonComponent;
-import dagger.hilt.internal.GeneratedComponentManager;
-import dagger.hilt.internal.Preconditions;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the Service.
- *
- * <p>Note: This class is not typed since its type in generated code is always <?> or <Object>. This
- * is mainly due to the fact that we don't know the components at the time of generation, and
- * because even the injector interface type is not a valid type if we have a hilt base class.
- */
-public final class ServiceComponentManager implements GeneratedComponentManager<Object> {
- /** Entrypoint for {@link ServiceComponentBuilder}. */
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- public interface ServiceComponentBuilderEntryPoint {
- ServiceComponentBuilder serviceComponentBuilder();
- }
-
- private final Service service;
- private Object component;
-
- public ServiceComponentManager(Service service) {
- this.service = service;
- }
-
- // This isn't ever really publicly exposed on a service so it should be fine without
- // synchronization.
- @Override
- public Object generatedComponent() {
- if (component == null) {
- component = createComponent();
- }
- return component;
- }
-
- private Object createComponent() {
- Application application = service.getApplication();
- Preconditions.checkState(
- application instanceof GeneratedComponentManager,
- "Hilt service must be attached to an @AndroidEntryPoint Application. Found: %s",
- application.getClass());
-
- return EntryPoints.get(application, ServiceComponentBuilderEntryPoint.class)
- .serviceComponentBuilder()
- .service(service)
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/internal/managers/ViewComponentManager.java b/java/dagger/hilt/android/internal/managers/ViewComponentManager.java
deleted file mode 100644
index cb2ece0..0000000
--- a/java/dagger/hilt/android/internal/managers/ViewComponentManager.java
+++ /dev/null
@@ -1,201 +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.internal.managers;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import androidx.fragment.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.components.FragmentComponent;
-import dagger.hilt.android.internal.builders.ViewComponentBuilder;
-import dagger.hilt.android.internal.builders.ViewWithFragmentComponentBuilder;
-import dagger.hilt.internal.GeneratedComponentManager;
-import dagger.hilt.internal.Preconditions;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the View.
- *
- * <p>Note: This class is not typed since its type in generated code is always <?> or <Object>. This
- * is mainly due to the fact that we don't know the components at the time of generation, and
- * because even the injector interface type is not a valid type if we have a hilt base class.
- */
-public final class ViewComponentManager implements GeneratedComponentManager<Object> {
- /** Entrypoint for {@link ViewWithFragmentComponentBuilder}. */
- @EntryPoint
- @InstallIn(FragmentComponent.class)
- public interface ViewWithFragmentComponentBuilderEntryPoint {
- ViewWithFragmentComponentBuilder viewWithFragmentComponentBuilder();
- }
-
- /** Entrypoint for {@link ViewComponentBuilder}. */
- @EntryPoint
- @InstallIn(ActivityComponent.class)
- public interface ViewComponentBuilderEntryPoint {
- ViewComponentBuilder viewComponentBuilder();
- }
-
- private volatile Object component;
- private final Object componentLock = new Object();
- private final boolean hasFragmentBindings;
- private final View view;
-
- public ViewComponentManager(View view, boolean hasFragmentBindings) {
- this.view = view;
- this.hasFragmentBindings = hasFragmentBindings;
- }
-
- @Override
- public Object generatedComponent() {
- if (component == null) {
- synchronized (componentLock) {
- if (component == null) {
- component = createComponent();
- }
- }
- }
- return component;
- }
-
- private Object createComponent() {
- GeneratedComponentManager<?> componentManager =
- getParentComponentManager(/*allowMissing=*/ false);
- if (hasFragmentBindings) {
- return EntryPoints.get(componentManager, ViewWithFragmentComponentBuilderEntryPoint.class)
- .viewWithFragmentComponentBuilder()
- .view(view)
- .build();
- } else {
- return EntryPoints.get(componentManager, ViewComponentBuilderEntryPoint.class)
- .viewComponentBuilder()
- .view(view)
- .build();
- }
- }
-
- /* Returns the component manager of the parent or null if not found. */
- public GeneratedComponentManager<?> maybeGetParentComponentManager() {
- return getParentComponentManager(/*allowMissing=*/ true);
- }
-
- private GeneratedComponentManager<?> getParentComponentManager(boolean allowMissing) {
- if (hasFragmentBindings) {
- Context context = getParentContext(FragmentContextWrapper.class, allowMissing);
- if (context instanceof FragmentContextWrapper) {
-
- FragmentContextWrapper fragmentContextWrapper = (FragmentContextWrapper) context;
- return (GeneratedComponentManager<?>) fragmentContextWrapper.fragment;
- } else if (allowMissing) {
- // We didn't find anything, so return null if we're not supposed to fail.
- // The rest of the logic is just about getting a good error message.
- return null;
- }
-
- // Check if there was a valid parent component, just not a Fragment, to give a more
- // specific error.
- Context parent = getParentContext(GeneratedComponentManager.class, allowMissing);
- Preconditions.checkState(
- !(parent instanceof GeneratedComponentManager),
- "%s, @WithFragmentBindings Hilt view must be attached to an "
- + "@AndroidEntryPoint Fragment. "
- + "Was attached to context %s",
- view.getClass(),
- parent.getClass().getName());
- } else {
- Context context = getParentContext(GeneratedComponentManager.class, allowMissing);
- if (context instanceof GeneratedComponentManager) {
- return (GeneratedComponentManager<?>) context;
- } else if (allowMissing) {
- return null;
- }
- }
-
- // Couldn't find any parent components to descend from.
- throw new IllegalStateException(
- String.format(
- "%s, Hilt view must be attached to an @AndroidEntryPoint Fragment or Activity.",
- view.getClass()));
-
- }
-
- private Context getParentContext(Class<?> parentType, boolean allowMissing) {
- Context context = unwrap(view.getContext(), parentType);
- if (context == unwrap(context.getApplicationContext(), GeneratedComponentManager.class)) {
- // If we searched for a type but ended up on the application context, just return null
- // as this is never what we are looking for
- Preconditions.checkState(
- allowMissing,
- "%s, Hilt view cannot be created using the application context. "
- + "Use a Hilt Fragment or Activity context.",
- view.getClass());
- return null;
- }
- return context;
- }
-
- private static Context unwrap(Context context, Class<?> target) {
- while (context instanceof ContextWrapper && !target.isInstance(context)) {
- context = ((ContextWrapper) context).getBaseContext();
- }
- return context;
- }
-
- /**
- * Do not use except in Hilt generated code!
- *
- * <p>A wrapper class to expose the {@link Fragment} to the views they're inflating.
- */
- // This is only non-final for the account override
- public static final class FragmentContextWrapper extends ContextWrapper {
- private LayoutInflater baseInflater;
- private LayoutInflater inflater;
- public final Fragment fragment;
-
- public FragmentContextWrapper(Context base, Fragment fragment) {
- super(Preconditions.checkNotNull(base));
- this.baseInflater = null;
- this.fragment = Preconditions.checkNotNull(fragment);
- }
-
- public FragmentContextWrapper(LayoutInflater baseInflater, Fragment fragment) {
- super(Preconditions.checkNotNull(Preconditions.checkNotNull(baseInflater).getContext()));
- this.baseInflater = baseInflater;
- this.fragment = Preconditions.checkNotNull(fragment);
- }
-
- @Override
- public Object getSystemService(String name) {
- if (!LAYOUT_INFLATER_SERVICE.equals(name)) {
- return getBaseContext().getSystemService(name);
- }
- if (inflater == null) {
- if (baseInflater == null) {
- baseInflater =
- (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
- }
- inflater = baseInflater.cloneInContext(this);
- }
- return inflater;
- }
- }
-}
diff --git a/java/dagger/hilt/android/internal/migration/BUILD b/java/dagger/hilt/android/internal/migration/BUILD
deleted file mode 100644
index b877f6f..0000000
--- a/java/dagger/hilt/android/internal/migration/BUILD
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Internal classes for migration
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "injected_by_hilt",
- srcs = ["InjectedByHilt.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/internal/migration/InjectedByHilt.java b/java/dagger/hilt/android/internal/migration/InjectedByHilt.java
deleted file mode 100644
index 087a7ee..0000000
--- a/java/dagger/hilt/android/internal/migration/InjectedByHilt.java
+++ /dev/null
@@ -1,25 +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.internal.migration;
-
-/**
- * Do not use except in Hilt generated code!
- */
-public interface InjectedByHilt {
- /** Returns true if this class was injected by Hilt. */
- boolean wasInjectedByHilt();
-}
diff --git a/java/dagger/hilt/android/internal/modules/ActivityModule.java b/java/dagger/hilt/android/internal/modules/ActivityModule.java
deleted file mode 100644
index 080e203..0000000
--- a/java/dagger/hilt/android/internal/modules/ActivityModule.java
+++ /dev/null
@@ -1,49 +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.internal.modules;
-
-import android.app.Activity;
-import android.content.Context;
-import androidx.fragment.app.FragmentActivity;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.Reusable;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.qualifiers.ActivityContext;
-
-/** Provides convenience bindings for activities. */
-@Module
-@InstallIn(ActivityComponent.class)
-abstract class ActivityModule {
- @Binds
- @ActivityContext
- abstract Context provideContext(Activity activity);
-
- @Provides
- @Reusable
- static FragmentActivity provideFragmentActivity(Activity activity) {
- try {
- return (FragmentActivity) activity;
- } catch (ClassCastException e) {
- throw new IllegalStateException("Expected activity to be a FragmentActivity: " + activity, e);
- }
- }
-
- private ActivityModule() {}
-}
diff --git a/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java b/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java
deleted file mode 100644
index af4ebc2..0000000
--- a/java/dagger/hilt/android/internal/modules/ApplicationContextModule.java
+++ /dev/null
@@ -1,47 +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.internal.modules;
-
-import android.app.Application;
-import android.content.Context;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.qualifiers.ApplicationContext;
-import dagger.hilt.components.SingletonComponent;
-
-/** Provides a binding for an Android BinderFragment Context. */
-@Module
-@InstallIn(SingletonComponent.class)
-public final class ApplicationContextModule {
- private final Context applicationContext;
-
- public ApplicationContextModule(Context applicationContext) {
- this.applicationContext = applicationContext;
- }
-
- @Provides
- @ApplicationContext
- Context provideContext() {
- return applicationContext;
- }
-
- @Provides
- Application provideApplication() {
- return (Application) applicationContext.getApplicationContext();
- }
-}
diff --git a/java/dagger/hilt/android/internal/modules/BUILD b/java/dagger/hilt/android/internal/modules/BUILD
deleted file mode 100644
index a36e237..0000000
--- a/java/dagger/hilt/android/internal/modules/BUILD
+++ /dev/null
@@ -1,37 +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.
-
-# Description:
-# Hilt android modules for standard components.
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "modules",
- srcs = glob(["*.java"]),
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/qualifiers",
- "@maven//:androidx_activity_activity",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_fragment_fragment",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/internal/testing/BUILD b/java/dagger/hilt/android/internal/testing/BUILD
deleted file mode 100644
index b0bc361..0000000
--- a/java/dagger/hilt/android/internal/testing/BUILD
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Internal Hilt android testing libraries
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "test_injector",
- testonly = 1,
- srcs = [
- "TestApplicationInjector.java",
- "TestInjector.java",
- ],
-)
-
-android_library(
- name = "internal_test_root",
- srcs = [
- "InternalTestRoot.java",
- ],
- deps = [
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-android_library(
- name = "test_application_component_manager",
- testonly = 1,
- srcs = ["TestApplicationComponentManager.java"],
- deps = [
- ":test_component_data",
- ":test_injector",
- "//java/dagger/hilt/android/testing:on_component_ready_runner",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:preconditions",
- "@maven//:junit_junit",
- ],
-)
-
-android_library(
- name = "test_component_data",
- testonly = 1,
- srcs = [
- "TestComponentData.java",
- "TestComponentDataSupplier.java",
- ],
- deps = [
- ":test_injector",
- "//java/dagger/hilt/internal:component_manager",
- ],
-)
-
-android_library(
- name = "test_application_component_manager_holder",
- testonly = 1,
- srcs = ["TestApplicationComponentManagerHolder.java"],
-)
-
-android_library(
- name = "mark_that_rules_ran_rule",
- testonly = 1,
- srcs = ["MarkThatRulesRanRule.java"],
- deps = [
- ":test_application_component_manager",
- ":test_application_component_manager_holder",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:preconditions",
- "@maven//:androidx_test_core",
- "@maven//:junit_junit",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["**/*"]),
-)
diff --git a/java/dagger/hilt/android/internal/testing/InternalTestRoot.java b/java/dagger/hilt/android/internal/testing/InternalTestRoot.java
deleted file mode 100644
index c3bbf0c..0000000
--- a/java/dagger/hilt/android/internal/testing/InternalTestRoot.java
+++ /dev/null
@@ -1,38 +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.internal.testing;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import android.app.Application;
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/** Annotation that generates a Hilt test application. */
-@Retention(CLASS)
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface InternalTestRoot {
-
- /** Returns the test class. */
- Class<?> testClass();
-
- /** Returns the base {@link Application} class. */
- Class<? extends Application> applicationBaseClass();
-}
diff --git a/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java b/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java
deleted file mode 100644
index 17c40b3..0000000
--- a/java/dagger/hilt/android/internal/testing/MarkThatRulesRanRule.java
+++ /dev/null
@@ -1,136 +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.internal.testing;
-
-import static dagger.hilt.internal.Preconditions.checkNotNull;
-import static dagger.hilt.internal.Preconditions.checkState;
-
-import android.content.Context;
-import androidx.test.core.app.ApplicationProvider;
-import dagger.hilt.internal.GeneratedComponentManager;
-import java.lang.annotation.Annotation;
-import java.util.concurrent.atomic.AtomicBoolean;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * A Junit {@code TestRule} that's installed in all Hilt tests.
- *
- * <p>This rule enforces that a Hilt TestRule has run. The Dagger component will not be created
- * without this test rule.
- */
-public final class MarkThatRulesRanRule implements TestRule {
- private static final String HILT_ANDROID_APP = "dagger.hilt.android.HiltAndroidApp";
- private static final String HILT_ANDROID_TEST = "dagger.hilt.android.testing.HiltAndroidTest";
-
- private final Context context = ApplicationProvider.getApplicationContext();
- private final Object testInstance;
- private final boolean autoAddModule;
-
- private final AtomicBoolean started = new AtomicBoolean(false);
-
- public MarkThatRulesRanRule(Object testInstance) {
- this.autoAddModule = true;
- this.testInstance = checkNotNull(testInstance);
- checkState(
- hasAnnotation(testInstance, HILT_ANDROID_TEST),
- "Expected %s to be annotated with @HiltAndroidTest.",
- testInstance.getClass().getName());
- checkState(
- context instanceof GeneratedComponentManager,
- "Hilt test, %s, must use a Hilt test application but found %s. To fix, configure the test "
- + "to use HiltTestApplication or a custom Hilt test application generated with "
- + "@CustomTestApplication.",
- testInstance.getClass().getName(),
- context.getClass().getName());
- checkState(
- !hasAnnotation(context, HILT_ANDROID_APP),
- "Hilt test, %s, cannot use a @HiltAndroidApp application but found %s. To fix, configure "
- + "the test to use HiltTestApplication or a custom Hilt test application generated "
- + "with @CustomTestApplication.",
- testInstance.getClass().getName(),
- context.getClass().getName());
- }
-
- public void delayComponentReady() {
- checkState(!started.get(), "Called delayComponentReady after test execution started");
- getTestApplicationComponentManager().delayComponentReady();
- }
-
- public void componentReady() {
- checkState(started.get(), "Called componentReady before test execution started");
- getTestApplicationComponentManager().componentReady();
- }
-
- public void inject() {
- getTestApplicationComponentManager().inject();
- }
-
- @Override
- public Statement apply(final Statement base, Description description) {
- started.set(true);
- checkState(
- description.getTestClass().isInstance(testInstance),
- "HiltAndroidRule was constructed with an argument that was not an instance of the test"
- + " class");
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
-
- TestApplicationComponentManager componentManager = getTestApplicationComponentManager();
- try {
- // This check is required to check that state hasn't been set before this rule runs. This
- // prevents cases like setting state in Application.onCreate for Gradle emulator tests
- // that will get cleared after running the first test case.
- componentManager.checkStateIsCleared();
- componentManager.setAutoAddModule(autoAddModule);
- if (testInstance != null) {
- componentManager.setTestInstance(testInstance);
- }
- componentManager.setHasHiltTestRule(description);
- base.evaluate();
- componentManager.verifyDelayedComponentWasMadeReady();
- } finally {
- componentManager.clearState();
- }
- }
- };
- }
-
- private TestApplicationComponentManager getTestApplicationComponentManager() {
- checkState(
- context instanceof TestApplicationComponentManagerHolder,
- "The context is not an instance of TestApplicationComponentManagerHolder: %s",
- context);
- Object componentManager = ((TestApplicationComponentManagerHolder) context).componentManager();
- checkState(
- componentManager instanceof TestApplicationComponentManager,
- "Expected TestApplicationComponentManagerHolder to return an instance of"
- + "TestApplicationComponentManager");
- return (TestApplicationComponentManager) componentManager;
- }
-
- private static boolean hasAnnotation(Object obj, String annotationName) {
- for (Annotation annotation : obj.getClass().getAnnotations()) {
- if (annotation.annotationType().getName().contentEquals(annotationName)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java b/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java
deleted file mode 100644
index 1878870..0000000
--- a/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java
+++ /dev/null
@@ -1,332 +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.internal.testing;
-
-import android.app.Application;
-import dagger.hilt.android.testing.OnComponentReadyRunner;
-import dagger.hilt.android.testing.OnComponentReadyRunner.OnComponentReadyRunnerHolder;
-import dagger.hilt.internal.GeneratedComponentManager;
-import dagger.hilt.internal.Preconditions;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicReference;
-import org.junit.runner.Description;
-
-/**
- * Do not use except in Hilt generated code!
- *
- * <p>A manager for the creation of components that live in the test Application.
- */
-public final class TestApplicationComponentManager
- implements GeneratedComponentManager<Object>, OnComponentReadyRunnerHolder {
-
- // This is a generated class that we always generate in a known location.
- private static final String TEST_COMPONENT_DATA_SUPPLIER_IMPL =
- "dagger.hilt.android.internal.testing.TestComponentDataSupplierImpl";
-
- private final Application application;
- private final Map<Class<?>, TestComponentData> testComponentDataSupplier;
-
- private final AtomicReference<Object> component = new AtomicReference<>();
- private final AtomicReference<Description> hasHiltTestRule = new AtomicReference<>();
- private final Map<Class<?>, Object> registeredModules = new ConcurrentHashMap<>();
- private final AtomicReference<Boolean> autoAddModuleEnabled = new AtomicReference<>();
- private final AtomicReference<DelayedComponentState> delayedComponentState =
- new AtomicReference<>(DelayedComponentState.NOT_DELAYED);
- private volatile Object testInstance;
- private volatile OnComponentReadyRunner onComponentReadyRunner = new OnComponentReadyRunner();
-
- /**
- * Represents the state of Component readiness. There are two valid transition sequences.
- *
- * <ul>
- * <li>Typical test (no HiltAndroidRule#delayComponentReady): {@code NOT_DELAYED -> INJECTED}
- * <li>Using HiltAndroidRule#delayComponentReady: {@code NOT_DELAYED -> COMPONENT_DELAYED ->
- * COMPONENT_READY -> INJECTED}
- * </ul>
- */
- private enum DelayedComponentState {
- // Valid transitions: COMPONENT_DELAYED, INJECTED
- NOT_DELAYED,
- // Valid transitions: COMPONENT_READY
- COMPONENT_DELAYED,
- // Valid transitions: INJECTED
- COMPONENT_READY,
- // Terminal state
- INJECTED
- }
-
- public TestApplicationComponentManager(Application application) {
- this.application = application;
- try {
- this.testComponentDataSupplier =
- Class.forName(TEST_COMPONENT_DATA_SUPPLIER_IMPL)
- .asSubclass(TestComponentDataSupplier.class)
- .getDeclaredConstructor()
- .newInstance()
- .get();
- } catch (ClassNotFoundException
- | NoSuchMethodException
- | IllegalAccessException
- | InstantiationException
- | InvocationTargetException e) {
- throw new RuntimeException(
- "Hilt classes generated from @HiltAndroidTest are missing. Check that you have annotated "
- + "your test class with @HiltAndroidTest and that the processor is running over your "
- + "test",
- e);
- }
- }
-
- @Override
- public Object generatedComponent() {
- if (component.get() == null) {
- Preconditions.checkState(
- hasHiltTestRule(),
- "The component was not created. Check that you have added the HiltAndroidRule.");
- if (!registeredModules.keySet().containsAll(requiredModules())) {
- Set<Class<?>> difference = new HashSet<>(requiredModules());
- difference.removeAll(registeredModules.keySet());
- throw new IllegalStateException(
- "The component was not created. Check that you have "
- + "registered all test modules:\n\tUnregistered: "
- + difference);
- }
- Preconditions.checkState(
- bindValueReady(), "The test instance has not been set. Did you forget to call #bind()?");
- throw new IllegalStateException(
- "The component has not been created. "
- + "Check that you have called #inject()? Otherwise, "
- + "there is a race between injection and component creation. Make sure there is a "
- + "happens-before edge between the HiltAndroidRule/registering"
- + " all test modules and the first injection.");
- }
- return component.get();
- }
-
- @Override
- public OnComponentReadyRunner getOnComponentReadyRunner() {
- return onComponentReadyRunner;
- }
-
- /** For framework use only! This flag must be set before component creation. */
- void setHasHiltTestRule(Description description) {
- Preconditions.checkState(
- // Some exempted tests set the test rule multiple times. Use CAS to avoid setting twice.
- hasHiltTestRule.compareAndSet(null, description),
- "The hasHiltTestRule flag has already been set!");
- tryToCreateComponent();
- }
-
- void checkStateIsCleared() {
- Preconditions.checkState(
- component.get() == null,
- "The Hilt component cannot be set before Hilt's test rule has run.");
- Preconditions.checkState(
- hasHiltTestRule.get() == null,
- "The Hilt test rule cannot be set before Hilt's test rule has run.");
- Preconditions.checkState(
- autoAddModuleEnabled.get() == null,
- "The Hilt autoAddModuleEnabled cannot be set before Hilt's test rule has run.");
- Preconditions.checkState(
- testInstance == null,
- "The Hilt BindValue instance cannot be set before Hilt's test rule has run.");
- Preconditions.checkState(
- registeredModules.isEmpty(),
- "The Hilt registered modules cannot be set before Hilt's test rule has run.");
- Preconditions.checkState(
- onComponentReadyRunner.isEmpty(),
- "The Hilt onComponentReadyRunner cannot add listeners before Hilt's test rule has run.");
- DelayedComponentState state = delayedComponentState.get();
- switch (state) {
- case NOT_DELAYED:
- case COMPONENT_DELAYED:
- // Expected
- break;
- case COMPONENT_READY:
- throw new IllegalStateException("Called componentReady before test execution started");
- case INJECTED:
- throw new IllegalStateException("Called inject before test execution started");
- }
- }
-
- void clearState() {
- component.set(null);
- hasHiltTestRule.set(null);
- testInstance = null;
- registeredModules.clear();
- autoAddModuleEnabled.set(null);
- delayedComponentState.set(DelayedComponentState.NOT_DELAYED);
- onComponentReadyRunner = new OnComponentReadyRunner();
- }
-
- public Description getDescription() {
- return hasHiltTestRule.get();
- }
-
- public Object getTestInstance() {
- Preconditions.checkState(
- testInstance != null,
- "The test instance has not been set.");
- return testInstance;
- }
-
- /** For framework use only! This method should be called when a required module is installed. */
- public <T> void registerModule(Class<T> moduleClass, T module) {
- Preconditions.checkNotNull(moduleClass);
- Preconditions.checkState(
- testComponentData().daggerRequiredModules().contains(moduleClass),
- "Found unknown module class: %s",
- moduleClass.getName());
- if (requiredModules().contains(moduleClass)) {
- Preconditions.checkState(
- // Some exempted tests register modules multiple times.
- !registeredModules.containsKey(moduleClass),
- "Module is already registered: %s",
- moduleClass.getName());
-
- registeredModules.put(moduleClass, module);
- tryToCreateComponent();
- }
- }
-
- void delayComponentReady() {
- switch (delayedComponentState.getAndSet(DelayedComponentState.COMPONENT_DELAYED)) {
- case NOT_DELAYED:
- // Expected
- break;
- case COMPONENT_DELAYED:
- throw new IllegalStateException("Called delayComponentReady() twice");
- case COMPONENT_READY:
- throw new IllegalStateException("Called delayComponentReady() after componentReady()");
- case INJECTED:
- throw new IllegalStateException("Called delayComponentReady() after inject()");
- }
- }
-
- void componentReady() {
- switch (delayedComponentState.getAndSet(DelayedComponentState.COMPONENT_READY)) {
- case NOT_DELAYED:
- throw new IllegalStateException(
- "Called componentReady(), even though delayComponentReady() was not used.");
- case COMPONENT_DELAYED:
- // Expected
- break;
- case COMPONENT_READY:
- throw new IllegalStateException("Called componentReady() multiple times");
- case INJECTED:
- throw new IllegalStateException("Called componentReady() after inject()");
- }
- tryToCreateComponent();
- }
-
- void inject() {
- switch (delayedComponentState.getAndSet(DelayedComponentState.INJECTED)) {
- case NOT_DELAYED:
- case COMPONENT_READY:
- // Expected
- break;
- case COMPONENT_DELAYED:
- throw new IllegalStateException("Called inject() before calling componentReady()");
- case INJECTED:
- throw new IllegalStateException("Called inject() multiple times");
- }
- Preconditions.checkNotNull(testInstance);
- testInjector().injectTest(testInstance);
- }
-
- void verifyDelayedComponentWasMadeReady() {
- Preconditions.checkState(
- delayedComponentState.get() != DelayedComponentState.COMPONENT_DELAYED,
- "Used delayComponentReady(), but never called componentReady()");
- }
-
- private void tryToCreateComponent() {
- if (hasHiltTestRule()
- && registeredModules.keySet().containsAll(requiredModules())
- && bindValueReady()
- && delayedComponentReady()) {
- Preconditions.checkState(
- autoAddModuleEnabled.get() != null,
- "Component cannot be created before autoAddModuleEnabled is set.");
- Preconditions.checkState(
- component.compareAndSet(
- null,
- componentSupplier().get(registeredModules, testInstance, autoAddModuleEnabled.get())),
- "Tried to create the component more than once! "
- + "There is a race between registering the HiltAndroidRule and registering"
- + " all test modules. Make sure there is a happens-before edge between the two.");
- onComponentReadyRunner.setComponentManager((GeneratedComponentManager) application);
- }
- }
-
- void setTestInstance(Object testInstance) {
- Preconditions.checkNotNull(testInstance);
- Preconditions.checkState(this.testInstance == null, "The test instance was already set!");
- this.testInstance = testInstance;
- }
-
- void setAutoAddModule(boolean autoAddModule) {
- Preconditions.checkState(
- autoAddModuleEnabled.get() == null, "autoAddModuleEnabled is already set!");
- autoAddModuleEnabled.set(autoAddModule);
- }
-
- private Set<Class<?>> requiredModules() {
- return autoAddModuleEnabled.get()
- ? testComponentData().hiltRequiredModules()
- : testComponentData().daggerRequiredModules();
- }
-
- private boolean waitForBindValue() {
- return testComponentData().waitForBindValue();
- }
-
- private TestInjector<Object> testInjector() {
- return testComponentData().testInjector();
- }
-
- private TestComponentData.ComponentSupplier componentSupplier() {
- return testComponentData().componentSupplier();
- }
-
- private TestComponentData testComponentData() {
- return testComponentDataSupplier.get(testClass());
- }
-
- private Class<?> testClass() {
- Preconditions.checkState(
- hasHiltTestRule(),
- "Test must have an HiltAndroidRule.");
- return hasHiltTestRule.get().getTestClass();
- }
-
- private boolean bindValueReady() {
- return !waitForBindValue() || testInstance != null;
- }
-
- private boolean delayedComponentReady() {
- return delayedComponentState.get() != DelayedComponentState.COMPONENT_DELAYED;
- }
-
- private boolean hasHiltTestRule() {
- return hasHiltTestRule.get() != null;
- }
-}
diff --git a/java/dagger/hilt/android/internal/testing/TestApplicationComponentManagerHolder.java b/java/dagger/hilt/android/internal/testing/TestApplicationComponentManagerHolder.java
deleted file mode 100644
index a8695c4..0000000
--- a/java/dagger/hilt/android/internal/testing/TestApplicationComponentManagerHolder.java
+++ /dev/null
@@ -1,24 +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.internal.testing;
-
-/** For use by Hilt internally only! Returns the component manager. */
-public interface TestApplicationComponentManagerHolder {
- // Returns {@link Object} so that we do not expose {@code TestApplicationComponentManager} to
- // clients. Framework code should explicitly cast to {@code TestApplicationComponentManager}.
- Object componentManager();
-}
diff --git a/java/dagger/hilt/android/internal/testing/TestApplicationInjector.java b/java/dagger/hilt/android/internal/testing/TestApplicationInjector.java
deleted file mode 100644
index c7ff5c9..0000000
--- a/java/dagger/hilt/android/internal/testing/TestApplicationInjector.java
+++ /dev/null
@@ -1,24 +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.internal.testing;
-
-/**
- * Interface to expose a method for members injection for use in tests.
- */
-public interface TestApplicationInjector<T> {
- void injectApp(T t);
-}
diff --git a/java/dagger/hilt/android/internal/testing/TestComponentData.java b/java/dagger/hilt/android/internal/testing/TestComponentData.java
deleted file mode 100644
index 4eed6fb..0000000
--- a/java/dagger/hilt/android/internal/testing/TestComponentData.java
+++ /dev/null
@@ -1,79 +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.internal.testing;
-
-import dagger.hilt.internal.Preconditions;
-import java.util.Map;
-import java.util.Set;
-
-/** Contains the data needed to create a test's component. */
-public final class TestComponentData {
- private final ComponentSupplier componentSupplier;
- private final TestInjector<Object> testInjector;
- private final Set<Class<?>> daggerRequiredModules;
- private final Set<Class<?>> hiltRequiredModules;
- private final boolean waitForBindValue;
-
- public TestComponentData(
- boolean waitForBindValue,
- TestInjector<Object> testInjector,
- Set<Class<?>> daggerRequiredModules,
- Set<Class<?>> hiltRequiredModules,
- ComponentSupplier componentSupplier) {
- Preconditions.checkState(
- daggerRequiredModules.containsAll(hiltRequiredModules),
- "Hilt required modules should be subset of Dagger required modules.");
- this.componentSupplier = componentSupplier;
- this.testInjector = testInjector;
- this.daggerRequiredModules = daggerRequiredModules;
- this.waitForBindValue = waitForBindValue;
- this.hiltRequiredModules = hiltRequiredModules;
- }
-
- /** Returns the {@link ComponentSupplier}. */
- public ComponentSupplier componentSupplier() {
- return componentSupplier;
- }
-
- /** Returns the {@link TestInjector}. */
- public TestInjector<Object> testInjector() {
- return testInjector;
- }
-
- /** Returns the set of modules that Dagger cannot create instances of itself */
- public Set<Class<?>> daggerRequiredModules() {
- return daggerRequiredModules;
- }
-
- /**
- * Returns a subset of {@link #daggerRequiredModules} that filters out the modules Hilt can
- * instantiate itself.
- */
- public Set<Class<?>> hiltRequiredModules() {
- return hiltRequiredModules;
- }
-
- /** Returns true if creation of the component needs to wait for bind() to be called. */
- public boolean waitForBindValue() {
- return waitForBindValue;
- }
-
- /** Returns the component using the given registered modules. */
- public interface ComponentSupplier {
- Object get(Map<Class<?>, ?> registeredModules, Object testInstance, Boolean autoAddModule);
- }
-}
diff --git a/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java b/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java
deleted file mode 100644
index e39073f..0000000
--- a/java/dagger/hilt/android/internal/testing/TestComponentDataSupplier.java
+++ /dev/null
@@ -1,26 +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.internal.testing;
-
-import java.util.Map;
-
-/** Stores the {@link TestComponentData} for all Hilt test classes. */
-public abstract class TestComponentDataSupplier {
-
- /** Returns a map of {@link TestComponentData} keyed by test class. */
- protected abstract Map<Class<?>, TestComponentData> get();
-}
diff --git a/java/dagger/hilt/android/internal/testing/TestInjector.java b/java/dagger/hilt/android/internal/testing/TestInjector.java
deleted file mode 100644
index 7055f91..0000000
--- a/java/dagger/hilt/android/internal/testing/TestInjector.java
+++ /dev/null
@@ -1,24 +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.internal.testing;
-
-/**
- * Interface to expose a method for members injection for use in tests.
- */
-public interface TestInjector<T> {
- void injectTest(T t);
-}
diff --git a/java/dagger/hilt/android/lifecycle/BUILD b/java/dagger/hilt/android/lifecycle/BUILD
deleted file mode 100644
index fd80510..0000000
--- a/java/dagger/hilt/android/lifecycle/BUILD
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Hilt ViewModel integration.
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "lifecycle",
- srcs = glob(["*.java"]),
- exported_plugins = [
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor",
- ],
- proguard_specs = ["proguard-rules.pro"],
- exports = [
- "//java/dagger/hilt/android/components:view_model_component",
- "//java/dagger/hilt/android/internal/lifecycle",
- ],
- deps = [
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/lifecycle/HiltViewModel.java b/java/dagger/hilt/android/lifecycle/HiltViewModel.java
deleted file mode 100644
index 198ec8a..0000000
--- a/java/dagger/hilt/android/lifecycle/HiltViewModel.java
+++ /dev/null
@@ -1,68 +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.lifecycle;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Identifies a {@link androidx.lifecycle.ViewModel} for construction injection.
- *
- * <p>The {@code ViewModel} annotated with {@link HiltViewModel} will be available for creation by
- * the {@link dagger.hilt.android.lifecycle.HiltViewModelFactory} and can be retrieved by default in
- * an {@code Activity} or {@code Fragment} annotated with {@link
- * dagger.hilt.android.AndroidEntryPoint}. The {@code HiltViewModel} containing a constructor
- * annotated with {@link javax.inject.Inject} will have its dependencies defined in the constructor
- * parameters injected by Dagger's Hilt.
- *
- * <p>Example:
- *
- * <pre>
- * @HiltViewModel
- * public class DonutViewModel extends ViewModel {
- * @Inject
- * public DonutViewModel(SavedStateHandle handle, RecipeRepository repository) {
- * // ...
- * }
- * }
- * </pre>
- *
- * <pre>
- * @AndroidEntryPoint
- * public class CookingActivity extends AppCompatActivity {
- * public void onCreate(Bundle savedInstanceState) {
- * DonutViewModel vm = new ViewModelProvider(this).get(DonutViewModel.class);
- * }
- * }
- * </pre>
- *
- * <p>Exactly one constructor in the {@code ViewModel} must be annotated with {@code Inject}.
- *
- * <p>Only dependencies available in the {@link dagger.hilt.android.components.ViewModelComponent}
- * can be injected into the {@code ViewModel}.
- *
- * <p>
- *
- * @see dagger.hilt.android.components.ViewModelComponent
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-@GeneratesRootInput
-public @interface HiltViewModel {}
diff --git a/java/dagger/hilt/android/lifecycle/proguard-rules.pro b/java/dagger/hilt/android/lifecycle/proguard-rules.pro
deleted file mode 100644
index edd3d3d..0000000
--- a/java/dagger/hilt/android/lifecycle/proguard-rules.pro
+++ /dev/null
@@ -1,2 +0,0 @@
-# Keep class names of Hilt injected ViewModels since their name are used as a multibinding map key.
--keepnames @dagger.hilt.android.lifecycle.HiltViewModel class * extends androidx.lifecycle.ViewModel
diff --git a/java/dagger/hilt/android/migration/BUILD b/java/dagger/hilt/android/migration/BUILD
deleted file mode 100644
index ade47c3..0000000
--- a/java/dagger/hilt/android/migration/BUILD
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Helpers for migrating to Hilt.
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "optional_inject",
- srcs = [
- "OptionalInject.java",
- "OptionalInjectCheck.java",
- ],
- exports = [
- "//java/dagger/hilt/android/internal/migration:injected_by_hilt",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt/android/internal/migration:injected_by_hilt",
- "//java/dagger/hilt/internal:preconditions",
- "@maven//:androidx_activity_activity",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_fragment_fragment",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
- deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["**/*"]),
-)
diff --git a/java/dagger/hilt/android/migration/OptionalInject.java b/java/dagger/hilt/android/migration/OptionalInject.java
deleted file mode 100644
index 14c1387..0000000
--- a/java/dagger/hilt/android/migration/OptionalInject.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.migration;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * When placed on an {@link dagger.hilt.android.AndroidEntryPoint}-annotated activity / fragment /
- * view / etc, allows injection to occur optionally based on whether or not the application is using
- * Hilt.
- *
- * <p>When using this annotation, you can use {@link OptionalInjectCheck#wasInjectedByHilt} to check
- * at runtime if the annotated class was injected by Hilt. Additionally, this annotation will also
- * cause a method, {@code wasInjectedByHilt} to be generated in the Hilt base class as well, that
- * behaves the same as {@link OptionalInjectCheck#wasInjectedByHilt}. The method is available to
- * users that extend the Hilt base class directly and don't use the Gradle plugin.
- *
- * <p>Example usage:
- *
- * <pre><code>
- * {@literal @}OptionalInject
- * {@literal @}AndroidEntryPoint
- * public final class MyFragment extends Fragment {
- *
- * {@literal @}Inject Foo foo;
- *
- * {@literal @}Override
- * public void onAttach(Activity activity) {
- * // Injection will happen here, but only if the Activity and the Application are also
- * // AndroidEntryPoints and were injected by Hilt.
- * super.onAttach(activity);
- * if (!OptionalInjectCheck.wasInjectedByHilt(this)) {
- * // Get Dagger components the previous way and inject.
- * }
- * }
- * }
- * </code></pre>
- *
- * <p>This is useful for libraries that have to support Hilt users as well as non-Hilt users.
- * Injection will happen if the parent type (e.g. the activity of a fragment) is an {@link
- * dagger.hilt.android.AndroidEntryPoint} annotated class and if that parent was also injected via
- * Hilt.
- *
- * @see OptionalInjectCheck
- * @see <a href="https://dagger.dev/hilt/optional-inject">Optional injection</a>
- */
-@Target(ElementType.TYPE)
-public @interface OptionalInject {}
diff --git a/java/dagger/hilt/android/migration/OptionalInjectCheck.java b/java/dagger/hilt/android/migration/OptionalInjectCheck.java
deleted file mode 100644
index f9d0ad8..0000000
--- a/java/dagger/hilt/android/migration/OptionalInjectCheck.java
+++ /dev/null
@@ -1,97 +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.migration;
-
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import android.view.View;
-import androidx.activity.ComponentActivity;
-import dagger.hilt.android.internal.migration.InjectedByHilt;
-import dagger.hilt.internal.Preconditions;
-
-/**
- * Utility methods for validating if an {@link dagger.hilt.android.AndroidEntryPoint}-annotated
- * class that is also annotated with {@link OptionalInject} was injected by Hilt.
- *
- * @see OptionalInject
- */
-public final class OptionalInjectCheck {
-
- /**
- * Returns true if the Activity was injected by Hilt.
- *
- * @throws IllegalArgumentException if the given instance is not an AndroidEntryPoint nor is
- * annotated with {@link OptionalInject}.
- */
- public static boolean wasInjectedByHilt(@NonNull ComponentActivity activity) {
- return check(activity);
- }
-
- /**
- * Returns true if the BroadcastReceiver was injected by Hilt.
- *
- * @throws IllegalArgumentException if the given instance is not an AndroidEntryPoint nor is
- * annotated with {@link OptionalInject}.
- */
- public static boolean wasInjectedByHilt(@NonNull BroadcastReceiver broadcastReceiver) {
- return check(broadcastReceiver);
- }
-
- /**
- * Returns true if the Fragment was injected by Hilt.
- *
- * @throws IllegalArgumentException if the given instance is not an AndroidEntryPoint nor is
- * annotated with {@link OptionalInject}.
- */
- public static boolean wasInjectedByHilt(@NonNull Fragment fragment) {
- return check(fragment);
- }
-
- /**
- * Returns true if the Service was injected by Hilt.
- *
- * @throws IllegalArgumentException if the given instance is not an AndroidEntryPoint nor is
- * annotated with {@link OptionalInject}.
- */
- public static boolean wasInjectedByHilt(@NonNull Service service) {
- return check(service);
- }
-
- /**
- * Returns true if the View was injected by Hilt.
- *
- * @throws IllegalArgumentException if the given instance is not an AndroidEntryPoint nor is
- * annotated with {@link OptionalInject}.
- */
- public static boolean wasInjectedByHilt(@NonNull View view) {
- return check(view);
- }
-
- private static boolean check(@NonNull Object obj) {
- Preconditions.checkNotNull(obj);
- Preconditions.checkArgument(
- obj instanceof InjectedByHilt,
- "'%s' is not an optionally injected android entry point. Check that you have annotated"
- + " the class with both @AndroidEntryPoint and @OptionalInject.",
- obj.getClass());
- return ((InjectedByHilt) obj).wasInjectedByHilt();
- }
-
- private OptionalInjectCheck() {}
-}
diff --git a/java/dagger/hilt/android/migration/package-info.java b/java/dagger/hilt/android/migration/package-info.java
deleted file mode 100644
index e37225a..0000000
--- a/java/dagger/hilt/android/migration/package-info.java
+++ /dev/null
@@ -1,25 +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.
- */
-
-/**
- * This package contains Android APIs to help migrating a codebase to Hilt.
- *
- * @see <a href="https://dagger.dev/hilt/migration">Migration to Hilt</a>
- */
-@ParametersAreNonnullByDefault
-package dagger.hilt.android.migration;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/java/dagger/hilt/android/package-info.java b/java/dagger/hilt/android/package-info.java
deleted file mode 100644
index 894f7ab..0000000
--- a/java/dagger/hilt/android/package-info.java
+++ /dev/null
@@ -1,28 +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.
- */
-
-/**
- * This package contains Hilt APIs for Android applications.
- *
- * <p>Hilt provides a standard way to incorporate Dagger dependency injection into an Android
- * application.
- *
- * @see <a href="https://dagger.dev/hilt">Hilt Developer Docs</a>
- */
-@ParametersAreNonnullByDefault
-package dagger.hilt.android;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/java/dagger/hilt/android/plugin/BUILD b/java/dagger/hilt/android/plugin/BUILD
deleted file mode 100644
index 7fd2c83..0000000
--- a/java/dagger/hilt/android/plugin/BUILD
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# A Gradle plugin that performs a transform.
-
-package(default_visibility = ["//:src"])
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(
- ["**/*"],
- # Exclude Gradle build folder to enable working along side Bazel
- exclude = ["**/build/**"],
- ),
-)
diff --git a/java/dagger/hilt/android/plugin/build.gradle b/java/dagger/hilt/android/plugin/build.gradle
deleted file mode 100644
index 274ecbe..0000000
--- a/java/dagger/hilt/android/plugin/build.gradle
+++ /dev/null
@@ -1,156 +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.
- */
-
-buildscript {
- repositories {
- google()
- jcenter()
- }
-}
-
-plugins {
- id 'org.jetbrains.kotlin.jvm' version '1.4.20'
- id 'java-gradle-plugin'
- id 'maven-publish'
-}
-
-repositories {
- google()
- jcenter()
-}
-
-configurations {
- additionalTestPlugin {
- canBeConsumed = false
- canBeResolved = true
- extendsFrom implementation
- }
-}
-
-dependencies {
- implementation gradleApi()
- compileOnly 'com.android.tools.build:gradle:4.2.0-beta04'
- // TODO(danysantiago): Make compileOnly to avoid dep for non-Kotlin projects.
- implementation 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.20'
- implementation 'org.javassist:javassist:3.26.0-GA'
- implementation 'org.ow2.asm:asm:9.0'
-
- testImplementation gradleTestKit()
- testImplementation 'junit:junit:4.12'
- testImplementation 'com.google.truth:truth:1.0.1'
- additionalTestPlugin 'com.android.tools.build:gradle:4.2.0-beta04'
-}
-
-// Configure the generating task of plugin-under-test-metadata.properties to
-// include additional dependencies for the injected plugin classpath that
-// are not present in the main runtime dependencies. This allows us to test
-// the desired AGP version while keeping a compileOnly dep on the main source.
-tasks.withType(PluginUnderTestMetadata.class).named("pluginUnderTestMetadata").configure {
- it.pluginClasspath.from(configurations.additionalTestPlugin)
-}
-
-compileKotlin {
- kotlinOptions {
- jvmTarget = "1.8"
- }
-}
-
-// Create sources Jar from main kotlin sources
-tasks.register("sourcesJar", Jar).configure {
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- description = "Assembles sources JAR"
- classifier = "sources"
- from(sourceSets["main"].allSource)
-}
-
-// Create javadoc Jar. The jar is empty since we don't really have docs
-// for this plugin but this is required to upload to Sonatype.
-// https://central.sonatype.org/pages/requirements.html#supply-javadoc-and-sources
-tasks.register("javadocJar", Jar).configure {
- group = JavaBasePlugin.DOCUMENTATION_GROUP
- description = "Assembles javadoc JAR"
- classifier = "javadoc"
-}
-
-// Disable Gradle metadata publication.
-tasks.withType(GenerateModuleMetadata) {
- enabled = false
-}
-
-// TODO(danysantiago): Use POM template in tools/ to avoid duplicating lines.
-publishing {
- publications {
- plugin(MavenPublication) {
- artifactId = 'hilt-android-gradle-plugin'
- def publishVersion = findProperty("PublishVersion")
- version = (publishVersion != null) ? publishVersion : "LOCAL-SNAPSHOT"
- from components.kotlin
- artifact(sourcesJar)
- artifact(javadocJar)
- pom {
- name = 'Hilt Android Gradle Plugin'
- description = 'A fast dependency injector for Android and Java.'
- url = 'https://github.com/google/dagger'
- scm {
- url = 'https://github.com/google/dagger/'
- connection = 'scm:git:git://github.com/google/dagger.git'
- developerConnection = 'scm:git:ssh://git@github.com/google/dagger.git'
- tag = 'HEAD'
- }
- issueManagement {
- system = 'GitHub Issues'
- url = 'https://github.com/google/dagger/issues'
- }
- licenses {
- license {
- name = 'Apache 2.0'
- url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
- }
- }
- organization {
- name = 'Google, Inc.'
- url = 'https://www.google.com'
- }
- withXml {
- def projectNode = asNode()
- // Adds:
- // <parent>
- // <groupId>org.sonatype.oss</groupId>
- // <artifactId>oss-parent</artifactId>
- // <version>7</version>
- // </parent>
- def parentNode = projectNode.appendNode('parent')
- parentNode.appendNode('groupId', 'org.sonatype.oss')
- parentNode.appendNode('artifactId', 'oss-parent')
- parentNode.appendNode('version', '7')
- // Adds scm->tag because for some reason the DSL API does not.
- // <scm>
- // <tag>HEAD</tag>
- // </scm>
- projectNode.get('scm').first().appendNode('tag', 'HEAD')
- }
- }
- }
- }
- // Publish to build output repository.
- repositories {
- maven {
- url = uri("$buildDir/repo")
- }
- }
-}
-
-group='com.google.dagger'
diff --git a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.jar b/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties b/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/java/dagger/hilt/android/plugin/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/java/dagger/hilt/android/plugin/gradlew b/java/dagger/hilt/android/plugin/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/java/dagger/hilt/android/plugin/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
deleted file mode 100644
index e066f48..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassTransformer.kt
+++ /dev/null
@@ -1,249 +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
- }
- 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) }
- return transformClassToOutput(clazz)
- }
-
- 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
- }
- 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/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
deleted file mode 100644
index 015bb76..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointClassVisitor.kt
+++ /dev/null
@@ -1,197 +0,0 @@
-package dagger.hilt.android.plugin
-
-import com.android.build.api.instrumentation.AsmClassVisitorFactory
-import com.android.build.api.instrumentation.ClassContext
-import com.android.build.api.instrumentation.ClassData
-import com.android.build.api.instrumentation.InstrumentationParameters
-import java.io.File
-import org.gradle.api.provider.Property
-import org.gradle.api.tasks.Input
-import org.objectweb.asm.ClassReader
-import org.objectweb.asm.ClassVisitor
-import org.objectweb.asm.FieldVisitor
-import org.objectweb.asm.MethodVisitor
-import org.objectweb.asm.Opcodes
-
-/**
- * ASM Adapter that transforms @AndroidEntryPoint-annotated classes to extend the Hilt
- * generated android class, including the @HiltAndroidApp application class.
- */
-@Suppress("UnstableApiUsage")
-class AndroidEntryPointClassVisitor(
- private val apiVersion: Int,
- nextClassVisitor: ClassVisitor,
- private val additionalClasses: File
-) : ClassVisitor(apiVersion, nextClassVisitor) {
-
- interface AndroidEntryPointParams : InstrumentationParameters {
- @get:Input
- val additionalClassesDir: Property<File>
- }
-
- abstract class Factory : AsmClassVisitorFactory<AndroidEntryPointParams> {
- override fun createClassVisitor(
- classContext: ClassContext,
- nextClassVisitor: ClassVisitor
- ): ClassVisitor {
- return AndroidEntryPointClassVisitor(
- apiVersion = instrumentationContext.apiVersion.get(),
- nextClassVisitor = nextClassVisitor,
- additionalClasses = parameters.get().additionalClassesDir.get()
- )
- }
-
- /**
- * Check if a class should be transformed.
- *
- * Only classes that are an Android entry point should be transformed.
- */
- override fun isInstrumentable(classData: ClassData) =
- classData.classAnnotations.any { ANDROID_ENTRY_POINT_ANNOTATIONS.contains(it) }
- }
-
- // The name of the Hilt generated superclass in it internal form.
- // e.g. "my/package/Hilt_MyActivity"
- lateinit var newSuperclassName: String
-
- lateinit var oldSuperclassName: String
-
- override fun visit(
- version: Int,
- access: Int,
- name: String,
- signature: String?,
- superName: String?,
- interfaces: Array<out String>?
- ) {
- val packageName = name.substringBeforeLast('/')
- val className = name.substringAfterLast('/')
- newSuperclassName =
- packageName + "/Hilt_" + className.replace("$", "_")
- oldSuperclassName = superName ?: error { "Superclass of $name is null!" }
- super.visit(version, access, name, signature, newSuperclassName, interfaces)
- }
-
- override fun visitMethod(
- access: Int,
- name: String,
- descriptor: String,
- signature: String?,
- exceptions: Array<out String>?
- ): MethodVisitor {
- val nextMethodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)
- val invokeSpecialVisitor = InvokeSpecialAdapter(apiVersion, nextMethodVisitor)
- if (name == ON_RECEIVE_METHOD_NAME &&
- descriptor == ON_RECEIVE_METHOD_DESCRIPTOR &&
- hasOnReceiveBytecodeInjectionMarker()
- ) {
- return OnReceiveAdapter(apiVersion, invokeSpecialVisitor)
- }
- return invokeSpecialVisitor
- }
-
- /**
- * Adapter for super calls (e.g. super.onCreate()) that rewrites the owner reference of the
- * invokespecial instruction to use 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
- */
- inner class InvokeSpecialAdapter(
- apiVersion: Int,
- nextClassVisitor: MethodVisitor
- ) : MethodVisitor(apiVersion, nextClassVisitor) {
- override fun visitMethodInsn(
- opcode: Int,
- owner: String,
- name: String,
- descriptor: String,
- isInterface: Boolean
- ) {
- if (opcode == Opcodes.INVOKESPECIAL && owner == oldSuperclassName) {
- // Update the owner of all INVOKESPECIAL instructions, including those found in
- // constructors.
- super.visitMethodInsn(opcode, newSuperclassName, name, descriptor, isInterface)
- } else {
- super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
- }
- }
- }
-
- /**
- * Method adapter for a BroadcastReceiver's onReceive method to insert a super call since with
- * its new superclass, onReceive will no longer be abstract (it is implemented by Hilt generated
- * receiver).
- */
- inner class OnReceiveAdapter(
- apiVersion: Int,
- nextClassVisitor: MethodVisitor
- ) : MethodVisitor(apiVersion, nextClassVisitor) {
- override fun visitCode() {
- super.visitCode()
- super.visitIntInsn(Opcodes.ALOAD, 0) // Load 'this'
- super.visitIntInsn(Opcodes.ALOAD, 1) // Load method param 1 (Context)
- super.visitIntInsn(Opcodes.ALOAD, 2) // Load method param 2 (Intent)
- super.visitMethodInsn(
- Opcodes.INVOKESPECIAL,
- newSuperclassName,
- ON_RECEIVE_METHOD_NAME,
- ON_RECEIVE_METHOD_DESCRIPTOR,
- false
- )
- }
- }
-
- /**
- * 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.
- */
- private fun hasOnReceiveBytecodeInjectionMarker() =
- findAdditionalClassFile(newSuperclassName).inputStream().use {
- var hasMarker = false
- ClassReader(it).accept(
- object : ClassVisitor(apiVersion) {
- override fun visitField(
- access: Int,
- name: String,
- descriptor: String,
- signature: String?,
- value: Any?
- ): FieldVisitor? {
- if (name == "onReceiveBytecodeInjectionMarker") {
- hasMarker = true
- }
- return null
- }
- },
- ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
- )
- return@use hasMarker
- }
-
- private fun findAdditionalClassFile(className: String) =
- File(additionalClasses, "$className.class")
-
- companion object {
- val ANDROID_ENTRY_POINT_ANNOTATIONS = setOf(
- "dagger.hilt.android.AndroidEntryPoint",
- "dagger.hilt.android.HiltAndroidApp"
- )
- const val ON_RECEIVE_METHOD_NAME = "onReceive"
- const val ON_RECEIVE_METHOD_DESCRIPTOR =
- "(Landroid/content/Context;Landroid/content/Intent;)V"
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
deleted file mode 100644
index 9bb5160..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/AndroidEntryPointTransform.kt
+++ /dev/null
@@ -1,174 +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 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/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
deleted file mode 100644
index 7a33836..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltExtension.kt
+++ /dev/null
@@ -1,50 +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
-
-/**
- * Configuration options for the Hilt Gradle Plugin
- */
-interface HiltExtension {
-
- /**
- * 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.
- *
- * 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.
- *
- * See https://github.com/google/dagger/issues/1991 for more context.
- */
- var enableExperimentalClasspathAggregation: Boolean
-
- /**
- * If set to `true`, Hilt will register a transform task that will rewrite `@AndroidEntryPoint`
- * 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.
- */
- var enableTransformForLocalTests: Boolean
-}
-
-internal open class HiltExtensionImpl : HiltExtension {
- override var enableExperimentalClasspathAggregation: Boolean = false
- override var enableTransformForLocalTests: Boolean = false
-}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
deleted file mode 100644
index e26edb5..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltGradlePlugin.kt
+++ /dev/null
@@ -1,298 +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 com.android.build.api.component.Component
-import com.android.build.api.extension.AndroidComponentsExtension
-import com.android.build.api.instrumentation.FramesComputationMode
-import com.android.build.api.instrumentation.InstrumentationScope
-import com.android.build.gradle.AppExtension
-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.api.BaseVariant
-import com.android.build.gradle.api.TestVariant
-import com.android.build.gradle.api.UnitTestVariant
-import dagger.hilt.android.plugin.util.CopyTransform
-import dagger.hilt.android.plugin.util.SimpleAGPVersion
-import java.io.File
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.component.ProjectComponentIdentifier
-import org.gradle.api.attributes.Attribute
-
-/**
- * A Gradle plugin that checks if the project is an Android project and if so, registers a
- * bytecode transformation.
- *
- * The plugin also passes an annotation processor option to disable superclass validation for
- * classes annotated with `@AndroidEntryPoint` since the registered transform by this plugin will
- * update the superclass.
- */
-class HiltGradlePlugin : Plugin<Project> {
- override fun apply(project: Project) {
- var configured = false
- project.plugins.withType(AndroidBasePlugin::class.java) {
- configured = true
- configureHilt(project)
- }
- project.afterEvaluate {
- check(configured) {
- // Check if configuration was applied, if not inform the developer they have applied the
- // plugin to a non-android project.
- "The Hilt Android Gradle plugin can only be applied to an Android project."
- }
- verifyDependencies(it)
- }
- }
-
- private fun configureHilt(project: Project) {
- val hiltExtension = project.extensions.create(
- HiltExtension::class.java, "hilt", HiltExtensionImpl::class.java
- )
- configureCompileClasspath(project, hiltExtension)
- if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(4, 2)) {
- // Configures bytecode transform using older APIs pre AGP 4.2
- configureTransform(project, hiltExtension)
- } else {
- // Configures bytecode transform using AGP 4.2 ASM pipeline.
- configureTransformASM(project, hiltExtension)
- }
- configureProcessorFlags(project)
- }
-
- private fun configureCompileClasspath(project: Project, hiltExtension: HiltExtension) {
- val androidExtension = project.extensions.findByType(BaseExtension::class.java)
- ?: throw error("Android BaseExtension not found.")
- when (androidExtension) {
- is AppExtension -> {
- // For an app project we configure the app variant and both androidTest and test variants,
- // Hilt components are generated in all of them.
- androidExtension.applicationVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- androidExtension.testVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- androidExtension.unitTestVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- }
- is LibraryExtension -> {
- // For a library project, only the androidTest and test variant are configured since
- // Hilt components are not generated in a library.
- androidExtension.testVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- androidExtension.unitTestVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- }
- is TestExtension -> {
- androidExtension.applicationVariants.all {
- configureVariantCompileClasspath(project, hiltExtension, androidExtension, it)
- }
- }
- else -> error(
- "Hilt plugin is unable to configure the compile classpath for project with extension " +
- "'$androidExtension'"
- )
- }
-
- project.dependencies.apply {
- registerTransform(CopyTransform::class.java) { spec ->
- // Java/Kotlin library projects offer an artifact of type 'jar'.
- spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "jar")
- // Android library projects (with or without Kotlin) offer an artifact of type
- // 'processed-jar', which AGP can offer as a jar.
- spec.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, "processed-jar")
- spec.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
- }
- }
- }
-
- private fun configureVariantCompileClasspath(
- project: Project,
- hiltExtension: HiltExtension,
- androidExtension: BaseExtension,
- variant: BaseVariant
- ) {
- if (!hiltExtension.enableExperimentalClasspathAggregation) {
- // Option is not enabled, don't configure compile classpath. Note that the option can't be
- // checked earlier (before iterating over the variants) since it would have been too early for
- // the value to be populated from the build file.
- return
- }
-
- if (androidExtension.lintOptions.isCheckReleaseBuilds &&
- SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(7, 0)
- ) {
- // Sadly we have to ask users to disable lint when enableExperimentalClasspathAggregation is
- // set to true and they are not in AGP 7.0+ since Lint will cause issues during the
- // configuration phase. See b/158753935 and b/160392650
- error(
- "Invalid Hilt plugin configuration: When 'enableExperimentalClasspathAggregation' is " +
- "enabled 'android.lintOptions.checkReleaseBuilds' has to be set to false unless " +
- "com.android.tools.build:gradle:7.0.0+ is used."
- )
- }
-
- if (
- listOf(
- "android.injected.build.model.only", // Sent by AS 1.0 only
- "android.injected.build.model.only.advanced", // Sent by AS 1.1+
- "android.injected.build.model.only.versioned", // Sent by AS 2.4+
- "android.injected.build.model.feature.full.dependencies", // Sent by AS 2.4+
- "android.injected.build.model.v2", // Sent by AS 4.2+
- ).any { project.properties.containsKey(it) }
- ) {
- // Do not configure compile classpath when AndroidStudio is building the model (syncing)
- // otherwise it will cause a freeze.
- return
- }
-
- val runtimeConfiguration = if (variant is TestVariant) {
- // For Android test variants, the tested runtime classpath is used since the test app has
- // tested dependencies removed.
- variant.testedVariant.runtimeConfiguration
- } else {
- variant.runtimeConfiguration
- }
- val artifactView = runtimeConfiguration.incoming.artifactView { view ->
- view.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, DAGGER_ARTIFACT_TYPE_VALUE)
- view.componentFilter { identifier ->
- // Filter out the project's classes from the aggregated view since this can cause
- // issues with Kotlin internal members visibility. b/178230629
- if (identifier is ProjectComponentIdentifier) {
- identifier.projectName != project.name
- } else {
- true
- }
- }
- }
-
- // CompileOnly config names don't follow the usual convention:
- // <Variant Name> -> <Config Name>
- // debug -> debugCompileOnly
- // debugAndroidTest -> androidTestDebugCompileOnly
- // debugUnitTest -> testDebugCompileOnly
- // release -> releaseCompileOnly
- // releaseUnitTest -> testReleaseCompileOnly
- val compileOnlyConfigName = when (variant) {
- is TestVariant ->
- "androidTest${variant.name.substringBeforeLast("AndroidTest").capitalize()}CompileOnly"
- is UnitTestVariant ->
- "test${variant.name.substringBeforeLast("UnitTest").capitalize()}CompileOnly"
- else ->
- "${variant.name}CompileOnly"
- }
- project.dependencies.add(compileOnlyConfigName, artifactView.files)
- }
-
- @Suppress("UnstableApiUsage")
- private fun configureTransformASM(project: Project, hiltExtension: HiltExtension) {
- var warnAboutLocalTestsFlag = false
- fun registerTransform(androidComponent: Component) {
- 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
- ) { params ->
- val classesDir =
- File(project.buildDir, "intermediates/javac/${androidComponent.name}/classes")
- params.additionalClassesDir.set(classesDir)
- }
- androidComponent.setAsmFramesComputationMode(
- FramesComputationMode.COMPUTE_FRAMES_FOR_INSTRUMENTED_METHODS
- )
- }
-
- val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
- androidComponents.onVariants { registerTransform(it) }
- androidComponents.androidTests { registerTransform(it) }
- androidComponents.unitTests { registerTransform(it) }
- }
-
- private fun configureTransform(project: Project, hiltExtension: HiltExtension) {
- val androidExtension = project.extensions.findByType(BaseExtension::class.java)
- ?: throw error("Android BaseExtension not found.")
- androidExtension.registerTransform(AndroidEntryPointTransform())
-
- // Create and configure a task for applying the transform for host-side unit tests. b/37076369
- val testedExtensions = project.extensions.findByType(TestedExtension::class.java)
- testedExtensions?.unitTestVariants?.all { unitTestVariant ->
- HiltTransformTestClassesTask.create(
- project = project,
- unitTestVariant = unitTestVariant,
- extension = hiltExtension
- )
- }
- }
-
- private fun configureProcessorFlags(project: Project) {
- val androidExtension = project.extensions.findByType(BaseExtension::class.java)
- ?: throw error("Android BaseExtension not found.")
- // Pass annotation processor flag to disable @AndroidEntryPoint superclass validation.
- androidExtension.defaultConfig.apply {
- javaCompileOptions.apply {
- annotationProcessorOptions.apply {
- PROCESSOR_OPTIONS.forEach { (key, value) -> argument(key, value) }
- }
- }
- }
- }
-
- private fun verifyDependencies(project: Project) {
- // If project is already failing, skip verification since dependencies might not be resolved.
- if (project.state.failure != null) {
- return
- }
- val dependencies = project.configurations.flatMap { configuration ->
- configuration.dependencies.map { dependency -> dependency.group to dependency.name }
- }
- if (!dependencies.contains(LIBRARY_GROUP to "hilt-android")) {
- error(missingDepError("$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"))
- }
- }
-
- companion object {
- val ARTIFACT_TYPE_ATTRIBUTE = Attribute.of("artifactType", String::class.java)
- const val DAGGER_ARTIFACT_TYPE_VALUE = "jar-for-dagger"
-
- const val LIBRARY_GROUP = "com.google.dagger"
- val PROCESSOR_OPTIONS = listOf(
- "dagger.fastInit" to "enabled",
- "dagger.hilt.android.internal.disableAndroidSuperclassValidation" to "true"
- )
- 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/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt
deleted file mode 100644
index 84b35b1..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/HiltTransformTestClassesTask.kt
+++ /dev/null
@@ -1,174 +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 com.android.build.gradle.api.UnitTestVariant
-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.compile.JavaCompile
-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
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-/**
- * Task that transform classes used by host-side unit tests. See b/37076369
- */
-@Suppress("UnstableApiUsage")
-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,
- unitTestVariant: 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.objects.fileCollection().from(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.
- @Suppress("UNCHECKED_CAST")
- val testCompileTaskProvider = project.tasks.named(
- "compile${unitTestVariant.name.capitalize()}JavaWithJavac"
- ) as TaskProvider<JavaCompile>
- 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) {
- @Suppress("UNCHECKED_CAST")
- val kotlinCompileTaskProvider = project.tasks.named(
- "compile${unitTestVariant.name.capitalize()}Kotlin"
- ) as TaskProvider<KotlinCompile>
- 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.objects.fileCollection().from(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/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
deleted file mode 100644
index 39a2d3a..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/CopyTransform.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package dagger.hilt.android.plugin.util
-
-import org.gradle.api.artifacts.transform.CacheableTransform
-import org.gradle.api.artifacts.transform.InputArtifact
-import org.gradle.api.artifacts.transform.TransformAction
-import org.gradle.api.artifacts.transform.TransformOutputs
-import org.gradle.api.artifacts.transform.TransformParameters
-import org.gradle.api.file.FileSystemLocation
-import org.gradle.api.provider.Provider
-import org.gradle.api.tasks.Classpath
-
-// A transform that registers the input jar file as an output and thus changing from one artifact
-// type to another.
-// TODO: Improve to only copy classes that need to be visible by Hilt & Dagger.
-@CacheableTransform
-abstract class CopyTransform : TransformAction<TransformParameters.None> {
- @get:Classpath
- @get:InputArtifact
- abstract val inputArtifactProvider: Provider<FileSystemLocation>
-
- override fun transform(outputs: TransformOutputs) {
- val input = inputArtifactProvider.get().asFile
- when {
- input.isDirectory -> outputs.dir(input)
- input.isFile -> outputs.file(input)
- else -> error("File/directory does not exist: ${input.absolutePath}")
- }
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
deleted file mode 100644
index e5a101e..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/Files.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package dagger.hilt.android.plugin.util
-
-import com.android.SdkConstants
-import java.io.File
-import java.util.zip.ZipEntry
-
-/* Checks if a file is a .class file. */
-fun File.isClassFile() = this.isFile && this.extension == SdkConstants.EXT_CLASS
-
-/* Checks if a Zip entry is a .class file. */
-fun ZipEntry.isClassFile() = !this.isDirectory && this.name.endsWith(SdkConstants.DOT_CLASS)
-
-/* CHecks if a file is a .jar file. */
-fun File.isJarFile() = this.isFile && this.extension == SdkConstants.EXT_JAR
diff --git a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt b/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
deleted file mode 100644
index 1580431..0000000
--- a/java/dagger/hilt/android/plugin/src/main/kotlin/dagger/hilt/android/plugin/util/SimpleAGPVersion.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package dagger.hilt.android.plugin.util
-
-import com.android.Version
-
-/**
- * Simple Android Gradle Plugin version class since there is no public API one. b/175816217
- */
-internal data class SimpleAGPVersion(
- val major: Int,
- val minor: Int,
-) : Comparable<SimpleAGPVersion> {
-
- override fun compareTo(other: SimpleAGPVersion): Int {
- return compareValuesBy(
- this,
- other,
- compareBy(SimpleAGPVersion::major).thenBy(SimpleAGPVersion::minor)
- ) { it }
- }
-
- companion object {
-
- val ANDROID_GRADLE_PLUGIN_VERSION by lazy { parse(Version.ANDROID_GRADLE_PLUGIN_VERSION) }
-
- fun parse(version: String?) =
- tryParse(version) ?: error("Unable to parse AGP version: $version")
-
- private fun tryParse(version: String?): SimpleAGPVersion? {
- if (version == null) {
- return null
- }
-
- val parts = version.split('.')
- if (parts.size == 1) {
- return SimpleAGPVersion(parts[0].toInt(), 0)
- }
-
- return SimpleAGPVersion(parts[0].toInt(), parts[1].toInt())
- }
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/dagger.hilt.android.plugin.properties b/java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/dagger.hilt.android.plugin.properties
deleted file mode 100644
index 5d2b9df..0000000
--- a/java/dagger/hilt/android/plugin/src/main/resources/META-INF/gradle-plugins/dagger.hilt.android.plugin.properties
+++ /dev/null
@@ -1 +0,0 @@
-implementation-class=dagger.hilt.android.plugin.HiltGradlePlugin
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/build.gradle
deleted file mode 100644
index e2d2a7b..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/build.gradle
+++ /dev/null
@@ -1,28 +0,0 @@
-plugins {
- id 'com.android.library'
- id 'dagger.hilt.android.plugin'
-}
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 21
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
-}
-
-dependencies {
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- implementation project(':libraryB')
- implementation project(':libraryC')
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/src/main/AndroidManifest.xml b/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/src/main/AndroidManifest.xml
deleted file mode 100644
index e704d4a..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="liba">
-</manifest>
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/src/main/java/liba/LibraryA.java b/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/src/main/java/liba/LibraryA.java
deleted file mode 100644
index 95e9356..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/android-libraryA/src/main/java/liba/LibraryA.java
+++ /dev/null
@@ -1,27 +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 liba;
-
-import javax.inject.Inject;
-import libb.LibraryB;
-import libc.LibraryC;
-
-/** Test LibA */
-public class LibraryA {
- @Inject
- public LibraryA(LibraryB b, LibraryC c) {}
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/build.gradle
deleted file mode 100644
index 3031528..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/build.gradle
+++ /dev/null
@@ -1,25 +0,0 @@
-plugins {
- id 'com.android.library'
- id 'dagger.hilt.android.plugin'
-}
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 21
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
-}
-
-dependencies {
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/src/main/AndroidManifest.xml b/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/src/main/AndroidManifest.xml
deleted file mode 100644
index a4967e3..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="libc">
-</manifest>
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/src/main/java/libc/LibraryC.java b/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/src/main/java/libc/LibraryC.java
deleted file mode 100644
index f7397fc..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/android-libraryC/src/main/java/libc/LibraryC.java
+++ /dev/null
@@ -1,25 +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 libc;
-
-import javax.inject.Inject;
-
-/** Test LibC */
-public class LibraryC {
- @Inject
- public LibraryC() {}
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/java-libraryA/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/java-libraryA/build.gradle
deleted file mode 100644
index dde8858..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/java-libraryA/build.gradle
+++ /dev/null
@@ -1,15 +0,0 @@
-plugins {
- id 'java-library'
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
-}
-
-dependencies {
- implementation 'com.google.dagger:hilt-core:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- implementation project(':libraryB')
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/java-libraryA/src/main/java/liba/LibraryA.java b/java/dagger/hilt/android/plugin/src/test/data/java-libraryA/src/main/java/liba/LibraryA.java
deleted file mode 100644
index afc0da2..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/java-libraryA/src/main/java/liba/LibraryA.java
+++ /dev/null
@@ -1,26 +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 liba;
-
-import javax.inject.Inject;
-import libb.LibraryBProvided;
-
-/** Test LibA */
-public class LibraryA {
- @Inject
- public LibraryA(LibraryBProvided b) {}
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/build.gradle b/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/build.gradle
deleted file mode 100644
index 55780cc..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/build.gradle
+++ /dev/null
@@ -1,13 +0,0 @@
-plugins {
- id 'java-library'
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
-}
-
-dependencies {
- implementation 'com.google.dagger:hilt-core:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-}
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryB.java b/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryB.java
deleted file mode 100644
index 285d5ba..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryB.java
+++ /dev/null
@@ -1,25 +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 libb;
-
-import javax.inject.Inject;
-
-/** Test LibB */
-public class LibraryB {
- @Inject
- public LibraryB() {}
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryBModule.java b/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryBModule.java
deleted file mode 100644
index d1c08f0..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryBModule.java
+++ /dev/null
@@ -1,32 +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 libb;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-
-/** Test LibB Module */
-@Module
-@InstallIn(SingletonComponent.class)
-public final class LibraryBModule {
- @Provides
- public static LibraryBProvided provideB() {
- return new LibraryBProvided();
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryBProvided.java b/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryBProvided.java
deleted file mode 100644
index b472bfb..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/java-libraryB/src/main/java/libb/LibraryBProvided.java
+++ /dev/null
@@ -1,20 +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 libb;
-
-/** Test LibB Provided */
-public class LibraryBProvided {}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/gradle.properties b/java/dagger/hilt/android/plugin/src/test/data/simple-project/gradle.properties
deleted file mode 100644
index 5bac8ac..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-android.useAndroidX=true
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/AndroidManifest.xml b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/AndroidManifest.xml
deleted file mode 100644
index 29060e0..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="simple">
-</manifest>
\ No newline at end of file
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java
deleted file mode 100644
index a6e5d93..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity1.java
+++ /dev/null
@@ -1,29 +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 simple;
-
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import javax.inject.Inject;
-
-/** Just an activity. */
-@AndroidEntryPoint(AppCompatActivity.class)
-public class Activity1 extends Hilt_Activity1 {
- @Inject String data;
-
- // Insert-change
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java
deleted file mode 100644
index f7793be..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Activity2.java
+++ /dev/null
@@ -1,29 +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 simple;
-
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import javax.inject.Inject;
-
-/** Just an activity. */
-@AndroidEntryPoint(AppCompatActivity.class)
-public class Activity2 extends Hilt_Activity2 {
- @Inject String data;
-
- // Insert-change
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Module1.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Module1.java
deleted file mode 100644
index d3297c3..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Module1.java
+++ /dev/null
@@ -1,36 +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 simple;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-
-/** Just a module. */
-@Module
-@InstallIn(ActivityComponent.class)
-public class Module1 {
-
- @Provides
- static String provideData() {
- return "010101";
- }
-
- // Insert-change
-
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Module2.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Module2.java
deleted file mode 100644
index dd23236..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/Module2.java
+++ /dev/null
@@ -1,36 +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 simple;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-
-/** Just a module. */
-@Module
-@InstallIn(ActivityComponent.class)
-public class Module2 {
-
- @Provides
- static int provideData() {
- return 0x010101;
- }
-
- // Insert-change
-
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java b/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java
deleted file mode 100644
index 5a92241..0000000
--- a/java/dagger/hilt/android/plugin/src/test/data/simple-project/src/main/java/simple/SimpleApp.java
+++ /dev/null
@@ -1,26 +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 simple;
-
-import android.app.Application;
-import dagger.hilt.android.HiltAndroidApp;
-
-/** Just an application. */
-@HiltAndroidApp(Application.class)
-public class SimpleApp extends Hilt_SimpleApp {
- // Insert-change
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt
deleted file mode 100644
index 6141250..0000000
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/CompileClasspathTest.kt
+++ /dev/null
@@ -1,111 +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.
- */
-
-import java.io.File
-import org.gradle.testkit.runner.TaskOutcome
-import org.junit.Assert.assertEquals
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-
-class CompileClasspathTest {
- @get:Rule
- val testProjectDir = TemporaryFolder()
-
- lateinit var gradleRunner: GradleTestRunner
-
- @Before
- fun setup() {
- gradleRunner = GradleTestRunner(testProjectDir)
- gradleRunner.addAndroidOption(
- "lintOptions.checkReleaseBuilds = false"
- )
- gradleRunner.addHiltOption(
- "enableExperimentalClasspathAggregation = 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'",
- "implementation project(':libraryA')",
- )
- gradleRunner.addSrc(
- srcPath = "minimal/MyApp.java",
- srcContent =
- """
- package minimal;
-
- import android.app.Application;
- import liba.LibraryA;
-
- @dagger.hilt.android.HiltAndroidApp
- public class MyApp extends Application {
- @javax.inject.Inject
- LibraryA libraryA;
- }
- """.trimIndent()
- )
- gradleRunner.setAppClassName(".MyApp")
- }
-
- // Verifies that library B and library C injected classes are available in the root classpath.
- @Test
- fun test_injectClasses() {
- File("src/test/data/android-libraryA")
- .copyRecursively(File(testProjectDir.root, "libraryA"))
- File("src/test/data/java-libraryB")
- .copyRecursively(File(testProjectDir.root, "libraryB"))
- File("src/test/data/android-libraryC")
- .copyRecursively(File(testProjectDir.root, "libraryC"))
-
- testProjectDir.newFile("settings.gradle").apply {
- writeText(
- """
- include ':libraryA'
- include ':libraryB'
- include ':libraryC'
- """.trimIndent()
- )
- }
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(":assembleDebug")
- assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
- }
-
- // Verifies that library B Hilt module is available in the root classpath.
- @Test
- fun test_injectClassesFromModules() {
- File("src/test/data/java-libraryA")
- .copyRecursively(File(testProjectDir.root, "libraryA"))
- File("src/test/data/java-libraryB")
- .copyRecursively(File(testProjectDir.root, "libraryB"))
-
- testProjectDir.newFile("settings.gradle").apply {
- writeText(
- """
- include ':libraryA'
- include ':libraryB'
- """.trimIndent()
- )
- }
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(":assembleDebug")
- assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt
deleted file mode 100644
index 2d58766..0000000
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/GradleTestRunner.kt
+++ /dev/null
@@ -1,214 +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.
- */
-
-import java.io.File
-import org.gradle.testkit.runner.BuildResult
-import org.gradle.testkit.runner.GradleRunner
-import org.junit.rules.TemporaryFolder
-
-/**
- * Testing utility class that sets up a simple Android project that applies the Hilt plugin.
- */
-class GradleTestRunner(val tempFolder: TemporaryFolder) {
- private val dependencies = mutableListOf<String>()
- private val activities = mutableListOf<String>()
- private val additionalAndroidOptions = mutableListOf<String>()
- private val hiltOptions = mutableListOf<String>()
- private var appClassName: String? = null
- private var buildFile: File? = null
- private var gradlePropertiesFile: File? = null
- private var manifestFile: File? = null
-
- init {
- tempFolder.newFolder("src", "main", "java", "minimal")
- tempFolder.newFolder("src", "main", "res")
- }
-
- // Adds project dependencies, e.g. "implementation <group>:<id>:<version>"
- fun addDependencies(vararg deps: String) {
- dependencies.addAll(deps)
- }
-
- // Adds an <activity> tag in the project's Android Manifest, e.g. "<activity name=".Foo"/>
- fun addActivities(vararg activityElements: String) {
- activities.addAll(activityElements)
- }
-
- // Adds 'android' options to the project's build.gradle, e.g. "lintOptions.checkReleaseBuilds = false"
- fun addAndroidOption(vararg options: String) {
- additionalAndroidOptions.addAll(options)
- }
-
- // Adds 'hilt' options to the project's build.gradle, e.g. "enableExperimentalClasspathAggregation = true"
- fun addHiltOption(vararg options: String) {
- hiltOptions.addAll(options)
- }
-
- // 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()
- }
-
- // Adds a source file to the project. The source path is relative to 'src/main/java'.
- fun addSrc(srcPath: String, srcContent: String): File {
- File(tempFolder.root, "src/main/java/${srcPath.substringBeforeLast(File.separator)}").mkdirs()
- return tempFolder.newFile("/src/main/java/$srcPath").apply { writeText(srcContent) }
- }
-
- // Adds a resource file to the project. The source path is relative to 'src/main/res'.
- fun addRes(resPath: String, resContent: String): File {
- File(tempFolder.root, "src/main/res/${resPath.substringBeforeLast(File.separator)}").mkdirs()
- return tempFolder.newFile("/src/main/res/$resPath").apply { writeText(resContent) }
- }
-
- fun setAppClassName(name: String) {
- appClassName = name
- }
-
- // Executes a Gradle builds and expects it to succeed.
- fun build(): Result {
- setupFiles()
- return Result(tempFolder.root, createRunner().build())
- }
-
- // Executes a Gradle build and expects it to fail.
- fun buildAndFail(): Result {
- setupFiles()
- return Result(tempFolder.root, createRunner().buildAndFail())
- }
-
- private fun setupFiles() {
- writeBuildFile()
- writeGradleProperties()
- writeAndroidManifest()
- }
-
- private fun writeBuildFile() {
- buildFile?.delete()
- buildFile = tempFolder.newFile("build.gradle").apply {
- writeText(
- """
- buildscript {
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:4.2.0-beta04'
- }
- }
-
- plugins {
- id 'com.android.application'
- id 'dagger.hilt.android.plugin'
- }
-
- android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "plugin.test"
- minSdkVersion 21
- targetSdkVersion 30
- }
-
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- ${additionalAndroidOptions.joinToString(separator = "\n")}
- }
-
- allprojects {
- repositories {
- mavenLocal()
- google()
- jcenter()
- }
- }
-
- dependencies {
- ${dependencies.joinToString(separator = "\n")}
- }
-
- hilt {
- ${hiltOptions.joinToString(separator = "\n")}
- }
- """.trimIndent()
- )
- }
- }
-
- private fun writeGradleProperties() {
- gradlePropertiesFile?.delete()
- gradlePropertiesFile = tempFolder.newFile("gradle.properties").apply {
- writeText(
- """
- android.useAndroidX=true
- """.trimIndent()
- )
- }
- }
-
- private fun writeAndroidManifest() {
- manifestFile?.delete()
- manifestFile = tempFolder.newFile("/src/main/AndroidManifest.xml").apply {
- writeText(
- """
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="minimal">
- <application
- android:name="${appClassName ?: "android.app.Application"}"
- android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
- ${activities.joinToString(separator = "\n")}
- </application>
- </manifest>
- """.trimIndent()
- )
- }
- }
-
- private fun createRunner() = GradleRunner.create()
- .withProjectDir(tempFolder.root)
- .withArguments("assembleDebug", "--stacktrace")
- .withPluginClasspath()
-// .withDebug(true) // Add this line to enable attaching a debugger to the gradle test invocation
- .forwardOutput()
-
- // Data class representing a Gradle Test run result.
- data class Result(
- private val projectRoot: File,
- private val buildResult: BuildResult
- ) {
- // Finds a task by name.
- fun getTask(name: String) = buildResult.task(name) ?: error("Task '$name' not found.")
-
- // Gets the full build output.
- fun getOutput() = buildResult.output
-
- // Finds a transformed file. The srcFilePath is relative to the app's package.
- fun getTransformedFile(srcFilePath: String): File {
- val parentDir =
- File(projectRoot, "build/intermediates/asm_instrumented_project_classes/debug")
- return File(parentDir, srcFilePath).also {
- if (!it.exists()) {
- error("Unable to find transformed class ${it.path}")
- }
- }
- }
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/HiltGradlePluginTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/HiltGradlePluginTest.kt
deleted file mode 100644
index f256985..0000000
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/HiltGradlePluginTest.kt
+++ /dev/null
@@ -1,68 +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.
- */
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-
-/**
- * Functional test of the plugin
- *
- * To run these tests first deploy artifacts to local maven via util/install-local-snapshot.sh.
- */
-class HiltGradlePluginTest {
-
- @get:Rule
- val testProjectDir = TemporaryFolder()
-
- lateinit var gradleRunner: GradleTestRunner
-
- @Before
- fun setup() {
- gradleRunner = GradleTestRunner(testProjectDir)
- }
-
- // Verify plugin configuration fails when runtime dependency is missing but plugin is applied.
- @Test
- fun test_missingLibraryDep() {
- gradleRunner.addDependencies(
- "implementation 'androidx.appcompat:appcompat:1.1.0'"
- )
-
- val result = gradleRunner.buildAndFail()
- assertThat(result.getOutput()).contains(
- "The Hilt Android Gradle plugin is applied but no " +
- "com.google.dagger:hilt-android dependency was found."
- )
- }
-
- // Verify plugin configuration fails when compiler dependency is missing but plugin is applied.
- @Test
- fun test_missingCompilerDep() {
- gradleRunner.addDependencies(
- "implementation 'androidx.appcompat:appcompat:1.1.0'",
- "implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'"
- )
-
- val result = gradleRunner.buildAndFail()
- assertThat(result.getOutput()).contains(
- "The Hilt Android Gradle plugin is applied but no " +
- "com.google.dagger:hilt-compiler dependency was found."
- )
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt
deleted file mode 100644
index a003ab5..0000000
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/IncrementalProcessorTest.kt
+++ /dev/null
@@ -1,615 +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.
- */
-
-import com.google.common.truth.Expect
-import java.io.File
-import org.gradle.testkit.runner.BuildResult
-import org.gradle.testkit.runner.GradleRunner
-import org.gradle.testkit.runner.TaskOutcome
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-
-/**
- * Tests to verify Gradle annotation processor incremental compilation.
- *
- * To run these tests first deploy artifacts to local maven via util/install-local-snapshot.sh.
- */
-class IncrementalProcessorTest {
-
- @get:Rule
- val testProjectDir = TemporaryFolder()
-
- @get:Rule
- val expect: Expect = Expect.create()
-
- // Original source files
- private lateinit var srcApp: File
- private lateinit var srcActivity1: File
- private lateinit var srcActivity2: File
- private lateinit var srcModule1: File
- private lateinit var srcModule2: File
-
- // Generated source files
- private lateinit var genHiltApp: File
- private lateinit var genHiltActivity1: File
- private lateinit var genHiltActivity2: File
- private lateinit var genAppInjector: File
- private lateinit var genActivityInjector1: File
- private lateinit var genActivityInjector2: File
- private lateinit var genAppInjectorDeps: File
- private lateinit var genActivityInjectorDeps1: File
- private lateinit var genActivityInjectorDeps2: File
- private lateinit var genModuleDeps1: File
- private lateinit var genModuleDeps2: File
- private lateinit var genHiltComponents: File
- private lateinit var genDaggerHiltApplicationComponent: File
-
- // Compiled classes
- private lateinit var classSrcApp: File
- private lateinit var classSrcActivity1: File
- private lateinit var classSrcActivity2: File
- private lateinit var classSrcModule1: File
- private lateinit var classSrcModule2: File
- private lateinit var classGenHiltApp: File
- private lateinit var classGenHiltActivity1: File
- private lateinit var classGenHiltActivity2: File
- private lateinit var classGenAppInjector: File
- private lateinit var classGenActivityInjector1: File
- private lateinit var classGenActivityInjector2: File
- private lateinit var classGenAppInjectorDeps: File
- private lateinit var classGenActivityInjectorDeps1: File
- private lateinit var classGenActivityInjectorDeps2: File
- private lateinit var classGenModuleDeps1: File
- private lateinit var classGenModuleDeps2: File
- private lateinit var classGenHiltComponents: File
- private lateinit var classGenDaggerHiltApplicationComponent: File
-
- // Timestamps of files
- private lateinit var fileToTimestampMap: Map<File, Long>
-
- // Sets of files that have changed/not changed/deleted
- private lateinit var changedFiles: Set<File>
- private lateinit var unchangedFiles: Set<File>
- private lateinit var deletedFiles: Set<File>
-
- @Before
- fun setup() {
- val projectRoot = testProjectDir.root
- // copy test project
- File("src/test/data/simple-project").copyRecursively(projectRoot)
-
- // set up build file
- File(projectRoot, "build.gradle").writeText(
- """
- buildscript {
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.5.3'
- }
- }
-
- plugins {
- id 'com.android.application'
- }
-
- android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "hilt.simple"
- minSdkVersion 21
- targetSdkVersion 30
- }
-
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- }
-
- repositories {
- mavenLocal()
- google()
- jcenter()
- }
-
- dependencies {
- implementation 'androidx.appcompat:appcompat:1.1.0'
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
- }
- """.trimIndent()
- )
-
- // Compute file paths
- srcApp = File(projectRoot, "$SRC_DIR/simple/SimpleApp.java")
- srcActivity1 = File(projectRoot, "$SRC_DIR/simple/Activity1.java")
- srcActivity2 = File(projectRoot, "$SRC_DIR/simple/Activity2.java")
- srcModule1 = File(projectRoot, "$SRC_DIR/simple/Module1.java")
- srcModule2 = File(projectRoot, "$SRC_DIR/simple/Module2.java")
-
- genHiltApp = File(projectRoot, "$GEN_SRC_DIR/simple/Hilt_SimpleApp.java")
- genHiltActivity1 = File(projectRoot, "$GEN_SRC_DIR/simple/Hilt_Activity1.java")
- genHiltActivity2 = File(projectRoot, "$GEN_SRC_DIR/simple/Hilt_Activity2.java")
- genAppInjector = File(projectRoot, "$GEN_SRC_DIR/simple/SimpleApp_GeneratedInjector.java")
- genActivityInjector1 = File(projectRoot, "$GEN_SRC_DIR/simple/Activity1_GeneratedInjector.java")
- genActivityInjector2 = File(projectRoot, "$GEN_SRC_DIR/simple/Activity2_GeneratedInjector.java")
- genAppInjectorDeps = File(
- projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/simple_SimpleApp_GeneratedInjectorModuleDeps.java"
- )
- genActivityInjectorDeps1 = File(
- projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/simple_Activity1_GeneratedInjectorModuleDeps.java"
- )
- genActivityInjectorDeps2 = File(
- projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/simple_Activity2_GeneratedInjectorModuleDeps.java"
- )
- genModuleDeps1 = File(
- projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/simple_Module1ModuleDeps.java"
- )
- genModuleDeps2 = File(
- projectRoot,
- "$GEN_SRC_DIR/hilt_aggregated_deps/simple_Module2ModuleDeps.java"
- )
- genHiltComponents = File(
- projectRoot,
- "$GEN_SRC_DIR/simple/SimpleApp_HiltComponents.java"
- )
- genDaggerHiltApplicationComponent = File(
- projectRoot,
- "$GEN_SRC_DIR/simple/DaggerSimpleApp_HiltComponents_SingletonC.java"
- )
-
- classSrcApp = File(projectRoot, "$CLASS_DIR/simple/SimpleApp.class")
- classSrcActivity1 = File(projectRoot, "$CLASS_DIR/simple/Activity1.class")
- classSrcActivity2 = File(projectRoot, "$CLASS_DIR/simple/Activity2.class")
- classSrcModule1 = File(projectRoot, "$CLASS_DIR/simple/Module1.class")
- classSrcModule2 = File(projectRoot, "$CLASS_DIR/simple/Module2.class")
- classGenHiltApp = File(projectRoot, "$CLASS_DIR/simple/Hilt_SimpleApp.class")
- classGenHiltActivity1 = File(projectRoot, "$CLASS_DIR/simple/Hilt_Activity1.class")
- classGenHiltActivity2 = File(projectRoot, "$CLASS_DIR/simple/Hilt_Activity2.class")
- classGenAppInjector = File(projectRoot, "$CLASS_DIR/simple/SimpleApp_GeneratedInjector.class")
- classGenActivityInjector1 = File(
- projectRoot,
- "$CLASS_DIR/simple/Activity1_GeneratedInjector.class"
- )
- classGenActivityInjector2 = File(
- projectRoot,
- "$CLASS_DIR/simple/Activity2_GeneratedInjector.class"
- )
- classGenAppInjectorDeps = File(
- projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/simple_SimpleApp_GeneratedInjectorModuleDeps.class"
- )
- classGenActivityInjectorDeps1 = File(
- projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/simple_Activity1_GeneratedInjectorModuleDeps.class"
- )
- classGenActivityInjectorDeps2 = File(
- projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/simple_Activity2_GeneratedInjectorModuleDeps.class"
- )
- classGenModuleDeps1 = File(
- projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/simple_Module1ModuleDeps.class"
- )
- classGenModuleDeps2 = File(
- projectRoot,
- "$CLASS_DIR/hilt_aggregated_deps/simple_Module2ModuleDeps.class"
- )
- classGenHiltComponents = File(
- projectRoot,
- "$CLASS_DIR/simple/SimpleApp_HiltComponents.class"
- )
- classGenDaggerHiltApplicationComponent = File(
- projectRoot,
- "$CLASS_DIR/simple/DaggerSimpleApp_HiltComponents_SingletonC.class"
- )
- }
-
- @Test
- fun firstFullBuild() {
- // This test verifies the results of the first full (non-incremental) build. The other tests
- // verify the results of the second incremental build based on different change scenarios.
- val result = runFullBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
-
- // Check annotation processing outputs
- assertFilesExist(
- genHiltApp,
- genHiltActivity1,
- genHiltActivity2,
- genAppInjector,
- genActivityInjector1,
- genActivityInjector2,
- genAppInjectorDeps,
- genActivityInjectorDeps1,
- genActivityInjectorDeps2,
- genModuleDeps1,
- genModuleDeps2,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
-
- // Check compilation outputs
- assertFilesExist(
- classSrcApp,
- classSrcActivity1,
- classSrcActivity2,
- classSrcModule1,
- classSrcModule2,
- classGenHiltApp,
- classGenHiltActivity1,
- classGenHiltActivity2,
- classGenAppInjector,
- classGenActivityInjector1,
- classGenActivityInjector2,
- classGenAppInjectorDeps,
- classGenActivityInjectorDeps1,
- classGenActivityInjectorDeps2,
- classGenModuleDeps1,
- classGenModuleDeps2,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
- }
-
- @Test
- fun changeActivitySource() {
- runFullBuild()
-
- // Change Activity 1 source
- searchAndReplace(
- srcActivity1, "// Insert-change",
- """
- @Override
- public void onResume() {
- super.onResume();
- }
- """.trimIndent()
- )
-
- val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
-
- // Check annotation processing outputs
- // * Only activity 1 sources are re-generated, isolation in modules and from other activities
- // * Root classes along with components are always re-generated (aggregated processor)
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genHiltActivity1,
- genAppInjector,
- genActivityInjector1,
- genAppInjectorDeps,
- genActivityInjectorDeps1,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
-
- // Check compilation outputs
- // * Gen sources from activity 1 are re-compiled
- // * All aggregating processor gen sources are re-compiled
- assertChangedFiles(
- FileType.CLASS,
- classSrcActivity1,
- classGenHiltApp,
- classGenHiltActivity1,
- classGenAppInjector,
- classGenActivityInjector1,
- classGenAppInjectorDeps,
- classGenActivityInjectorDeps1,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
- }
-
- @Test
- fun changeModuleSource() {
- runFullBuild()
-
- // Change Module 1 source
- searchAndReplace(
- srcModule1, "// Insert-change",
- """
- @Provides
- static double provideDouble() {
- return 10.10;
- }
- """.trimIndent()
- )
-
- val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
-
- // Check annotation processing outputs
- // * Only module 1 sources are re-generated, isolation from other modules
- // * Root classes along with components are always re-generated (aggregated processor)
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genModuleDeps1,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
-
- // Check compilation outputs
- // * Gen sources from module 1 are re-compiled
- // * All aggregating processor gen sources are re-compiled
- assertChangedFiles(
- FileType.CLASS,
- classSrcModule1,
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenModuleDeps1,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
- }
-
- @Test
- fun changeAppSource() {
- runFullBuild()
-
- // Change Application source
- searchAndReplace(
- srcApp, "// Insert-change",
- """
- @Override
- public void onCreate() {
- super.onCreate();
- }
- """.trimIndent()
- )
-
- val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
-
- // Check annotation processing outputs
- // * No modules or activities (or any other non-root) classes should be generated
- // * Root classes along with components are always re-generated (aggregated processor)
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
-
- // Check compilation outputs
- // * All aggregating processor gen sources are re-compiled
- assertChangedFiles(
- FileType.CLASS,
- classSrcApp, // re-compiles because superclass re-compiled
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
- }
-
- @Test
- fun deleteActivitySource() {
- runFullBuild()
-
- srcActivity2.delete()
-
- val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
-
- // Check annotation processing outputs
- // * All related gen classes from activity 2 should be deleted
- // * Unrelated activities and modules are in isolation and should be unchanged
- // * Root classes along with components are always re-generated (aggregated processor)
- assertDeletedFiles(
- genHiltActivity2,
- genActivityInjector2,
- genActivityInjectorDeps2
- )
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
-
- // Check compilation outputs
- // * All compiled classes from activity 2 should be deleted
- // * Unrelated activities and modules are in isolation and should be unchanged
- assertDeletedFiles(
- classSrcActivity2,
- classGenHiltActivity2,
- classGenActivityInjector2,
- classGenActivityInjectorDeps2
- )
- assertChangedFiles(
- FileType.CLASS,
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
- }
-
- @Test
- fun deleteModuleSource() {
- runFullBuild()
-
- srcModule2.delete()
-
- val result = runIncrementalBuild()
- expect.that(result.task(COMPILE_TASK)!!.outcome).isEqualTo(TaskOutcome.SUCCESS)
-
- // Check annotation processing outputs
- // * All related gen classes from module 2 should be deleted
- // * Unrelated activities and modules are in isolation and should be unchanged
- // * Root classes along with components are always re-generated (aggregated processor)
- assertDeletedFiles(
- genModuleDeps2
- )
- assertChangedFiles(
- FileType.JAVA,
- genHiltApp,
- genAppInjector,
- genAppInjectorDeps,
- genHiltComponents,
- genDaggerHiltApplicationComponent
- )
-
- // Check compilation outputs
- // * All compiled classes from module 2 should be deleted
- // * Unrelated activities and modules are in isolation and should be unchanged
- assertDeletedFiles(
- classSrcModule2,
- classGenModuleDeps2
- )
- assertChangedFiles(
- FileType.CLASS,
- classGenHiltApp,
- classGenAppInjector,
- classGenAppInjectorDeps,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
- }
-
- private fun runGradleTasks(vararg args: String): BuildResult {
- return GradleRunner.create()
- .withProjectDir(testProjectDir.root)
- .withArguments(*args)
- .withPluginClasspath()
- .forwardOutput()
- .build()
- }
-
- private fun runFullBuild(): BuildResult {
- val result = runGradleTasks(CLEAN_TASK, COMPILE_TASK)
- recordTimestamps()
- return result
- }
-
- private fun runIncrementalBuild(): BuildResult {
- val result = runGradleTasks(COMPILE_TASK)
- recordFileChanges()
- return result
- }
- private fun recordTimestamps() {
- val files = listOf(
- genHiltApp,
- genHiltActivity1,
- genHiltActivity2,
- genAppInjector,
- genActivityInjector1,
- genActivityInjector2,
- genAppInjectorDeps,
- genActivityInjectorDeps1,
- genActivityInjectorDeps2,
- genModuleDeps1,
- genModuleDeps2,
- genHiltComponents,
- genDaggerHiltApplicationComponent,
- classSrcApp,
- classSrcActivity1,
- classSrcActivity2,
- classSrcModule1,
- classSrcModule2,
- classGenHiltApp,
- classGenHiltActivity1,
- classGenHiltActivity2,
- classGenAppInjector,
- classGenActivityInjector1,
- classGenActivityInjector2,
- classGenAppInjectorDeps,
- classGenActivityInjectorDeps1,
- classGenActivityInjectorDeps2,
- classGenModuleDeps1,
- classGenModuleDeps2,
- classGenHiltComponents,
- classGenDaggerHiltApplicationComponent
- )
-
- fileToTimestampMap = mutableMapOf<File, Long>().apply {
- for (file in files) {
- this[file] = file.lastModified()
- }
- }
- }
-
- private fun recordFileChanges() {
- changedFiles = fileToTimestampMap.filter { (file, previousTimestamp) ->
- file.exists() && file.lastModified() != previousTimestamp
- }.keys
-
- unchangedFiles = fileToTimestampMap.filter { (file, previousTimestamp) ->
- file.exists() && file.lastModified() == previousTimestamp
- }.keys
-
- deletedFiles = fileToTimestampMap.filter { (file, _) -> !file.exists() }.keys
- }
-
- private fun assertFilesExist(vararg files: File) {
- expect.withMessage("Existing files")
- .that(files.filter { it.exists() })
- .containsExactlyElementsIn(files)
- }
-
- private fun assertChangedFiles(type: FileType, vararg files: File) {
- expect.withMessage("Changed files")
- .that(changedFiles.filter { it.name.endsWith(type.extension) })
- .containsExactlyElementsIn(files)
- }
-
- private fun assertDeletedFiles(vararg files: File) {
- expect.withMessage("Deleted files").that(deletedFiles).containsAtLeastElementsIn(files)
- }
-
- private fun searchAndReplace(file: File, search: String, replace: String) {
- file.writeText(file.readText().replace(search, replace))
- }
-
- enum class FileType(val extension: String) {
- JAVA(".java"),
- CLASS(".class"),
- }
-
- companion object {
- private const val SRC_DIR = "src/main/java"
- private const val GEN_SRC_DIR = "build/generated/ap_generated_sources/debug/out/"
- private const val CLASS_DIR = "build/intermediates/javac/debug/classes"
-
- private const val CLEAN_TASK = ":clean"
- private const val COMPILE_TASK = ":compileDebugJavaWithJavac"
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt
deleted file mode 100644
index 0b84002..0000000
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/TransformTest.kt
+++ /dev/null
@@ -1,313 +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.
- */
-
-import java.io.DataInputStream
-import java.io.FileInputStream
-import javassist.bytecode.ByteArray
-import javassist.bytecode.ClassFile
-import junit.framework.Assert.assertEquals
-import org.gradle.testkit.runner.TaskOutcome
-import org.junit.Assert
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-
-class TransformTest {
-
- @get:Rule
- val testProjectDir = TemporaryFolder()
-
- lateinit var gradleRunner: GradleTestRunner
-
- @Before
- fun setup() {
- gradleRunner = GradleTestRunner(testProjectDir)
- gradleRunner.addSrc(
- srcPath = "minimal/MainActivity.java",
- srcContent =
- """
- package minimal;
-
- import android.os.Bundle;
- import androidx.appcompat.app.AppCompatActivity;
-
- @dagger.hilt.android.AndroidEntryPoint
- public class MainActivity extends AppCompatActivity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
- }
- """.trimIndent()
- )
- }
-
- // Simple functional test to verify transformation.
- @Test
- fun testAssemble() {
- 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'"
- )
- gradleRunner.addActivities(
- "<activity android:name=\".MainActivity\"/>"
- )
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(":assembleDebug")
- Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
-
- val transformedClass = result.getTransformedFile("minimal/MainActivity.class")
- FileInputStream(transformedClass).use { fileInput ->
- ClassFile(DataInputStream(fileInput)).let { classFile ->
- // Verify superclass is updated
- Assert.assertEquals("minimal.Hilt_MainActivity", classFile.superclass)
- // Verify super call is also updated
- val constPool = classFile.constPool
- classFile.methods.first { it.name == "onCreate" }.let { methodInfo ->
- // bytecode of MainActivity.onCreate() is:
- // 0 - aload_0
- // 1 - aload_1
- // 2 - invokespecial
- // 5 - return
- val invokeIndex = 2
- val methodRef = ByteArray.readU16bit(methodInfo.codeAttribute.code, invokeIndex + 1)
- val classRef = constPool.getMethodrefClassName(methodRef)
- Assert.assertEquals("minimal.Hilt_MainActivity", classRef)
- }
- }
- }
- }
-
- // Verify correct transformation is done on nested classes.
- @Test
- fun testAssemble_nestedClass() {
- 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'"
- )
-
- gradleRunner.addSrc(
- srcPath = "minimal/TopClass.java",
- srcContent =
- """
- package minimal;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- public class TopClass {
- @dagger.hilt.android.AndroidEntryPoint
- public static class NestedActivity extends AppCompatActivity { }
- }
- """.trimIndent()
- )
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(":assembleDebug")
- Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
-
- val transformedClass = result.getTransformedFile("minimal/TopClass\$NestedActivity.class")
- FileInputStream(transformedClass).use { fileInput ->
- ClassFile(DataInputStream(fileInput)).let { classFile ->
- Assert.assertEquals("minimal.Hilt_TopClass_NestedActivity", classFile.superclass)
- }
- }
- }
-
- // Verify transformation ignores abstract methods.
- @Test
- fun testAssemble_abstractMethod() {
- 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'"
- )
-
- gradleRunner.addSrc(
- srcPath = "minimal/AbstractActivity.java",
- srcContent =
- """
- package minimal;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- @dagger.hilt.android.AndroidEntryPoint
- public abstract class AbstractActivity extends AppCompatActivity {
- public abstract void method();
- }
- """.trimIndent()
- )
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(":assembleDebug")
- Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
-
- val transformedClass = result.getTransformedFile("minimal/AbstractActivity.class")
- FileInputStream(transformedClass).use { fileInput ->
- ClassFile(DataInputStream(fileInput)).let { classFile ->
- Assert.assertEquals("minimal.Hilt_AbstractActivity", classFile.superclass)
- }
- }
- }
-
- // Verify transformation ignores native methods.
- @Test
- fun testAssemble_nativeMethod() {
- 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'"
- )
-
- gradleRunner.addSrc(
- srcPath = "minimal/SimpleActivity.java",
- srcContent =
- """
- package minimal;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- @dagger.hilt.android.AndroidEntryPoint
- public class SimpleActivity extends AppCompatActivity {
- public native void method();
- }
- """.trimIndent()
- )
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(":assembleDebug")
- Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
-
- val transformedClass = result.getTransformedFile("minimal/SimpleActivity.class")
- FileInputStream(transformedClass).use { fileInput ->
- ClassFile(DataInputStream(fileInput)).let { classFile ->
- Assert.assertEquals("minimal.Hilt_SimpleActivity", classFile.superclass)
- }
- }
- }
-
- // Verifies the transformation is applied incrementally when a class to be transformed is updated.
- @Test
- fun testTransform_incrementalClass() {
- 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'"
- )
-
- val srcFile = gradleRunner.addSrc(
- srcPath = "minimal/OtherActivity.java",
- srcContent =
- """
- package minimal;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- @dagger.hilt.android.AndroidEntryPoint
- public class OtherActivity extends AppCompatActivity {
-
- }
- """.trimIndent()
- )
-
- gradleRunner.build().let {
- val assembleTask = it.getTask(TRANSFORM_TASK_NAME)
- Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
- }
-
- gradleRunner.build().let {
- val assembleTask = it.getTask(TRANSFORM_TASK_NAME)
- Assert.assertEquals(TaskOutcome.UP_TO_DATE, assembleTask.outcome)
- }
-
- srcFile.delete()
- gradleRunner.addSrc(
- srcPath = "minimal/OtherActivity.java",
- srcContent =
- """
- package minimal;
-
- import androidx.fragment.app.FragmentActivity;
-
- @dagger.hilt.android.AndroidEntryPoint
- public class OtherActivity extends FragmentActivity {
-
- }
- """.trimIndent()
- )
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(TRANSFORM_TASK_NAME)
- Assert.assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
-
- val transformedClass = result.getTransformedFile("minimal/OtherActivity.class")
- FileInputStream(transformedClass).use { fileInput ->
- ClassFile(DataInputStream(fileInput)).let { classFile ->
- Assert.assertEquals("minimal.Hilt_OtherActivity", classFile.superclass)
- }
- }
- }
-
- // Verifies the transformation is applied incrementally when a new class is added to an existing
- // directory.
- @Test
- fun testTransform_incrementalDir() {
- 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'"
- )
-
- gradleRunner.addSrcPackage("ui/")
-
- gradleRunner.build().let {
- val assembleTask = it.getTask(TRANSFORM_TASK_NAME)
- assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
- }
-
- gradleRunner.build().let {
- val assembleTask = it.getTask(TRANSFORM_TASK_NAME)
- assertEquals(TaskOutcome.UP_TO_DATE, assembleTask.outcome)
- }
-
- gradleRunner.addSrc(
- srcPath = "ui/OtherActivity.java",
- srcContent =
- """
- package ui;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- @dagger.hilt.android.AndroidEntryPoint
- public class OtherActivity extends AppCompatActivity {
-
- }
- """.trimIndent()
- )
-
- val result = gradleRunner.build()
- val assembleTask = result.getTask(TRANSFORM_TASK_NAME)
- assertEquals(TaskOutcome.SUCCESS, assembleTask.outcome)
- }
-
- companion object {
- const val TRANSFORM_TASK_NAME =
- ":transformDebugClassesWithAsm"
- }
-}
diff --git a/java/dagger/hilt/android/plugin/src/test/kotlin/util/SimpleAGPVersionTest.kt b/java/dagger/hilt/android/plugin/src/test/kotlin/util/SimpleAGPVersionTest.kt
deleted file mode 100644
index 75292b8..0000000
--- a/java/dagger/hilt/android/plugin/src/test/kotlin/util/SimpleAGPVersionTest.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package util
-
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.plugin.util.SimpleAGPVersion
-import org.junit.Test
-
-class SimpleAGPVersionTest {
-
- @Test
- fun parsing() {
- assertThat(SimpleAGPVersion.parse("4.2"))
- .isEqualTo(SimpleAGPVersion(4, 2))
- assertThat(SimpleAGPVersion.parse("4.2.1"))
- .isEqualTo(SimpleAGPVersion(4, 2))
- assertThat(SimpleAGPVersion.parse("7.0.0-alpha01"))
- .isEqualTo(SimpleAGPVersion(7, 0))
- }
-
- @Test
- fun comparing() {
- assertThat(SimpleAGPVersion(4, 2))
- .isEqualTo(SimpleAGPVersion(4, 2))
- assertThat(SimpleAGPVersion(4, 2))
- .isGreaterThan(SimpleAGPVersion(3, 4))
- assertThat(SimpleAGPVersion(4, 2))
- .isLessThan(SimpleAGPVersion(7, 0))
-
- assertThat(SimpleAGPVersion.parse("4.2.1"))
- .isEqualTo(SimpleAGPVersion.parse("4.2.2"))
- assertThat(SimpleAGPVersion.parse("4.2.1"))
- .isGreaterThan(SimpleAGPVersion.parse("3.4.1"))
- assertThat(SimpleAGPVersion.parse("4.2.1"))
- .isLessThan(SimpleAGPVersion.parse("7.0.1"))
-
- assertThat(SimpleAGPVersion.parse("4.2.1"))
- .isLessThan(SimpleAGPVersion.parse("7.0.0-alpha01"))
- assertThat(SimpleAGPVersion.parse("7.0.0-alpha01"))
- .isEqualTo(SimpleAGPVersion.parse("7.0.0-alpha02"))
- }
-}
diff --git a/java/dagger/hilt/android/processor/BUILD b/java/dagger/hilt/android/processor/BUILD
deleted file mode 100644
index e116c44..0000000
--- a/java/dagger/hilt/android/processor/BUILD
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Hilt android processors.
-
-load("//:build_defs.bzl", "POM_VERSION_ALPHA")
-load("//tools:maven.bzl", "gen_maven_artifact")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "artifact-lib",
- tags = ["maven_coordinates=com.google.dagger:hilt-android-compiler:" + POM_VERSION_ALPHA],
- visibility = ["//visibility:private"],
- exports = [
- "//java/dagger/hilt/processor:artifact-lib-shared",
- ],
-)
-
-gen_maven_artifact(
- name = "artifact",
- artifact_coordinates = "com.google.dagger:hilt-android-compiler:" + POM_VERSION_ALPHA,
- artifact_name = "Hilt Android Processor",
- artifact_target = ":artifact-lib",
- artifact_target_libs = [
- "//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/android/processor/internal:utils",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:android_generators",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:compiler_options",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:metadata",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
- "//java/dagger/hilt/android/processor/internal/bindvalue:bind_value_processor_lib",
- "//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib",
- "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//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:kotlin",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
- "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
- "//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
- "//java/dagger/hilt/processor/internal/aliasof:processor_lib",
- "//java/dagger/hilt/processor/internal/definecomponent:define_components",
- "//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
- "//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
- "//java/dagger/hilt/processor/internal/root:root_metadata",
- "//java/dagger/hilt/processor/internal/root:root_type",
- ],
- 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.guava:failureaccess",
- "com.google.guava:guava",
- "com.squareup:javapoet",
- "javax.annotation:jsr250-api",
- "javax.inject:javax.inject",
- "net.ltgt.gradle.incap:incap",
- "org.jetbrains.kotlin:kotlin-stdlib",
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
- ],
- javadoc_android_api_level = 30,
- javadoc_root_packages = [
- "dagger.hilt.processor",
- "dagger.hilt.android.processor",
- ],
- javadoc_srcs = [
- "//java/dagger/hilt:hilt_processing_filegroup",
- ],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.hilt.android.shaded.auto.common.@1"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/processor/internal/AndroidClassNames.java b/java/dagger/hilt/android/processor/internal/AndroidClassNames.java
deleted file mode 100644
index 915ae51..0000000
--- a/java/dagger/hilt/android/processor/internal/AndroidClassNames.java
+++ /dev/null
@@ -1,117 +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 static com.squareup.javapoet.ClassName.get;
-
-import com.squareup.javapoet.ClassName;
-
-/** Holder for commonly used class names. */
-public final class AndroidClassNames {
-
- public static final ClassName APPLICATION_PROVIDER =
- get("androidx.test.core.app", "ApplicationProvider");
- public static final ClassName ACTIVITY = get("android.app", "Activity");
- public static final ClassName COMPONENT_ACTIVITY = get("androidx.activity", "ComponentActivity");
- public static final ClassName APPLICATION = get("android.app", "Application");
- public static final ClassName BROADCAST_RECEIVER = get("android.content", "BroadcastReceiver");
- public static final ClassName SERVICE = get("android.app", "Service");
- public static final ClassName FRAGMENT =
- get("androidx.fragment.app", "Fragment");
- public static final ClassName VIEW = get("android.view", "View");
-
- public static final ClassName NULLABLE_INTERNAL = get("android.annotation", "Nullable");
- public static final ClassName TARGET_API = get("android.annotation", "TargetApi");
-
- public static final ClassName CONTEXT = get("android.content", "Context");
- public static final ClassName CONTEXT_WRAPPER = get("android.content", "ContextWrapper");
- public static final ClassName INTENT = get("android.content", "Intent");
-
- public static final ClassName BUNDLE = get("android.os", "Bundle");
-
- public static final ClassName CALL_SUPER = get("androidx.annotation", "CallSuper");
- public static final ClassName MAIN_THREAD = get("androidx.annotation", "MainThread");
- public static final ClassName NULLABLE = get("androidx.annotation", "Nullable");
- public static final ClassName MULTI_DEX_APPLICATION =
- get("androidx.multidex", "MultiDexApplication");
-
- public static final ClassName ATTRIBUTE_SET = get("android.util", "AttributeSet");
- public static final ClassName LAYOUT_INFLATER = get("android.view", "LayoutInflater");
-
- public static final ClassName ANDROID_ENTRY_POINT =
- get("dagger.hilt.android", "AndroidEntryPoint");
- public static final ClassName WITH_FRAGMENT_BINDINGS =
- get("dagger.hilt.android", "WithFragmentBindings");
- public static final ClassName HILT_ANDROID_APP =
- get("dagger.hilt.android", "HiltAndroidApp");
- public static final ClassName OPTIONAL_INJECT =
- get("dagger.hilt.android.migration", "OptionalInject");
-
- public static final ClassName SINGLETON_COMPONENT =
- get("dagger.hilt.components", "SingletonComponent");
- public static final ClassName ACTIVITY_COMPONENT =
- get("dagger.hilt.android.components", "ActivityComponent");
- public static final ClassName ACTIVITY_RETAINED_COMPONENT =
- get("dagger.hilt.android.components", "ActivityRetainedComponent");
- public static final ClassName FRAGMENT_COMPONENT =
- get("dagger.hilt.android.components", "FragmentComponent");
- public static final ClassName VIEW_WITH_FRAGMENT_COMPONENT =
- get("dagger.hilt.android.components", "ViewWithFragmentComponent");
- public static final ClassName VIEW_COMPONENT =
- get("dagger.hilt.android.components", "ViewComponent");
- public static final ClassName SERVICE_COMPONENT =
- get("dagger.hilt.android.components", "ServiceComponent");
- public static final ClassName VIEW_MODEL_COMPONENT =
- get("dagger.hilt.android.components", "ViewModelComponent");
-
- public static final ClassName ACTIVITY_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.managers", "ActivityComponentManager");
- public static final ClassName APPLICATION_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.managers", "ApplicationComponentManager");
- public static final ClassName BROADCAST_RECEIVER_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.managers", "BroadcastReceiverComponentManager");
- public static final ClassName COMPONENT_SUPPLIER =
- get("dagger.hilt.android.internal.managers", "ComponentSupplier");
- public static final ClassName FRAGMENT_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.managers", "FragmentComponentManager");
- public static final ClassName SERVICE_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.managers", "ServiceComponentManager");
- public static final ClassName VIEW_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.managers", "ViewComponentManager");
-
- public static final ClassName INJECTED_BY_HILT =
- get("dagger.hilt.android.internal.migration", "InjectedByHilt");
-
- public static final ClassName APPLICATION_CONTEXT_MODULE =
- get("dagger.hilt.android.internal.modules", "ApplicationContextModule");
-
- public static final ClassName DEFAULT_VIEW_MODEL_FACTORIES =
- get("dagger.hilt.android.internal.lifecycle", "DefaultViewModelFactories");
- public static final ClassName HILT_VIEW_MODEL =
- get("dagger.hilt.android.lifecycle", "HiltViewModel");
- public static final ClassName HILT_VIEW_MODEL_MAP_QUALIFIER =
- get("dagger.hilt.android.internal.lifecycle", "HiltViewModelMap");
- public static final ClassName HILT_VIEW_MODEL_KEYS_QUALIFIER =
- get("dagger.hilt.android.internal.lifecycle", "HiltViewModelMap", "KeySet");
- public static final ClassName VIEW_MODEL = get("androidx.lifecycle", "ViewModel");
- public static final ClassName VIEW_MODEL_PROVIDER_FACTORY =
- get("androidx.lifecycle", "ViewModelProvider", "Factory");
- public static final ClassName SAVED_STATE_HANDLE =
- get("androidx.lifecycle", "SavedStateHandle");
-
- private AndroidClassNames() {}
-}
diff --git a/java/dagger/hilt/android/processor/internal/BUILD b/java/dagger/hilt/android/processor/internal/BUILD
deleted file mode 100644
index aaf8b89..0000000
--- a/java/dagger/hilt/android/processor/internal/BUILD
+++ /dev/null
@@ -1,45 +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.
-
-# Description:
-# Internal code for implementing Hilt android processors.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "android_classnames",
- srcs = [
- "AndroidClassNames.java",
- ],
- deps = [
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-# TODO(erichang): Merge this into other utils
-java_library(
- name = "utils",
- srcs = [
- "MoreTypes.java",
- ],
- deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/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
deleted file mode 100644
index ce9ad14..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGenerator.java
+++ /dev/null
@@ -1,116 +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.androidentrypoint;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-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 AndroidEntryPointMetadata metadata;
- private final ClassName generatedClassName;
-
- public ActivityGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
-
- generatedClassName = metadata.generatedClassName();
- }
-
- // @Generated("ActivityGenerator")
- // abstract class Hilt_$CLASS extends $BASE implements ComponentManager<?> {
- // ...
- // }
- public void generate() throws IOException {
- TypeSpec.Builder builder =
- TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
- .superclass(metadata.baseClassName())
- .addModifiers(metadata.generatedClassModifiers());
-
- Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
- Processors.addGeneratedAnnotation(builder, env, getClass());
-
- Generators.copyConstructors(metadata.baseElement(), builder);
- builder.addMethod(onCreate());
-
-
- metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEachOrdered(builder::addTypeVariable);
-
- Generators.addComponentOverride(metadata, builder);
- Generators.copyLintAnnotations(metadata.element(), builder);
-
- Generators.addInjectionMethods(metadata, builder);
-
- if (Processors.isAssignableFrom(metadata.baseElement(), AndroidClassNames.COMPONENT_ACTIVITY)
- && !metadata.overridesAndroidEntryPointClass()) {
- builder.addMethod(getDefaultViewModelProviderFactory());
- }
-
- JavaFile.builder(generatedClassName.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
- }
-
- // @CallSuper
- // @Override
- // protected void onCreate(@Nullable Bundle savedInstanceState) {
- // inject();
- // super.onCreate(savedInstanceState);
- // }
- private MethodSpec onCreate() {
- return MethodSpec.methodBuilder("onCreate")
- .addAnnotation(AndroidClassNames.CALL_SUPER)
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PROTECTED)
- .addParameter(
- ParameterSpec.builder(AndroidClassNames.BUNDLE, "savedInstanceState")
- .addAnnotation(AndroidClassNames.NULLABLE)
- .build())
- .addStatement("inject()")
- .addStatement("super.onCreate(savedInstanceState)")
- .build();
- }
-
- // @Override
- // public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
- // return DefaultViewModelFactories.getActivityFactory(this);
- // }
- private MethodSpec getDefaultViewModelProviderFactory() {
- return MethodSpec.methodBuilder("getDefaultViewModelProviderFactory")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .returns(AndroidClassNames.VIEW_MODEL_PROVIDER_FACTORY)
- .addStatement(
- "return $T.getActivityFactory(this)",
- AndroidClassNames.DEFAULT_VIEW_MODEL_FACTORIES)
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
deleted file mode 100644
index e5868f8..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
+++ /dev/null
@@ -1,522 +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.androidentrypoint;
-
-import static dagger.hilt.android.processor.internal.androidentrypoint.HiltCompilerOptions.BooleanOption.DISABLE_ANDROID_SUPERCLASS_VALIDATION;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-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.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.ParameterSpec;
-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.KotlinMetadataUtils;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-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 base class {@link Element} given to @AndroidEntryPoint. */
- public abstract TypeElement baseElement();
-
- /** The name of the generated base class, beginning with 'Hilt_'. */
- public abstract ClassName generatedClassName();
-
- /** Returns {@code true} if the class requires bytecode injection to replace the base class. */
- public abstract boolean requiresBytecodeInjection();
-
- /** Returns the {@link AndroidType} for the annotated element. */
- public abstract AndroidType androidType();
-
- /** Returns {@link Optional} of {@link AndroidEntryPointMetadata}. */
- public abstract Optional<AndroidEntryPointMetadata> baseMetadata();
-
- /** Returns set of scopes that the component interface should be installed in. */
- public abstract ImmutableSet<ClassName> installInComponents();
-
- /** Returns the component manager this generated Hilt class should use. */
- public abstract TypeName componentManager();
-
- /** Returns the initialization arguments for the component manager. */
- public abstract Optional<CodeBlock> componentManagerInitArgs();
-
- /**
- * Returns the metadata for the root most class in the hierarchy.
- *
- * <p>If this is the only metadata in the class hierarchy, it returns this.
- */
- @Memoized
- public AndroidEntryPointMetadata rootMetadata() {
- return baseMetadata().map(AndroidEntryPointMetadata::rootMetadata).orElse(this);
- }
-
- boolean isRootMetadata() {
- return this.equals(rootMetadata());
- }
-
- /** Returns true if this class allows optional injection. */
- public boolean allowsOptionalInjection() {
- return Processors.hasAnnotation(element(), AndroidClassNames.OPTIONAL_INJECT);
- }
-
- /** Returns true if any base class (transitively) allows optional injection. */
- public boolean baseAllowsOptionalInjection() {
- return baseMetadata().isPresent() && baseMetadata().get().allowsOptionalInjection();
- }
-
- /** Returns true if any base class (transitively) uses @AndroidEntryPoint. */
- public boolean overridesAndroidEntryPointClass() {
- return baseMetadata().isPresent();
- }
-
- /** The name of the class annotated with @AndroidEntryPoint */
- public ClassName elementClassName() {
- return ClassName.get(element());
- }
-
- /** The name of the base class given to @AndroidEntryPoint */
- public TypeName baseClassName() {
- return TypeName.get(baseElement().asType());
- }
-
- /** The name of the generated injector for the Hilt class. */
- public ClassName injectorClassName() {
- return Processors.append(
- Processors.getEnclosedClassName(elementClassName()), "_GeneratedInjector");
- }
-
- /**
- * The name of inject method for this class. The format is: inject$CLASS. If the class is nested,
- * will return the full name deliminated with '_'. e.g. Foo.Bar.Baz -> injectFoo_Bar_Baz
- */
- public String injectMethodName() {
- return "inject" + Processors.getEnclosedName(elementClassName());
- }
-
- /** Returns the @InstallIn annotation for the module providing this class. */
- public final AnnotationSpec injectorInstallInAnnotation() {
- return Components.getInstallInAnnotationSpec(installInComponents());
- }
-
- public ParameterSpec componentManagerParam() {
- return ParameterSpec.builder(componentManager(), "componentManager").build();
- }
-
- /**
- * Modifiers that should be applied to the generated class.
- *
- * <p>Note that the generated class must have public visibility if used by a
- * public @AndroidEntryPoint-annotated kotlin class. See:
- * 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)
- ? new Modifier[] {Modifier.ABSTRACT, Modifier.PUBLIC}
- : new Modifier[] {Modifier.ABSTRACT};
- }
-
- private static ClassName generatedClassName(TypeElement element) {
- String prefix = "Hilt_";
- return Processors.prepend(Processors.getEnclosedClassName(ClassName.get(element)), prefix);
- }
-
- private static final ImmutableSet<ClassName> HILT_ANNOTATION_NAMES =
- ImmutableSet.of(
- 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())))
- .collect(toImmutableSet());
- }
-
- /** Returns true if the given element has Android Entry Point metadata. */
- public static boolean hasAndroidEntryPointMetadata(Element 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 manuallyConstruct(
- TypeElement element,
- TypeElement baseElement,
- ClassName generatedClassName,
- boolean requiresBytecodeInjection,
- AndroidType androidType,
- Optional<AndroidEntryPointMetadata> baseMetadata,
- ImmutableSet<ClassName> installInComponents,
- TypeName componentManager,
- Optional<CodeBlock> componentManagerInitArgs) {
- return new AutoValue_AndroidEntryPointMetadata(
- element,
- baseElement,
- generatedClassName,
- requiresBytecodeInjection,
- androidType,
- baseMetadata,
- installInComponents,
- componentManager,
- componentManagerInitArgs);
- }
-
- /**
- * Internal implementation for "of" method, checking inheritance cycle utilizing inheritanceTrace
- * along the way.
- */
- private static AndroidEntryPointMetadata of(
- ProcessingEnvironment env, Element element, LinkedHashSet<Element> inheritanceTrace) {
- ImmutableSet<? extends AnnotationMirror> 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()));
-
- ProcessorErrors.checkState(
- element.getKind() == ElementKind.CLASS,
- element,
- "Only classes can be annotated with @%s",
- annotationClassName.simpleName());
- TypeElement androidEntryPointElement = MoreElements.asType(element);
-
- ProcessorErrors.checkState(
- androidEntryPointElement.getTypeParameters().isEmpty(),
- element,
- "@%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;
- boolean requiresBytecodeInjection =
- DISABLE_ANDROID_SUPERCLASS_VALIDATION.get(env)
- && MoreTypes.isTypeOf(Void.class, androidEntryPointClassValue.asType());
- if (requiresBytecodeInjection) {
- baseElement = MoreElements.asType(env.getTypeUtils().asElement(androidEntryPointElement.getSuperclass()));
- // 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.
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- ProcessorErrors.checkState(
- !metadataUtil.hasMetadata(androidEntryPointElement)
- || !metadataUtil.containsConstructorWithDefaultParam(baseElement),
- baseElement,
- "The base class, '%s', of the @AndroidEntryPoint, '%s', contains a constructor with "
- + "default parameters. This is currently not supported by the Gradle plugin. Either "
- + "specify the base class as described at "
- + "https://dagger.dev/hilt/gradle-setup#why-use-the-plugin or remove the default value "
- + "declaration.",
- baseElement.getQualifiedName(),
- androidEntryPointElement.getQualifiedName());
- generatedClassName = generatedClassName(androidEntryPointElement);
- } else {
- baseElement = androidEntryPointClassValue;
- ProcessorErrors.checkState(
- !MoreTypes.isTypeOf(Void.class, baseElement.asType()),
- androidEntryPointElement,
- "Expected @%s to have a value."
- + " Did you forget to apply the Gradle Plugin? (dagger.hilt.android.plugin)\n"
- + "See https://dagger.dev/hilt/gradle-setup.html" ,
- annotationClassName.simpleName());
-
- // 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);
- }
-
- Optional<AndroidEntryPointMetadata> baseMetadata =
- baseMetadata(env, androidEntryPointElement, baseElement, inheritanceTrace);
-
- if (baseMetadata.isPresent()) {
- return manuallyConstruct(
- androidEntryPointElement,
- baseElement,
- generatedClassName,
- requiresBytecodeInjection,
- baseMetadata.get().androidType(),
- baseMetadata,
- baseMetadata.get().installInComponents(),
- baseMetadata.get().componentManager(),
- baseMetadata.get().componentManagerInitArgs());
- } else {
- Type type = Type.of(androidEntryPointElement, baseElement);
- return manuallyConstruct(
- androidEntryPointElement,
- baseElement,
- generatedClassName,
- requiresBytecodeInjection,
- type.androidType,
- Optional.empty(),
- ImmutableSet.of(type.component),
- type.manager,
- Optional.ofNullable(type.componentManagerInitArgs));
- }
- }
-
- private static Optional<AndroidEntryPointMetadata> baseMetadata(
- ProcessingEnvironment env,
- TypeElement element,
- TypeElement baseElement,
- LinkedHashSet<Element> inheritanceTrace) {
- ProcessorErrors.checkState(
- inheritanceTrace.add(baseElement),
- element,
- cyclicInheritanceErrorMessage(inheritanceTrace, baseElement));
- if (hasAndroidEntryPointMetadata(baseElement)) {
- AndroidEntryPointMetadata baseMetadata =
- AndroidEntryPointMetadata.of(env, baseElement, inheritanceTrace);
- checkConsistentAnnotations(element, baseMetadata);
- return Optional.of(baseMetadata);
- }
-
- TypeMirror 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);
- }
-
- return Optional.empty();
- }
-
- private static String cyclicInheritanceErrorMessage(
- LinkedHashSet<Element> inheritanceTrace, TypeElement 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)
- .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));
- }
-
- /**
- * The Android type of the Android Entry Point element. Component splits (like with fragment
- * bindings) are coalesced.
- */
- public enum AndroidType {
- APPLICATION,
- ACTIVITY,
- BROADCAST_RECEIVER,
- FRAGMENT,
- SERVICE,
- VIEW
- }
-
- /** The type of Android Entry Point element. This includes splits for different components. */
- private static final class Type {
- private static final Type APPLICATION =
- new Type(
- AndroidClassNames.SINGLETON_COMPONENT,
- AndroidType.APPLICATION,
- AndroidClassNames.APPLICATION_COMPONENT_MANAGER,
- null);
- private static final Type SERVICE =
- new Type(
- AndroidClassNames.SERVICE_COMPONENT,
- AndroidType.SERVICE,
- AndroidClassNames.SERVICE_COMPONENT_MANAGER,
- CodeBlock.of("this"));
- private static final Type BROADCAST_RECEIVER =
- new Type(
- AndroidClassNames.SINGLETON_COMPONENT,
- AndroidType.BROADCAST_RECEIVER,
- AndroidClassNames.BROADCAST_RECEIVER_COMPONENT_MANAGER,
- null);
- private static final Type ACTIVITY =
- new Type(
- AndroidClassNames.ACTIVITY_COMPONENT,
- AndroidType.ACTIVITY,
- AndroidClassNames.ACTIVITY_COMPONENT_MANAGER,
- CodeBlock.of("this"));
- private static final Type FRAGMENT =
- new Type(
- AndroidClassNames.FRAGMENT_COMPONENT,
- AndroidType.FRAGMENT,
- AndroidClassNames.FRAGMENT_COMPONENT_MANAGER,
- CodeBlock.of("this"));
- private static final Type VIEW =
- new Type(
- AndroidClassNames.VIEW_WITH_FRAGMENT_COMPONENT,
- AndroidType.VIEW,
- AndroidClassNames.VIEW_COMPONENT_MANAGER,
- CodeBlock.of("this, true /* hasFragmentBindings */"));
- private static final Type VIEW_NO_FRAGMENT =
- new Type(
- AndroidClassNames.VIEW_COMPONENT,
- AndroidType.VIEW,
- AndroidClassNames.VIEW_COMPONENT_MANAGER,
- CodeBlock.of("this, false /* hasFragmentBindings */"));
-
- final ClassName component;
- final AndroidType androidType;
- final ClassName manager;
- final CodeBlock componentManagerInitArgs;
-
- Type(
- ClassName component,
- AndroidType androidType,
- ClassName manager,
- CodeBlock componentManagerInitArgs) {
- this.component = component;
- this.androidType = androidType;
- this.manager = manager;
- this.componentManagerInitArgs = componentManagerInitArgs;
- }
-
- AndroidType androidType() {
- return androidType;
- }
-
- 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 forHiltAndroidApp(TypeElement element, TypeElement baseElement) {
- ProcessorErrors.checkState(
- Processors.isAssignableFrom(baseElement, AndroidClassNames.APPLICATION),
- element,
- "@HiltAndroidApp base class must extend Application. Found: %s",
- baseElement);
- return Type.APPLICATION;
- }
-
- private static Type forAndroidEntryPoint(TypeElement element, TypeElement baseElement) {
- if (Processors.isAssignableFrom(baseElement, AndroidClassNames.ACTIVITY)) {
- ProcessorErrors.checkState(
- Processors.isAssignableFrom(baseElement, AndroidClassNames.COMPONENT_ACTIVITY),
- element,
- "Activities annotated with @AndroidEntryPoint must be a subclass of "
- + "androidx.activity.ComponentActivity. (e.g. FragmentActivity, "
- + "AppCompatActivity, etc.)"
- );
- return Type.ACTIVITY;
- } else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.SERVICE)) {
- return Type.SERVICE;
- } else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.BROADCAST_RECEIVER)) {
- return Type.BROADCAST_RECEIVER;
- } else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.FRAGMENT)) {
- return Type.FRAGMENT;
- } else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.VIEW)) {
- boolean withFragmentBindings =
- Processors.hasAnnotation(element, AndroidClassNames.WITH_FRAGMENT_BINDINGS);
- return withFragmentBindings ? Type.VIEW : Type.VIEW_NO_FRAGMENT;
- } else if (Processors.isAssignableFrom(baseElement, AndroidClassNames.APPLICATION)) {
- throw new BadInputException(
- "@AndroidEntryPoint cannot be used on an Application. Use @HiltAndroidApp instead.",
- element);
- }
- throw new BadInputException(
- "@AndroidEntryPoint base class must extend ComponentActivity, (support) Fragment, "
- + "View, Service, or BroadcastReceiver.",
- element);
- }
- }
-
- private static void checkConsistentAnnotations(
- TypeElement element, AndroidEntryPointMetadata baseMetadata) {
- TypeElement baseElement = baseMetadata.element();
- checkAnnotationsMatch(element, baseElement, AndroidClassNames.WITH_FRAGMENT_BINDINGS);
-
- ProcessorErrors.checkState(
- baseMetadata.allowsOptionalInjection()
- || !Processors.hasAnnotation(element, AndroidClassNames.OPTIONAL_INJECT),
- element,
- "@OptionalInject Hilt class cannot extend from a non-optional @AndroidEntryPoint "
- + "base: %s",
- element);
- }
-
- private static void checkAnnotationsMatch(
- TypeElement element, TypeElement baseElement, ClassName annotationName) {
- boolean isAnnotated = Processors.hasAnnotation(element, annotationName);
- boolean isBaseAnnotated = Processors.hasAnnotation(baseElement, annotationName);
- ProcessorErrors.checkState(
- isAnnotated == isBaseAnnotated,
- element,
- isBaseAnnotated
- ? "Classes that extend an @%1$s base class must also be annotated @%1$s"
- : "Classes that extend a @AndroidEntryPoint base class must not use @%1$s when the "
- + "base class "
- + "does not use @%1$s",
- annotationName.simpleName());
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
deleted file mode 100644
index 7bb9b9a..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessor.java
+++ /dev/null
@@ -1,85 +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.processor.internal.androidentrypoint;
-
-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 java.util.Set;
-import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
-
-/**
- * Processor that creates a module for classes marked with {@link
- * dagger.hilt.android.AndroidEntryPoint}.
- */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class AndroidEntryPointProcessor extends BaseProcessor {
-
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(
- AndroidClassNames.ANDROID_ENTRY_POINT.toString(),
- AndroidClassNames.HILT_ANDROID_APP.toString());
- }
-
- @Override
- public Set<String> getSupportedOptions() {
- return HiltCompilerOptions.getProcessorOptions();
- }
-
- @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:
- new ApplicationGenerator(getProcessingEnv(), metadata).generate();
- 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());
- }
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
deleted file mode 100644
index f16e06d..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ApplicationGenerator.java
+++ /dev/null
@@ -1,162 +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.androidentrypoint;
-
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-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.ComponentNames;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-
-/** Generates an Hilt Application for an @AndroidEntryPoint app class. */
-public final class ApplicationGenerator {
- private final ProcessingEnvironment env;
- private final AndroidEntryPointMetadata metadata;
- private final ClassName wrapperClassName;
-
- public ApplicationGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
- wrapperClassName = metadata.generatedClassName();
- }
-
- // @Generated("ApplicationGenerator")
- // abstract class Hilt_$APP extends $BASE implements ComponentManager<ApplicationComponent> {
- // ...
- // }
- public void generate() throws IOException {
- TypeSpec.Builder typeSpecBuilder =
- TypeSpec.classBuilder(wrapperClassName.simpleName())
- .addOriginatingElement(metadata.element())
- .superclass(metadata.baseClassName())
- .addModifiers(metadata.generatedClassModifiers())
- .addField(componentManagerField())
- .addMethod(componentManagerMethod());
-
- Generators.addGeneratedBaseClassJavadoc(typeSpecBuilder, AndroidClassNames.HILT_ANDROID_APP);
- Processors.addGeneratedAnnotation(typeSpecBuilder, env, getClass());
-
- metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEachOrdered(typeSpecBuilder::addTypeVariable);
-
- Generators.copyLintAnnotations(metadata.element(), typeSpecBuilder);
- Generators.addComponentOverride(metadata, typeSpecBuilder);
-
- typeSpecBuilder.addMethod(onCreateMethod());
-
- JavaFile.builder(metadata.elementClassName().packageName(), typeSpecBuilder.build())
- .build()
- .writeTo(env.getFiler());
- }
-
- // private final ApplicationComponentManager<ApplicationComponent> componentManager =
- // new ApplicationComponentManager(/* creatorType */);
- private FieldSpec componentManagerField() {
- ParameterSpec managerParam = metadata.componentManagerParam();
- return FieldSpec.builder(managerParam.type, managerParam.name)
- .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
- .initializer("new $T($L)", AndroidClassNames.APPLICATION_COMPONENT_MANAGER, creatorType())
- .build();
- }
-
- // protected ApplicationComponentManager<ApplicationComponent> componentManager() {
- // return componentManager();
- // }
- private MethodSpec componentManagerMethod() {
- return MethodSpec.methodBuilder("componentManager")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .returns(metadata.componentManagerParam().type)
- .addStatement("return $N", metadata.componentManagerParam())
- .build();
- }
-
- // new Supplier<ApplicationComponent>() {
- // @Override
- // public ApplicationComponent get() {
- // return DaggerApplicationComponent.builder()
- // .applicationContextModule(new ApplicationContextModule(Hilt_$APP.this))
- // .build();
- // }
- // }
- private TypeSpec creatorType() {
- ClassName component =
- ComponentNames.generatedComponent(
- metadata.elementClassName(), AndroidClassNames.SINGLETON_COMPONENT);
- return TypeSpec.anonymousClassBuilder("")
- .addSuperinterface(AndroidClassNames.COMPONENT_SUPPLIER)
- .addMethod(
- MethodSpec.methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .returns(TypeName.OBJECT)
- .addStatement(
- "return $T.builder()\n"
- + ".applicationContextModule(new $T($T.this))\n"
- + ".build()",
- Processors.prepend(Processors.getEnclosedClassName(component), "Dagger"),
- AndroidClassNames.APPLICATION_CONTEXT_MODULE,
- wrapperClassName)
- .build())
- .build();
- }
-
- // @CallSuper
- // @Override
- // public void onCreate() {
- // // This is a known unsafe cast but should be fine if the only use is
- // // $APP extends Hilt_$APP
- // generatedComponent().inject(($APP) this);
- // super.onCreate();
- // }
- private MethodSpec onCreateMethod() {
- return MethodSpec.methodBuilder("onCreate")
- .addAnnotation(AndroidClassNames.CALL_SUPER)
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addCode(injectCodeBlock())
- .addStatement("super.onCreate()")
- .build();
- }
-
- // // This is a known unsafe cast but should be fine if the only use is
- // // $APP extends Hilt_$APP
- // generatedComponent().inject$APP(($APP) this);
- private CodeBlock injectCodeBlock() {
- return CodeBlock.builder()
- .add("// This is a known unsafe cast, but is safe in the only correct use case:\n")
- .add("// $T extends $T\n", metadata.elementClassName(), metadata.generatedClassName())
- .addStatement(
- "(($T) generatedComponent()).$L($L)",
- metadata.injectorClassName(),
- metadata.injectMethodName(),
- Generators.unsafeCastThisTo(metadata.elementClassName()))
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
deleted file mode 100644
index 55e9ddc..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# Description:
-# Hilt android processors.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor",
- tags = [
- "annotation=dagger.hilt.android.AndroidEntryPoint;" +
- "genclass=${package}.Hilt_${outerclasses}${classname};" +
- "genclass=${package}.${outerclasses}${classname}_EntryPoint",
- ],
- deps = [
- ":processor_lib",
- ],
-)
-
-java_library(
- name = "processor_lib",
- srcs = ["AndroidEntryPointProcessor.java"],
- deps = [
- ":android_generators",
- ":compiler_options",
- ":metadata",
- "//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- ],
-)
-
-java_library(
- name = "android_generators",
- srcs = [
- "ActivityGenerator.java",
- "ApplicationGenerator.java",
- "BroadcastReceiverGenerator.java",
- "FragmentGenerator.java",
- "Generators.java",
- "InjectorEntryPointGenerator.java",
- "ServiceGenerator.java",
- "ViewGenerator.java",
- ],
- 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:component_names",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "metadata",
- srcs = [
- "AndroidEntryPointMetadata.java",
- ],
- deps = [
- ":compiler_options",
- "//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:components",
- "//java/dagger/hilt/processor/internal:kotlin",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "compiler_options",
- srcs = ["HiltCompilerOptions.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
deleted file mode 100644
index f8e9f60..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/BroadcastReceiverGenerator.java
+++ /dev/null
@@ -1,153 +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.androidentrypoint;
-
-import static dagger.internal.codegen.langmodel.DaggerElements.getMethodDescriptor;
-
-import com.google.common.collect.Iterables;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-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.android.processor.internal.MoreTypes;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-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 AndroidEntryPointMetadata metadata;
- private final ClassName generatedClassName;
-
- public BroadcastReceiverGenerator(
- ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
-
- generatedClassName = metadata.generatedClassName();
- }
-
- // @Generated("BroadcastReceiverGenerator")
- // abstract class Hilt_$CLASS extends $BASE {
- // ...
- // }
- public void generate() throws IOException {
- TypeSpec.Builder builder =
- TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
- .superclass(metadata.baseClassName())
- .addModifiers(metadata.generatedClassModifiers())
- .addMethod(onReceiveMethod());
-
- Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
- Processors.addGeneratedAnnotation(builder, env, getClass());
- Generators.copyConstructors(metadata.baseElement(), builder);
-
- metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEachOrdered(builder::addTypeVariable);
-
- Generators.addInjectionMethods(metadata, builder);
- Generators.copyLintAnnotations(metadata.element(), builder);
-
- // Add an unused field used as a marker to let the bytecode injector know this receiver will
- // need to be injected with a super.onReceive call. This is only necessary if no concrete
- // onReceive call is implemented in any of the super classes.
- if (metadata.requiresBytecodeInjection() && !isOnReceiveImplemented(metadata.baseElement())) {
- builder.addField(
- FieldSpec.builder(
- TypeName.BOOLEAN,
- "onReceiveBytecodeInjectionMarker",
- Modifier.PRIVATE,
- Modifier.FINAL)
- .initializer("false")
- .build());
- }
-
- JavaFile.builder(generatedClassName.packageName(),
- builder.build()).build().writeTo(env.getFiler());
- }
-
- private static boolean isOnReceiveImplemented(TypeElement typeElement) {
- boolean isImplemented =
- ElementFilter.methodsIn(typeElement.getEnclosedElements()).stream()
- .anyMatch(
- methodElement ->
- getMethodDescriptor(methodElement).equals(ON_RECEIVE_DESCRIPTOR)
- && !methodElement.getModifiers().contains(Modifier.ABSTRACT));
- if (isImplemented) {
- return true;
- } else if (typeElement.getSuperclass().getKind() != TypeKind.NONE) {
- return isOnReceiveImplemented(MoreTypes.asTypeElement(typeElement.getSuperclass()));
- } else {
- return false;
- }
- }
-
- // @Override
- // public void onReceive(Context context, Intent intent) {
- // inject(context);
- // super.onReceive();
- // }
- private MethodSpec onReceiveMethod() throws IOException {
- MethodSpec.Builder method =
- MethodSpec.methodBuilder("onReceive")
- .addAnnotation(Override.class)
- .addAnnotation(AndroidClassNames.CALL_SUPER)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(ParameterSpec.builder(AndroidClassNames.CONTEXT, "context").build())
- .addParameter(ParameterSpec.builder(AndroidClassNames.INTENT, "intent").build())
- .addStatement("inject(context)");
-
- if (metadata.overridesAndroidEntryPointClass()) {
- // We directly call super.onReceive here because we know Hilt base classes have a
- // non-abstract onReceive method. However, because the Hilt base class may not be generated
- // already we cannot fall down to the below logic to find it.
- 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"));
-
- // 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))
- .ifPresent(onReceive -> method.addStatement("super.onReceive(context, intent)"));
- }
-
- return method.build();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
deleted file mode 100644
index 4ef479f..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
+++ /dev/null
@@ -1,217 +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.androidentrypoint;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-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.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. */
-public final class FragmentGenerator {
- private static final FieldSpec COMPONENT_CONTEXT_FIELD =
- FieldSpec.builder(AndroidClassNames.CONTEXT_WRAPPER, "componentContext")
- .addModifiers(Modifier.PRIVATE)
- .build();
-
- private final ProcessingEnvironment env;
- private final AndroidEntryPointMetadata metadata;
- private final ClassName generatedClassName;
-
- public FragmentGenerator(
- ProcessingEnvironment env,
- AndroidEntryPointMetadata metadata ) {
- this.env = env;
- this.metadata = metadata;
- generatedClassName = metadata.generatedClassName();
- }
-
- public void generate() throws IOException {
- JavaFile.builder(generatedClassName.packageName(), createTypeSpec())
- .build()
- .writeTo(env.getFiler());
- }
-
- // @Generated("FragmentGenerator")
- // abstract class Hilt_$CLASS extends $BASE implements ComponentManager<?> {
- // ...
- // }
- TypeSpec createTypeSpec() {
- TypeSpec.Builder builder =
- TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
- .superclass(metadata.baseClassName())
- .addModifiers(metadata.generatedClassModifiers())
- .addField(COMPONENT_CONTEXT_FIELD)
- .addMethod(onAttachContextMethod())
- .addMethod(onAttachActivityMethod())
- .addMethod(initializeComponentContextMethod())
- .addMethod(getContextMethod())
- .addMethod(inflatorMethod());
-
- Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
- Processors.addGeneratedAnnotation(builder, env, getClass());
- Generators.copyLintAnnotations(metadata.element(), builder);
- Generators.addSuppressAnnotation(builder, "deprecation");
- Generators.copyConstructors(metadata.baseElement(), builder);
-
- metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEachOrdered(builder::addTypeVariable);
-
- Generators.addComponentOverride(metadata, builder);
-
- Generators.addInjectionMethods(metadata, builder);
-
- if (!metadata.overridesAndroidEntryPointClass() ) {
- builder.addMethod(getDefaultViewModelProviderFactory());
- }
-
- return builder.build();
- }
-
- // @CallSuper
- // @Override
- // public void onAttach(Activity activity) {
- // super.onAttach(activity);
- // initializeComponentContext();
- // }
- private static MethodSpec onAttachContextMethod() {
- return MethodSpec.methodBuilder("onAttach")
- .addAnnotation(Override.class)
- .addAnnotation(AndroidClassNames.CALL_SUPER)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(AndroidClassNames.CONTEXT, "context")
- .addStatement("super.onAttach(context)")
- .addStatement("initializeComponentContext()")
- .build();
- }
-
- // @CallSuper
- // @Override
- // public void onAttach(Activity activity) {
- // super.onAttach(activity);
- // Preconditions.checkState(
- // componentContext == null || FragmentComponentManager.findActivity(
- // componentContext) == activity, "...");
- // initializeComponentContext();
- // }
- private static MethodSpec onAttachActivityMethod() {
- return MethodSpec.methodBuilder("onAttach")
- .addAnnotation(Override.class)
- .addAnnotation(AndroidClassNames.CALL_SUPER)
- .addAnnotation(AndroidClassNames.MAIN_THREAD)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(AndroidClassNames.ACTIVITY, "activity")
- .addStatement("super.onAttach(activity)")
- .addStatement(
- "$T.checkState($N == null || $T.findActivity($N) == activity, $S)",
- ClassNames.PRECONDITIONS,
- COMPONENT_CONTEXT_FIELD,
- AndroidClassNames.FRAGMENT_COMPONENT_MANAGER,
- COMPONENT_CONTEXT_FIELD,
- "onAttach called multiple times with different Context! "
- + "Hilt Fragments should not be retained.")
- .addStatement("initializeComponentContext()")
- .build();
- }
-
- // private void initializeComponentContext() {
- // // Only inject on the first call to onAttach.
- // if (componentContext == null) {
- // // Note: The LayoutInflater provided by this componentContext may be different from super
- // // Fragment's because we are getting it from base context instead of cloning from super
- // // Fragment's LayoutInflater.
- // componentContext = FragmentComponentManager.createContextWrapper(super.getContext(), this);
- // inject();
- // }
- // }
- private MethodSpec initializeComponentContextMethod() {
- return MethodSpec.methodBuilder("initializeComponentContext")
- .addModifiers(Modifier.PRIVATE)
- .addComment("Only inject on the first call to onAttach.")
- .beginControlFlow("if ($N == null)", COMPONENT_CONTEXT_FIELD)
- .addComment(
- "Note: The LayoutInflater provided by this componentContext may be different from"
- + " super Fragment's because we getting it from base context instead of cloning"
- + " from the super Fragment's LayoutInflater.")
- .addStatement(
- "$N = $T.createContextWrapper(super.getContext(), this)",
- COMPONENT_CONTEXT_FIELD,
- metadata.componentManager())
- .addStatement("inject()")
- .endControlFlow()
- .build();
- }
-
- // @Override
- // public Context getContext() {
- // return componentContext;
- // }
- private static MethodSpec getContextMethod() {
- return MethodSpec.methodBuilder("getContext")
- .returns(AndroidClassNames.CONTEXT)
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addStatement("return $N", COMPONENT_CONTEXT_FIELD)
- .build();
- }
-
- // @Override
- // public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
- // LayoutInflater inflater = super.onGetLayoutInflater(savedInstanceState);
- // return LayoutInflater.from(FragmentComponentManager.createContextWrapper(inflater, this));
- // }
- private MethodSpec inflatorMethod() {
- return MethodSpec.methodBuilder("onGetLayoutInflater")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(AndroidClassNames.BUNDLE, "savedInstanceState")
- .returns(AndroidClassNames.LAYOUT_INFLATER)
- .addStatement(
- "$T inflater = super.onGetLayoutInflater(savedInstanceState)",
- AndroidClassNames.LAYOUT_INFLATER)
- .addStatement(
- "return $T.from($T.createContextWrapper(inflater, this))",
- AndroidClassNames.LAYOUT_INFLATER,
- metadata.componentManager())
- .build();
- }
-
- // @Override
- // public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
- // return DefaultViewModelFactories.getFragmentFactory(this);
- // }
- private MethodSpec getDefaultViewModelProviderFactory() {
- return MethodSpec.methodBuilder("getDefaultViewModelProviderFactory")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .returns(AndroidClassNames.VIEW_MODEL_PROVIDER_FACTORY)
- .addStatement(
- "return $T.getFragmentFactory(this)",
- AndroidClassNames.DEFAULT_VIEW_MODEL_FACTORIES)
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
deleted file mode 100644
index daadd03..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/Generators.java
+++ /dev/null
@@ -1,493 +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.androidentrypoint;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.google.common.base.Preconditions;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.android.processor.internal.AndroidClassNames;
-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 {
-
- static void addGeneratedBaseClassJavadoc(TypeSpec.Builder builder, ClassName annotation) {
- builder.addJavadoc("A generated base class to be extended by the @$T annotated class. If using"
- + " the Gradle plugin, this is swapped as the base class via bytecode transformation.",
- annotation);
- }
-
- /**
- * Copies all constructors with arguments to the builder.
- */
- static void copyConstructors(TypeElement 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());
-
- if (constructors.size() == 1
- && getOnlyElement(constructors).getParameters().isEmpty()
- && body.isEmpty()) {
- // No need to copy the constructor if the default constructor will handle it.
- return;
- }
-
- constructors.forEach(constructor -> builder.addMethod(copyConstructor(constructor, body)));
- }
-
- /** 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);
- // 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())
- : Optional.of(annotationSpec);
- }
- }
- return Optional.empty();
- }
-
- /**
- * 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();
- 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.
- */
- // Example:
- // Foo(Param1 param1, Param2 param2) {
- // super(param1, param2);
- // }
- static MethodSpec copyConstructor(ExecutableElement constructor) {
- return copyConstructor(constructor, CodeBlock.builder().build());
- }
-
- private static MethodSpec copyConstructor(ExecutableElement constructor, CodeBlock body) {
- List<ParameterSpec> params =
- constructor.getParameters().stream()
- .map(parameter -> getParameterSpecWithNullable(parameter))
- .collect(Collectors.toList());
-
- final MethodSpec.Builder builder =
- MethodSpec.constructorBuilder()
- .addParameters(params)
- .addStatement(
- "super($L)",
- params.stream().map(param -> param.name).collect(Collectors.joining(", ")))
- .addCode(body);
-
- constructor.getAnnotationMirrors().stream()
- .filter(a -> Processors.hasAnnotation(a, AndroidClassNames.TARGET_API))
- .collect(toOptional())
- .map(AnnotationSpec::get)
- .ifPresent(builder::addAnnotation);
-
- return builder.build();
- }
-
- /**
- * Copies the Android lint annotations from the annotated element to the generated element.
- *
- * <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)));
- }
- }
-
- // @Override
- // public CompT generatedComponent() {
- // return componentManager().generatedComponent();
- // }
- static void addComponentOverride(AndroidEntryPointMetadata metadata, TypeSpec.Builder builder) {
- if (metadata.overridesAndroidEntryPointClass()) {
- // We don't need to override this method if we are extending a Hilt type.
- return;
- }
- builder
- .addSuperinterface(ClassNames.GENERATED_COMPONENT_MANAGER_HOLDER)
- .addMethod(
- MethodSpec.methodBuilder("generatedComponent")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .returns(TypeName.OBJECT)
- .addStatement("return $L.generatedComponent()", componentManagerCallBlock(metadata))
- .build());
- }
-
- /** Adds the inject() and optionally the componentManager() methods to allow for injection. */
- static void addInjectionMethods(AndroidEntryPointMetadata metadata, TypeSpec.Builder builder) {
- switch (metadata.androidType()) {
- case ACTIVITY:
- case FRAGMENT:
- case VIEW:
- case SERVICE:
- addComponentManagerMethods(metadata, builder);
- // fall through
- case BROADCAST_RECEIVER:
- addInjectMethod(metadata, builder);
- break;
- default:
- throw new AssertionError();
- }
- }
-
- // @Override
- // public FragmentComponentManager componentManager() {
- // if (componentManager == null) {
- // synchronize (componentManagerLock) {
- // if (componentManager == null) {
- // componentManager = createComponentManager();
- // }
- // }
- // }
- // return componentManager;
- // }
- private static void addComponentManagerMethods(
- AndroidEntryPointMetadata metadata, TypeSpec.Builder typeSpecBuilder) {
- if (metadata.overridesAndroidEntryPointClass()) {
- // We don't need to override this method if we are extending a Hilt type.
- return;
- }
-
- ParameterSpec managerParam = metadata.componentManagerParam();
- typeSpecBuilder.addField(componentManagerField(metadata));
-
- typeSpecBuilder.addMethod(createComponentManagerMethod(metadata));
-
- MethodSpec.Builder methodSpecBuilder =
- MethodSpec.methodBuilder("componentManager")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .returns(managerParam.type)
- .beginControlFlow("if ($N == null)", managerParam);
-
- // Views do not do double-checked locking because this is called from the constructor
- if (metadata.androidType() != AndroidEntryPointMetadata.AndroidType.VIEW) {
- typeSpecBuilder.addField(componentManagerLockField());
-
- methodSpecBuilder
- .beginControlFlow("synchronized (componentManagerLock)")
- .beginControlFlow("if ($N == null)", managerParam);
- }
-
- methodSpecBuilder
- .addStatement("$N = createComponentManager()", managerParam)
- .endControlFlow();
-
- if (metadata.androidType() != AndroidEntryPointMetadata.AndroidType.VIEW) {
- methodSpecBuilder
- .endControlFlow()
- .endControlFlow();
- }
-
- methodSpecBuilder.addStatement("return $N", managerParam);
-
- typeSpecBuilder.addMethod(methodSpecBuilder.build());
- }
-
- // protected FragmentComponentManager createComponentManager() {
- // return new FragmentComponentManager(initArgs);
- // }
- private static MethodSpec createComponentManagerMethod(AndroidEntryPointMetadata metadata) {
- Preconditions.checkState(
- metadata.componentManagerInitArgs().isPresent(),
- "This method should not have been called for metadata where the init args are not"
- + " present.");
- return MethodSpec.methodBuilder("createComponentManager")
- .addModifiers(Modifier.PROTECTED)
- .returns(metadata.componentManager())
- .addStatement(
- "return new $T($L)",
- metadata.componentManager(),
- metadata.componentManagerInitArgs().get())
- .build();
- }
-
- // private volatile ComponentManager componentManager;
- private static FieldSpec componentManagerField(AndroidEntryPointMetadata metadata) {
- ParameterSpec managerParam = metadata.componentManagerParam();
- FieldSpec.Builder builder = FieldSpec.builder(managerParam.type, managerParam.name)
- .addModifiers(Modifier.PRIVATE);
-
- // Views do not need volatile since these are set in the constructor if ever set.
- if (metadata.androidType() != AndroidEntryPointMetadata.AndroidType.VIEW) {
- builder.addModifiers(Modifier.VOLATILE);
- }
-
- return builder.build();
- }
-
- // private final Object componentManagerLock = new Object();
- private static FieldSpec componentManagerLockField() {
- return FieldSpec.builder(TypeName.get(Object.class), "componentManagerLock")
- .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
- .initializer("new Object()")
- .build();
- }
-
- // protected void inject() {
- // if (!injected) {
- // generatedComponent().inject$CLASS(($CLASS) this);
- // injected = true;
- // }
- // }
- private static void addInjectMethod(
- AndroidEntryPointMetadata metadata, TypeSpec.Builder typeSpecBuilder) {
- MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("inject")
- .addModifiers(Modifier.PROTECTED);
-
- // Check if the parent is a Hilt type. If it isn't or if it is but it
- // wasn't injected by hilt, then return.
- // Object parent = ...depends on type...
- // if (!(parent instanceof GeneratedComponentManager)
- // || ((parent instanceof InjectedByHilt) &&
- // !((InjectedByHilt) parent).wasInjectedByHilt())) {
- // return;
- //
- if (metadata.allowsOptionalInjection()) {
- methodSpecBuilder
- .addStatement("$T parent = $L", ClassNames.OBJECT, getParentCodeBlock(metadata))
- .beginControlFlow(
- "if (!(parent instanceof $T) "
- + "|| ((parent instanceof $T) && !(($T) parent).wasInjectedByHilt()))",
- ClassNames.GENERATED_COMPONENT_MANAGER,
- AndroidClassNames.INJECTED_BY_HILT,
- AndroidClassNames.INJECTED_BY_HILT)
- .addStatement("return")
- .endControlFlow();
- }
-
- typeSpecBuilder.addField(injectedField(metadata));
-
- switch (metadata.androidType()) {
- case ACTIVITY:
- case FRAGMENT:
- case VIEW:
- case SERVICE:
- // Only add @Override if an ancestor extends a generated Hilt class.
- // When using bytecode injection, this isn't always guaranteed.
- if (metadata.overridesAndroidEntryPointClass()
- && ancestorExtendsGeneratedHiltClass(metadata)) {
- methodSpecBuilder.addAnnotation(Override.class);
- }
- methodSpecBuilder
- .beginControlFlow("if (!injected)")
- .addStatement("injected = true")
- .addStatement(
- "(($T) $L).$L($L)",
- metadata.injectorClassName(),
- generatedComponentCallBlock(metadata),
- metadata.injectMethodName(),
- unsafeCastThisTo(metadata.elementClassName()))
- .endControlFlow();
- break;
- case BROADCAST_RECEIVER:
- typeSpecBuilder.addField(injectedLockField());
-
- methodSpecBuilder
- .addParameter(ParameterSpec.builder(AndroidClassNames.CONTEXT, "context").build())
- .beginControlFlow("if (!injected)")
- .beginControlFlow("synchronized (injectedLock)")
- .beginControlFlow("if (!injected)")
- .addStatement(
- "(($T) $T.generatedComponent(context)).$L($L)",
- metadata.injectorClassName(),
- metadata.componentManager(),
- metadata.injectMethodName(),
- unsafeCastThisTo(metadata.elementClassName()))
- .addStatement("injected = true")
- .endControlFlow()
- .endControlFlow()
- .endControlFlow();
- break;
- default:
- throw new AssertionError();
- }
-
- // Also add a wasInjectedByHilt method if needed.
- // Even if we aren't optionally injected, if we override an optionally injected Hilt class
- // we also need to override the wasInjectedByHilt method.
- if (metadata.allowsOptionalInjection() || metadata.baseAllowsOptionalInjection()) {
- typeSpecBuilder.addMethod(
- MethodSpec.methodBuilder("wasInjectedByHilt")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .returns(boolean.class)
- .addStatement("return injected")
- .build());
- // Only add the interface though if this class allows optional injection (not that it
- // really matters since if the base allows optional injection the class implements the
- // interface anyway). But it is probably better to be consistent about only optionally
- // injected classes extend the interface.
- if (metadata.allowsOptionalInjection()) {
- typeSpecBuilder.addSuperinterface(AndroidClassNames.INJECTED_BY_HILT);
- }
- }
-
- typeSpecBuilder.addMethod(methodSpecBuilder.build());
- }
-
- private static CodeBlock getParentCodeBlock(AndroidEntryPointMetadata metadata) {
- switch (metadata.androidType()) {
- case ACTIVITY:
- case SERVICE:
- return CodeBlock.of("getApplicationContext()");
- case FRAGMENT:
- return CodeBlock.of("getHost()");
- case VIEW:
- return CodeBlock.of(
- "$L.maybeGetParentComponentManager()", componentManagerCallBlock(metadata));
- case BROADCAST_RECEIVER:
- // Broadcast receivers receive a "context" parameter
- return CodeBlock.of("context.getApplicationContext()");
- default:
- throw new AssertionError();
- }
- }
-
- /**
- * Returns the call to {@code generatedComponent()} with casts if needed.
- *
- * <p>A cast is required when the root generated Hilt class uses bytecode injection because
- * subclasses won't have access to the {@code generatedComponent()} method in that case.
- */
- private static CodeBlock generatedComponentCallBlock(AndroidEntryPointMetadata metadata) {
- return CodeBlock.of(
- "$L.generatedComponent()",
- !metadata.isRootMetadata() && metadata.rootMetadata().requiresBytecodeInjection()
- ? unsafeCastThisTo(ClassNames.GENERATED_COMPONENT_MANAGER_HOLDER)
- : "this");
- }
-
- /**
- * Returns the call to {@code componentManager()} with casts if needed.
- *
- * <p>A cast is required when the root generated Hilt class uses bytecode injection because
- * subclasses won't have access to the {@code componentManager()} method in that case.
- */
- private static CodeBlock componentManagerCallBlock(AndroidEntryPointMetadata metadata) {
- return CodeBlock.of(
- "$L.componentManager()",
- !metadata.isRootMetadata() && metadata.rootMetadata().requiresBytecodeInjection()
- ? unsafeCastThisTo(ClassNames.GENERATED_COMPONENT_MANAGER_HOLDER)
- : "this");
- }
-
- static CodeBlock unsafeCastThisTo(ClassName castType) {
- return CodeBlock.of("$T.<$T>unsafeCast(this)", ClassNames.UNSAFE_CASTS, castType);
- }
-
- /** Returns {@code true} if the an ancestor annotated class extends the generated class */
- private static boolean ancestorExtendsGeneratedHiltClass(AndroidEntryPointMetadata metadata) {
- while (metadata.baseMetadata().isPresent()) {
- metadata = metadata.baseMetadata().get();
- if (!metadata.requiresBytecodeInjection()) {
- return true;
- }
- }
- return false;
- }
-
- // private boolean injected = false;
- private static FieldSpec injectedField(AndroidEntryPointMetadata metadata) {
- FieldSpec.Builder builder = FieldSpec.builder(TypeName.BOOLEAN, "injected")
- .addModifiers(Modifier.PRIVATE);
-
- // Broadcast receivers do double-checked locking so this needs to be volatile
- if (metadata.androidType() == AndroidEntryPointMetadata.AndroidType.BROADCAST_RECEIVER) {
- builder.addModifiers(Modifier.VOLATILE);
- }
-
- // Views should not add an initializer here as this runs after the super constructor
- // and may reset state set during the super constructor call.
- if (metadata.androidType() != AndroidEntryPointMetadata.AndroidType.VIEW) {
- builder.initializer("false");
- }
- return builder.build();
- }
-
- // private final Object injectedLock = new Object();
- private static FieldSpec injectedLockField() {
- return FieldSpec.builder(TypeName.OBJECT, "injectedLock")
- .addModifiers(Modifier.PRIVATE, Modifier.FINAL)
- .initializer("new $T()", TypeName.OBJECT)
- .build();
- }
-
- /**
- * Adds the SupressWarnings to supress a warning in the generated code.
- *
- * @param keys the string keys of the warnings to suppress, e.g. 'deprecation', 'unchecked', etc.
- */
- public static void addSuppressAnnotation(TypeSpec.Builder builder, String... keys) {
- AnnotationSpec.Builder annotationBuilder = AnnotationSpec.builder(SuppressWarnings.class);
- for (String key : keys) {
- annotationBuilder.addMember("value", "$S", key);
- }
- builder.addAnnotation(annotationBuilder.build());
- }
-
- private Generators() {}
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java
deleted file mode 100644
index 577410d..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/HiltCompilerOptions.java
+++ /dev/null
@@ -1,71 +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.processor.internal.androidentrypoint;
-
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.processing.ProcessingEnvironment;
-
-/** Hilt annotation processor options. */
-// TODO(danysantiago): Consider consolidating with Dagger compiler options logic.
-// TODO(user): Move this class to dagger/hilt/processor/internal
-public final class HiltCompilerOptions {
-
- /** Processor options which can have true or false values. */
- public enum BooleanOption {
- /**
- * Flag that disables validating the superclass of @AndroidEntryPoint are Hilt_ generated,
- * classes. This flag is to be used internally by the Gradle plugin, enabling the bytecode
- * transformation to change the superclass.
- */
- DISABLE_ANDROID_SUPERCLASS_VALIDATION(
- "android.internal.disableAndroidSuperclassValidation", false),
-
- /** Flag that disables check on modules to be annotated with @InstallIn. */
- DISABLE_MODULES_HAVE_INSTALL_IN_CHECK("disableModulesHaveInstallInCheck", false);
-
- private final String name;
- private final boolean defaultValue;
-
- BooleanOption(String name, boolean defaultValue) {
- this.name = name;
- this.defaultValue = defaultValue;
- }
-
- public boolean get(ProcessingEnvironment env) {
- String value = env.getOptions().get(getQualifiedName());
- if (value == null) {
- return defaultValue;
- }
- // TODO(danysantiago): Strictly verify input, either 'true' or 'false' and nothing else.
- return Boolean.parseBoolean(value);
- }
-
- public String getQualifiedName() {
- return "dagger.hilt." + name;
- }
- }
-
- public static Set<String> getProcessorOptions() {
- return Arrays.stream(BooleanOption.values())
- .map(BooleanOption::getQualifiedName)
- .collect(Collectors.toSet());
- }
-
- private HiltCompilerOptions() {}
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
deleted file mode 100644
index e9e217d..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/InjectorEntryPointGenerator.java
+++ /dev/null
@@ -1,67 +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.androidentrypoint;
-
-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;
-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 AndroidEntryPointMetadata metadata;
-
- public InjectorEntryPointGenerator(
- ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
- }
-
- // @Generated("InjectorEntryPointGenerator")
- // @InstallIn({$SCOPES})
- // public interface FooActivity_GeneratedInjector {
- // void injectFoo(FooActivity foo);
- // }
- public void generate() throws IOException {
- 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())
- .addModifiers(Modifier.PUBLIC)
- .addMethod(
- MethodSpec.methodBuilder(metadata.injectMethodName())
- .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addParameter(
- metadata.elementClassName(),
- Processors.upperToLowerCamel(metadata.elementClassName().simpleName()))
- .build());
-
- Processors.addGeneratedAnnotation(builder, env, getClass());
- Generators.copyLintAnnotations(metadata.element(), builder);
-
- JavaFile.builder(name.packageName(), builder.build()).build().writeTo(env.getFiler());
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
deleted file mode 100644
index a80a215..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ServiceGenerator.java
+++ /dev/null
@@ -1,112 +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.androidentrypoint;
-
-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 AndroidEntryPointMetadata metadata;
- private final ClassName generatedClassName;
-
- public ServiceGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
-
- generatedClassName = metadata.generatedClassName();
- }
-
- // @Generated("ServiceGenerator")
- // abstract class Hilt_$CLASS extends $BASE {
- // ...
- // }
- 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());
-
- Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
- Processors.addGeneratedAnnotation(builder, env, getClass());
- Generators.copyLintAnnotations(metadata.element(), builder);
-
- metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEachOrdered(builder::addTypeVariable);
-
- Generators.addInjectionMethods(metadata, builder);
-
- Generators.addComponentOverride(metadata, builder);
-
- JavaFile.builder(generatedClassName.packageName(), builder.build())
- .build().writeTo(env.getFiler());
- }
-
- 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());
-
- return MethodSpec.constructorBuilder()
- .addParameters(params)
- .addStatement(
- "super($L)",
- params.stream().map(p -> p.name).collect(Collectors.joining(",")))
- .build();
- })
- .collect(Collectors.toList());
- }
-
- // @CallSuper
- // @Override
- // protected void onCreate() {
- // inject();
- // super.onCreate();
- // }
- private MethodSpec onCreateMethod() throws IOException {
- return MethodSpec.methodBuilder("onCreate")
- .addAnnotation(AndroidClassNames.CALL_SUPER)
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addStatement("inject()")
- .addStatement("super.onCreate()")
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
deleted file mode 100644
index 412b09a..0000000
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/ViewGenerator.java
+++ /dev/null
@@ -1,194 +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.androidentrypoint;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.Visibility;
-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.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.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 AndroidEntryPointMetadata metadata;
- private final ClassName generatedClassName;
-
- public ViewGenerator(ProcessingEnvironment env, AndroidEntryPointMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
-
- generatedClassName = metadata.generatedClassName();
- }
-
- // @Generated("ViewGenerator")
- // abstract class Hilt_$CLASS extends $BASE implements
- // ComponentManagerHolder<ViewComponentManager<$CLASS_EntryPoint>> {
- // ...
- // }
- public void generate() throws IOException {
- // 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
- // since the object isn't done constructing yet.
-
- TypeSpec.Builder builder =
- TypeSpec.classBuilder(generatedClassName.simpleName())
- .addOriginatingElement(metadata.element())
- .superclass(metadata.baseClassName())
- .addModifiers(metadata.generatedClassModifiers());
-
- Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
- Processors.addGeneratedAnnotation(builder, env, getClass());
- Generators.copyLintAnnotations(metadata.element(), builder);
-
- metadata.baseElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEachOrdered(builder::addTypeVariable);
-
- Generators.addComponentOverride(metadata, builder);
-
- Generators.addInjectionMethods(metadata, builder);
-
- ElementFilter.constructorsIn(metadata.baseElement().getEnclosedElements()).stream()
- .filter(this::isConstructorVisibleToGeneratedClass)
- .forEach(constructor -> builder.addMethod(constructorMethod(constructor)));
-
- JavaFile.builder(generatedClassName.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
- }
-
- private boolean isConstructorVisibleToGeneratedClass(ExecutableElement constructorElement) {
- if (Visibility.ofElement(constructorElement) == Visibility.DEFAULT
- && !isInOurPackage(constructorElement)) {
- return false;
- } else if (Visibility.ofElement(constructorElement) == Visibility.PRIVATE) {
- return false;
- }
-
- // We extend the base class, so both protected and public methods are always accessible.
- return true;
- }
-
- /**
- * Returns a pass-through constructor matching the base class's provided constructorElement. The
- * generated constructor simply calls super(), then inject().
- *
- * <p>Eg
- *
- * <pre>
- * Hilt_$CLASS(Context context, ...) {
- * super(context, ...);
- * inject();
- * }
- * </pre>
- */
- private MethodSpec constructorMethod(ExecutableElement constructorElement) {
- MethodSpec.Builder constructor =
- Generators.copyConstructor(constructorElement).toBuilder();
-
- if (isRestrictedApiConstructor(constructorElement)) {
- // 4 parameter constructors are only available on @TargetApi(21).
- constructor.addAnnotation(
- AnnotationSpec.builder(AndroidClassNames.TARGET_API).addMember("value", "21").build());
- }
-
- constructor.addStatement("inject()");
-
- return constructor.build();
- }
-
- private boolean isRestrictedApiConstructor(ExecutableElement constructor) {
- if (constructor.getParameters().size() != 4) {
- return false;
- }
-
- List<? extends VariableElement> constructorParams = constructor.getParameters();
- for (int i = 0; i < constructorParams.size(); i++) {
- TypeMirror type = constructorParams.get(i).asType();
- Element element = env.getTypeUtils().asElement(type);
- switch (i) {
- case 0:
- if (!isFirstRestrictedParameter(element)) {
- return false;
- }
- break;
- case 1:
- if (!isSecondRestrictedParameter(element)) {
- return false;
- }
- break;
- case 2:
- if (!isThirdRestrictedParameter(type)) {
- return false;
- }
- break;
- case 3:
- if (!isFourthRestrictedParameter(type)) {
- return false;
- }
- break;
- default:
- return false;
- }
- }
-
- return true;
- }
-
- private static boolean isFourthRestrictedParameter(TypeMirror type) {
- return type.getKind().isPrimitive()
- && Processors.getPrimitiveType(type).getKind() == TypeKind.INT;
- }
-
- private static boolean isThirdRestrictedParameter(TypeMirror type) {
- return type.getKind().isPrimitive()
- && Processors.getPrimitiveType(type).getKind() == TypeKind.INT;
- }
-
- private static boolean isSecondRestrictedParameter(Element element) {
- return element instanceof TypeElement
- && Processors.isAssignableFrom(
- MoreElements.asType(element), AndroidClassNames.ATTRIBUTE_SET);
- }
-
- private static boolean isFirstRestrictedParameter(Element element) {
- return element instanceof TypeElement
- && Processors.isAssignableFrom(MoreElements.asType(element), AndroidClassNames.CONTEXT);
- }
-
- private boolean isInOurPackage(ExecutableElement constructorElement) {
- return MoreElements.getPackage(constructorElement)
- .equals(MoreElements.getPackage(metadata.element()));
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD b/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
deleted file mode 100644
index cbc51b3..0000000
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BUILD
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# Description:
-# Hilt android library for binding values in test processors.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "bind_value_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.bindvalue.BindValueProcessor",
- deps = [
- ":bind_value_processor_lib",
- ],
-)
-
-java_library(
- name = "bind_value_processor_lib",
- srcs = [
- "BindValueGenerator.java",
- "BindValueMetadata.java",
- "BindValueProcessor.java",
- ],
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:components",
- "//java/dagger/hilt/processor/internal:kotlin",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
deleted file mode 100644
index 108a15d..0000000
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueGenerator.java
+++ /dev/null
@@ -1,160 +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.processor.internal.bindvalue;
-
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static java.util.Comparator.comparing;
-
-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;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.android.processor.internal.bindvalue.BindValueMetadata.BindValueElement;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Components;
-import dagger.hilt.processor.internal.Processors;
-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;
-
-/**
- * Generates a SINGLETON module for all {@code BindValue} annotated fields in a test class.
- */
-final class BindValueGenerator {
- private static final String SUFFIX = "_BindValueModule";
-
- private final ProcessingEnvironment env;
- private final BindValueMetadata metadata;
- private final ClassName testClassName;
- private final ClassName className;
-
- BindValueGenerator(ProcessingEnvironment env, BindValueMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
- testClassName = ClassName.get(metadata.testElement());
- className = Processors.append(testClassName, SUFFIX);
- }
-
- // @Module
- // @InstallIn(SingletonComponent.class)
- // public final class FooTest_BindValueModule {
- // // 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());
-
- Processors.addGeneratedAnnotation(builder, env, getClass());
-
- metadata.bindValueElements().stream()
- .map(this::providesMethod)
- .sorted(comparing(MethodSpec::toString))
- .forEachOrdered(builder::addMethod);
-
- JavaFile.builder(className.packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
- }
-
- // @Provides
- // static FooTest providesFooTest(@ApplicationContext Context context) {
- // return (FooTest)
- // ((TestApplicationComponentManager)
- // ((TestApplicationComponentManagerHolder) context).componentManager())
- // .getTestInstance();
- // }
- private MethodSpec providesTestMethod() {
- String methodName = "provides" + testClassName.simpleName();
- MethodSpec.Builder builder =
- MethodSpec.methodBuilder(methodName)
- .addAnnotation(Provides.class)
- .addModifiers(Modifier.STATIC)
- .addParameter(
- ParameterSpec.builder(ClassNames.CONTEXT, "context")
- .addAnnotation(ClassNames.APPLICATION_CONTEXT)
- .build())
- .returns(testClassName)
- .addStatement(
- "return ($T) (($T) (($T) context).componentManager()).getTestInstance()",
- testClassName,
- ClassNames.TEST_APPLICATION_COMPONENT_MANAGER,
- ClassNames.TEST_APPLICATION_COMPONENT_MANAGER_HOLDER);
- return builder.build();
- }
-
- // @Provides
- // @BarQualifier
- // static Bar providesBarQualifierBar(FooTest test) {
- // return test.bar;
- // }
- 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());
- MethodSpec.Builder builder =
- MethodSpec.methodBuilder(methodName)
- .addAnnotation(Provides.class)
- .addModifiers(Modifier.STATIC)
- .returns(ClassName.get(bindValue.variableElement().asType()));
-
- if (bindValue.variableElement().getModifiers().contains(Modifier.STATIC)) {
- builder.addStatement(
- "return $T.$L", testClassName, bindValue.variableElement().getSimpleName());
- } 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()));
- }
-
- ClassName annotationClassName = bindValue.annotationName();
- if (BindValueMetadata.BIND_VALUE_INTO_MAP_ANNOTATIONS.contains(annotationClassName)) {
- builder.addAnnotation(IntoMap.class);
- // 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()));
- } 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)));
- 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
deleted file mode 100644
index bf50288..0000000
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueMetadata.java
+++ /dev/null
@@ -1,178 +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.processor.internal.bindvalue;
-
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.value.AutoValue;
-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.KotlinMetadataUtils;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import java.util.Collection;
-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.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.
- */
-@AutoValue
-abstract class BindValueMetadata {
- static final ImmutableSet<ClassName> BIND_VALUE_ANNOTATIONS =
- ImmutableSet.of(
- ClassNames.ANDROID_BIND_VALUE);
- static final ImmutableSet<ClassName> BIND_VALUE_INTO_SET_ANNOTATIONS =
- ImmutableSet.of(
- ClassNames.ANDROID_BIND_VALUE_INTO_SET);
- static final ImmutableSet<ClassName> BIND_ELEMENTS_INTO_SET_ANNOTATIONS =
- ImmutableSet.of(
- ClassNames.ANDROID_BIND_ELEMENTS_INTO_SET);
- static final ImmutableSet<ClassName> BIND_VALUE_INTO_MAP_ANNOTATIONS =
- ImmutableSet.of(
- ClassNames.ANDROID_BIND_VALUE_INTO_MAP);
-
- /** @return the {@code TestRoot} annotated class's name. */
- abstract TypeElement 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) {
-
- ImmutableSet.Builder<BindValueElement> elements = ImmutableSet.builder();
- for (Element element : bindValueElements) {
- elements.add(BindValueElement.create(element));
- }
-
- return new AutoValue_BindValueMetadata(testElement, elements.build());
- }
-
- @AutoValue
- abstract static class BindValueElement {
- abstract VariableElement variableElement();
-
- abstract ClassName annotationName();
-
- abstract Optional<AnnotationMirror> qualifier();
-
- abstract Optional<AnnotationMirror> mapKey();
-
- abstract Optional<ExecutableElement> getterElement();
-
- static BindValueElement create(Element element) {
- ImmutableList<ClassName> bindValues = BindValueProcessor.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);
-
- ProcessorErrors.checkState(
- element.getKind() == ElementKind.FIELD,
- element,
- "@%s can only be used with fields. Found: %s",
- annotationClassName.simpleName(),
- element);
-
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- Optional<ExecutableElement> propertyGetter =
- metadataUtil.hasMetadata(element)
- ? metadataUtil.getPropertyGetter(MoreElements.asVariable(element))
- : Optional.empty();
- if (propertyGetter.isPresent()) {
- ProcessorErrors.checkState(
- !propertyGetter.get().getModifiers().contains(Modifier.PRIVATE),
- element,
- "@%s field getter cannot be private. Found: %s",
- annotationClassName.simpleName(),
- element);
- } else {
- ProcessorErrors.checkState(
- !element.getModifiers().contains(Modifier.PRIVATE),
- element,
- "@%s fields cannot be private. Found: %s",
- annotationClassName.simpleName(),
- element);
- }
-
- ProcessorErrors.checkState(
- !Processors.hasAnnotation(element, Inject.class),
- element,
- "@%s fields cannot be used with @Inject annotation. Found %s",
- annotationClassName.simpleName(),
- element);
-
- ImmutableList<AnnotationMirror> qualifiers = Processors.getQualifierAnnotations(element);
- ProcessorErrors.checkState(
- qualifiers.size() <= 1,
- element,
- "@%s fields cannot have more than one qualifier. Found %s",
- annotationClassName.simpleName(),
- qualifiers);
-
- ImmutableList<AnnotationMirror> mapKeys = Processors.getMapKeyAnnotations(element);
- Optional<AnnotationMirror> optionalMapKeys;
- if (BIND_VALUE_INTO_MAP_ANNOTATIONS.contains(annotationClassName)) {
- ProcessorErrors.checkState(
- mapKeys.size() == 1,
- element,
- "@BindValueIntoMap fields must have exactly one @MapKey. Found %s",
- mapKeys);
- optionalMapKeys = Optional.of(mapKeys.get(0));
- } else {
- ProcessorErrors.checkState(
- mapKeys.isEmpty(),
- element,
- "@MapKey can only be used on @BindValueIntoMap fields, not @%s fields",
- annotationClassName.simpleName());
- optionalMapKeys = Optional.empty();
- }
-
- ImmutableList<AnnotationMirror> scopes = Processors.getScopeAnnotations(element);
- ProcessorErrors.checkState(
- scopes.isEmpty(),
- element,
- "@%s fields cannot be scoped. Found %s",
- annotationClassName.simpleName(),
- scopes);
-
- return new AutoValue_BindValueMetadata_BindValueElement(
- (VariableElement) element,
- annotationClassName,
- qualifiers.isEmpty()
- ? Optional.<AnnotationMirror>empty()
- : Optional.<AnnotationMirror>of(qualifiers.get(0)),
- optionalMapKeys,
- propertyGetter);
- }
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java b/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java
deleted file mode 100644
index 060b077..0000000
--- a/java/dagger/hilt/android/processor/internal/bindvalue/BindValueProcessor.java
+++ /dev/null
@@ -1,113 +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.processor.internal.bindvalue;
-
-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 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();
-
- @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();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD b/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
deleted file mode 100644
index e9721d5..0000000
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/BUILD
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A processor for @dagger.hilt.android.testing.CustomTestApplication.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "CustomTestApplicationGenerator.java",
- "CustomTestApplicationMetadata.java",
- "CustomTestApplicationProcessor.java",
- ],
- deps = [
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java
deleted file mode 100644
index 51b7ef4..0000000
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationGenerator.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.processor.internal.customtestapplication;
-
-import com.squareup.javapoet.FieldSpec;
-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.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.
- */
-final class CustomTestApplicationGenerator {
- private static final ParameterSpec COMPONENT_MANAGER =
- ParameterSpec.builder(ClassNames.TEST_APPLICATION_COMPONENT_MANAGER, "componentManager")
- .build();
-
- private final ProcessingEnvironment processingEnv;
- private final CustomTestApplicationMetadata metadata;
-
- public CustomTestApplicationGenerator(
- ProcessingEnvironment 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(getComponentManagerField())
- .addMethod(getAttachBaseContextMethod())
- .addMethod(getComponentManagerMethod())
- .addMethod(getComponentMethod());
-
- Processors.addGeneratedAnnotation(
- generator, processingEnv, CustomTestApplicationProcessor.class);
-
- JavaFile.builder(metadata.appName().packageName(), generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-
- // Initialize this in attachBaseContext to not pull it into the main dex.
- /** private TestApplicationComponentManager componentManager; */
- private static FieldSpec getComponentManagerField() {
- return FieldSpec.builder(COMPONENT_MANAGER.type, COMPONENT_MANAGER.name, Modifier.PRIVATE)
- .build();
- }
-
- /**
- * Initializes application fields. These fields are initialized in attachBaseContext to avoid
- * potential multidexing issues.
- *
- * <pre><code>
- * {@literal @Override} protected void attachBaseContext(Context base) {
- * super.attachBaseContext(base);
- * componentManager = new TestApplicationComponentManager(this);
- * }
- * </code></pre>
- */
- private static MethodSpec getAttachBaseContextMethod() {
- return MethodSpec.methodBuilder("attachBaseContext")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PROTECTED, Modifier.FINAL)
- .addParameter(ClassNames.CONTEXT, "base")
- .addStatement("super.attachBaseContext(base)")
- .addStatement("$N = new $T(this)", COMPONENT_MANAGER, COMPONENT_MANAGER.type)
- .build();
- }
-
- private static MethodSpec getComponentMethod() {
- return MethodSpec.methodBuilder("generatedComponent")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .returns(TypeName.OBJECT)
- .addStatement("return $N.generatedComponent()", COMPONENT_MANAGER)
- .build();
- }
-
- private static MethodSpec getComponentManagerMethod() {
- return MethodSpec.methodBuilder("componentManager")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .returns(TypeName.OBJECT)
- .addStatement("return $N", COMPONENT_MANAGER)
- .build();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java
deleted file mode 100644
index de8e3f7..0000000
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationMetadata.java
+++ /dev/null
@@ -1,144 +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.processor.internal.customtestapplication;
-
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-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.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;
-
-/** Stores the metadata for a custom base test application. */
-@AutoValue
-abstract class CustomTestApplicationMetadata {
- /** Returns the annotated element. */
- abstract TypeElement element();
-
- /** Returns the name of the base application. */
- abstract ClassName baseAppName();
-
- /** Returns the name of the generated application */
- ClassName appName() {
- return Processors.append(
- Processors.getEnclosedClassName(ClassName.get(element())), "_Application");
- }
-
- static CustomTestApplicationMetadata of(Element element, Elements elements) {
- Preconditions.checkState(
- Processors.hasAnnotation(element, ClassNames.CUSTOM_TEST_APPLICATION),
- "The given element, %s, is not annotated with @%s.",
- element,
- ClassNames.CUSTOM_TEST_APPLICATION.simpleName());
-
- ProcessorErrors.checkState(
- MoreElements.isType(element),
- element,
- "@%s should only be used on classes or interfaces but found: %s",
- ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
- element);
-
- TypeElement baseAppElement = getBaseElement(element, elements);
-
- return new AutoValue_CustomTestApplicationMetadata(
- MoreElements.asType(element), ClassName.get(baseAppElement));
- }
-
- private static TypeElement getBaseElement(Element element, Elements elements) {
- TypeElement baseElement =
- Processors.getAnnotationClassValue(
- elements,
- Processors.getAnnotationMirror(element, ClassNames.CUSTOM_TEST_APPLICATION),
- "value");
-
- TypeElement baseSuperclassElement = baseElement;
- while (!baseSuperclassElement.getSuperclass().getKind().equals(TypeKind.NONE)) {
- ProcessorErrors.checkState(
- !Processors.hasAnnotation(baseSuperclassElement, 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);
-
- ImmutableList<VariableElement> injectFields =
- ElementFilter.fieldsIn(baseSuperclassElement.getEnclosedElements()).stream()
- .filter(field -> Processors.hasAnnotation(field, ClassNames.INJECT))
- .collect(toImmutableList());
- ProcessorErrors.checkState(
- injectFields.isEmpty(),
- element,
- "@%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);
-
- ImmutableList<ExecutableElement> injectMethods =
- ElementFilter.methodsIn(baseSuperclassElement.getEnclosedElements()).stream()
- .filter(method -> Processors.hasAnnotation(method, ClassNames.INJECT))
- .collect(toImmutableList());
- ProcessorErrors.checkState(
- injectMethods.isEmpty(),
- element,
- "@%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);
-
- ImmutableList<ExecutableElement> injectConstructors =
- ElementFilter.constructorsIn(baseSuperclassElement.getEnclosedElements()).stream()
- .filter(method -> Processors.hasAnnotation(method, ClassNames.INJECT))
- .collect(toImmutableList());
- ProcessorErrors.checkState(
- injectConstructors.isEmpty(),
- element,
- "@%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 = MoreTypes.asTypeElement(baseSuperclassElement.getSuperclass());
- }
-
- // We check this last because if the base type is a @HiltAndroidApp we'd accidentally fail
- // with this message instead of the one above when the superclass hasn't yet been generated.
- ProcessorErrors.checkState(
- Processors.isAssignableFrom(baseElement, ClassNames.APPLICATION),
- element,
- "@%s value should be an instance of %s. Found: %s",
- ClassNames.CUSTOM_TEST_APPLICATION.simpleName(),
- ClassNames.APPLICATION,
- baseElement);
-
- return baseElement;
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java b/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java
deleted file mode 100644
index fd1a6c8..0000000
--- a/java/dagger/hilt/android/processor/internal/customtestapplication/CustomTestApplicationProcessor.java
+++ /dev/null
@@ -1,46 +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.processor.internal.customtestapplication;
-
-import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
-
-import com.google.auto.service.AutoService;
-import com.google.common.collect.ImmutableSet;
-import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ClassNames;
-import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
-
-/** Processes usages of {@link dagger.hilt.android.testing.CustomTestApplication}. */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class CustomTestApplicationProcessor extends BaseProcessor {
-
- @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();
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/uninstallmodules/BUILD b/java/dagger/hilt/android/processor/internal/uninstallmodules/BUILD
deleted file mode 100644
index 73c4606..0000000
--- a/java/dagger/hilt/android/processor/internal/uninstallmodules/BUILD
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A processor for @dagger.hilt.android.testing.UninstallModules.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.uninstallmodules.UninstallModulesProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "UninstallModulesProcessor.java",
- ],
- deps = [
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/processor/internal/uninstallmodules/UninstallModulesProcessor.java b/java/dagger/hilt/android/processor/internal/uninstallmodules/UninstallModulesProcessor.java
deleted file mode 100644
index e92f0f0..0000000
--- a/java/dagger/hilt/android/processor/internal/uninstallmodules/UninstallModulesProcessor.java
+++ /dev/null
@@ -1,80 +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.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 dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import java.util.Set;
-import javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
-
-/** Validates {@link dagger.hilt.android.testing.UninstallModules} usages. */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class UninstallModulesProcessor extends BaseProcessor {
-
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- return ImmutableSet.of(ClassNames.IGNORE_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);
-
- ImmutableList<TypeElement> invalidModules =
- Processors.getAnnotationClassValues(
- getElementUtils(),
- Processors.getAnnotationMirror(element, ClassNames.IGNORE_MODULES),
- "value")
- .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.
- element,
- "@%s should only include modules annotated with both @Module and @InstallIn, but found: "
- + "%s.",
- annotation.getSimpleName(),
- invalidModules);
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD b/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
deleted file mode 100644
index b45925f..0000000
--- a/java/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ /dev/null
@@ -1,84 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# ViewModelInject processor.
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.viewmodel.ViewModelProcessor",
- deps = [":processor_lib"],
-)
-
-kt_jvm_library(
- name = "processor_lib",
- srcs = [
- "ViewModelMetadata.kt",
- "ViewModelModuleGenerator.kt",
- "ViewModelProcessor.kt",
- ],
- deps = [
- "//java/dagger/hilt/android/processor/internal:android_classnames",
- "//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/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_plugin(
- name = "validation_plugin",
- deps = [":validation_plugin_lib"],
-)
-
-kt_jvm_library(
- name = "validation_plugin_lib",
- srcs = [
- "ViewModelValidationPlugin.kt",
- ],
- deps = [
- "//:spi",
- "//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-# See: https://github.com/bazelbuild/rules_kotlin/issues/324
-alias(
- name = "libprocessor_lib-src.jar",
- actual = ":processor_lib-sources.jar",
-)
-
-alias(
- name = "libvalidation_plugin_lib-src.jar",
- actual = ":validation_plugin_lib-sources.jar",
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
deleted file mode 100644
index 789fbfe..0000000
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelMetadata.kt
+++ /dev/null
@@ -1,107 +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.processor.internal.viewmodel
-
-import com.google.auto.common.MoreElements
-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
-
-/**
- * Data class that represents a Hilt injected ViewModel
- */
-internal class ViewModelMetadata private constructor(
- val typeElement: TypeElement
-) {
- val className = ClassName.get(typeElement)
-
- val modulesClassName = ClassName.get(
- MoreElements.getPackage(typeElement).qualifiedName.toString(),
- "${className.simpleNames().joinToString("_")}_HiltModules"
- )
-
- companion object {
- internal fun create(
- processingEnv: ProcessingEnvironment,
- typeElement: TypeElement,
- ): ViewModelMetadata? {
- val types = processingEnv.typeUtils
- val elements = processingEnv.elementUtils
-
- ProcessorErrors.checkState(
- types.isSubtype(
- typeElement.asType(),
- elements.getTypeElement(AndroidClassNames.VIEW_MODEL.toString()).asType()
- ),
- 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 ->
- ProcessorErrors.checkState(
- !constructor.modifiers.contains(Modifier.PRIVATE),
- constructor,
- "@Inject annotated constructors must not be private."
- )
- }
- }
-
- ProcessorErrors.checkState(
- typeElement.nestingKind != NestingKind.MEMBER ||
- typeElement.modifiers.contains(Modifier.STATIC),
- typeElement,
- "@HiltViewModel may only be used on inner classes if they are static."
- )
-
- Processors.getScopeAnnotations(typeElement).let { scopeAnnotations ->
- ProcessorErrors.checkState(
- scopeAnnotations.isEmpty(),
- typeElement,
- "@HiltViewModel classes should not be scoped. Found: %s",
- scopeAnnotations.joinToString()
- )
- }
-
- 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
deleted file mode 100644
index 846f7d2..0000000
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelModuleGenerator.kt
+++ /dev/null
@@ -1,169 +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.processor.internal.viewmodel
-
-import com.google.auto.common.GeneratedAnnotationSpecs
-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 dagger.hilt.android.processor.internal.AndroidClassNames
-import dagger.hilt.processor.internal.ClassNames
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.SourceVersion
-import javax.lang.model.element.Modifier
-import javax.lang.model.util.Elements
-
-/**
- * Source generator to support Hilt injection of ViewModels.
- *
- * Should generate:
- * ```
- * public final class $_HiltModules {
- * @Module
- * @InstallIn(ViewModelComponent.class)
- * public static abstract class BindsModule {
- * @Binds
- * @IntoMap
- * @StringKey("pkg.$")
- * @HiltViewModelMap
- * public abstract ViewModel bind($ vm)
- * }
- * @Module
- * @InstallIn(ActivityRetainedComponent.class)
- * public static final class KeyModule {
- * @Provides
- * @IntoSet
- * @HiltViewModelMap.KeySet
- * public static String provide() {
- * return "pkg.$";
- * }
- * }
- * }
- * ```
- */
-internal class ViewModelModuleGenerator(
- private val processingEnv: ProcessingEnvironment,
- 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()
- )
- .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)
- }
-
- private fun getBindsModuleTypeSpec() = createModuleTypeSpec(
- className = "BindsModule",
- component = AndroidClassNames.VIEW_MODEL_COMPONENT
- )
- .addModifiers(Modifier.ABSTRACT)
- .addMethod(getViewModelBindsMethod())
- .build()
-
- private fun getViewModelBindsMethod() =
- MethodSpec.methodBuilder("binds")
- .addAnnotation(ClassNames.BINDS)
- .addAnnotation(ClassNames.INTO_MAP)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.STRING_KEY)
- .addMember("value", S, injectedViewModel.className.reflectionName())
- .build()
- )
- .addAnnotation(AndroidClassNames.HILT_VIEW_MODEL_MAP_QUALIFIER)
- .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .returns(AndroidClassNames.VIEW_MODEL)
- .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 getViewModelKeyProvidesMethod() =
- MethodSpec.methodBuilder("provide")
- .addAnnotation(ClassNames.PROVIDES)
- .addAnnotation(ClassNames.INTO_SET)
- .addAnnotation(AndroidClassNames.HILT_VIEW_MODEL_KEYS_QUALIFIER)
- .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
- .returns(String::class.java)
- .addStatement("return $S", injectedViewModel.className.reflectionName())
- .build()
-
- private fun createModuleTypeSpec(className: String, component: ClassName) =
- TypeSpec.classBuilder(className)
- .addOriginatingElement(injectedViewModel.typeElement)
- .addAnnotation(ClassNames.MODULE)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.INSTALL_IN)
- .addMember("value", "$T.class", component)
- .build()
- )
- .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
-
- companion object {
-
- const val L = "\$L"
- const val T = "\$T"
- 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/ViewModelProcessor.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessor.kt
deleted file mode 100644
index 97ebe52..0000000
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessor.kt
+++ /dev/null
@@ -1,64 +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.processor.internal.viewmodel
-
-import com.google.auto.common.MoreElements
-import com.google.auto.service.AutoService
-import dagger.hilt.android.processor.internal.AndroidClassNames
-import dagger.hilt.processor.internal.BaseProcessor
-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.
- */
-@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()
- }
-}
diff --git a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt b/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
deleted file mode 100644
index a8e57dc..0000000
--- a/java/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPlugin.kt
+++ /dev/null
@@ -1,92 +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.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 javax.tools.Diagnostic.Kind
-
-/**
- * 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
- // component.
- return
- }
-
- val network: ImmutableNetwork<Node, Edge> = bindingGraph.network()
- bindingGraph.dependencyEdges().forEach { edge ->
- 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)
- ) {
- diagnosticReporter.reportDependency(
- Kind.ERROR,
- edge,
- "\nInjection of an @HiltViewModel class is prohibited since it does not create a " +
- "ViewModel instance correctly.\nAccess the ViewModel via the Android APIs " +
- "(e.g. ViewModelProvider) instead." +
- "\nInjected ViewModel: ${target.key().type()}\n"
- )
- }
- }
- }
-
- private fun isHiltViewModelBinding(target: Binding): Boolean {
- // 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)
- }
-
- private fun isInternalHiltViewModelUsage(source: Node): Boolean {
- // We expect @HiltViewModel classes to be bound into a map with an @Binds like
- // @Binds
- // @IntoMap
- // @StringKey(...)
- // @HiltViewModelMap
- // abstract ViewModel bindViewModel(FooViewModel vm)
- //
- // So we check that it is a multibinding contribution with the internal qualifier.
- // 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().multibindingContributionIdentifier().isPresent()
- }
-}
diff --git a/java/dagger/hilt/android/qualifiers/ActivityContext.java b/java/dagger/hilt/android/qualifiers/ActivityContext.java
deleted file mode 100644
index cfcc40e..0000000
--- a/java/dagger/hilt/android/qualifiers/ActivityContext.java
+++ /dev/null
@@ -1,29 +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.qualifiers;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.inject.Qualifier;
-
-/** Annotation for a {@code Context} that corresponds to the activity. */
-@Qualifier
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
-public @interface ActivityContext {}
diff --git a/java/dagger/hilt/android/qualifiers/ApplicationContext.java b/java/dagger/hilt/android/qualifiers/ApplicationContext.java
deleted file mode 100644
index 226ef75..0000000
--- a/java/dagger/hilt/android/qualifiers/ApplicationContext.java
+++ /dev/null
@@ -1,26 +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.qualifiers;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-import javax.inject.Qualifier;
-
-/** Annotation for an Application Context dependency. */
-@Qualifier
-@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
-public @interface ApplicationContext {}
diff --git a/java/dagger/hilt/android/qualifiers/BUILD b/java/dagger/hilt/android/qualifiers/BUILD
deleted file mode 100644
index 26b45ec..0000000
--- a/java/dagger/hilt/android/qualifiers/BUILD
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Hilt Android qualifiers
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "qualifiers",
- srcs = [
- "ActivityContext.java",
- "ApplicationContext.java",
- ],
- deps = [
- ":package_info",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/qualifiers/package-info.java b/java/dagger/hilt/android/qualifiers/package-info.java
deleted file mode 100644
index 2cbd744..0000000
--- a/java/dagger/hilt/android/qualifiers/package-info.java
+++ /dev/null
@@ -1,18 +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.
- */
-
-/** This package contains Hilt's built-in Android {@link javax.inject.Qualifier} annotations. */
-package dagger.hilt.android.qualifiers;
diff --git a/java/dagger/hilt/android/scopes/ActivityRetainedScoped.java b/java/dagger/hilt/android/scopes/ActivityRetainedScoped.java
deleted file mode 100644
index c61325d..0000000
--- a/java/dagger/hilt/android/scopes/ActivityRetainedScoped.java
+++ /dev/null
@@ -1,30 +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.scopes;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * Scope annotation for bindings that should exist for the life of an activity, surviving
- * configuration.
- */
-@Scope
-@Retention(CLASS)
-public @interface ActivityRetainedScoped {}
diff --git a/java/dagger/hilt/android/scopes/ActivityScoped.java b/java/dagger/hilt/android/scopes/ActivityScoped.java
deleted file mode 100644
index 9f128f7..0000000
--- a/java/dagger/hilt/android/scopes/ActivityScoped.java
+++ /dev/null
@@ -1,29 +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.scopes;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * Scope annotation for bindings that should exist for the life of an activity.
- */
-@Scope
-@Retention(CLASS)
-public @interface ActivityScoped {}
diff --git a/java/dagger/hilt/android/scopes/BUILD b/java/dagger/hilt/android/scopes/BUILD
deleted file mode 100644
index e74ac9e..0000000
--- a/java/dagger/hilt/android/scopes/BUILD
+++ /dev/null
@@ -1,60 +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(default_visibility = ["//:src"])
-
-# Description:
-# Hilt scopes.
-
-android_library(
- name = "scopes",
- srcs = [
- "ActivityScoped.java",
- "FragmentScoped.java",
- "ServiceScoped.java",
- "ViewScoped.java",
- ],
- deps = [
- ":package_info",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-android_library(
- name = "activity_retained_scoped",
- srcs = ["ActivityRetainedScoped.java"],
- deps = [
- ":package_info",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-android_library(
- name = "view_model_scoped",
- srcs = ["ViewModelScoped.java"],
- deps = [
- ":package_info",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/scopes/FragmentScoped.java b/java/dagger/hilt/android/scopes/FragmentScoped.java
deleted file mode 100644
index bc6c75e..0000000
--- a/java/dagger/hilt/android/scopes/FragmentScoped.java
+++ /dev/null
@@ -1,29 +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.scopes;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * Scope annotation for bindings that should exist for the life of a fragment.
- */
-@Scope
-@Retention(CLASS)
-public @interface FragmentScoped {}
diff --git a/java/dagger/hilt/android/scopes/ServiceScoped.java b/java/dagger/hilt/android/scopes/ServiceScoped.java
deleted file mode 100644
index 84205f2..0000000
--- a/java/dagger/hilt/android/scopes/ServiceScoped.java
+++ /dev/null
@@ -1,29 +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.scopes;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * Scope annotation for bindings that should exist for the life of a service.
- */
-@Scope
-@Retention(CLASS)
-public @interface ServiceScoped {}
diff --git a/java/dagger/hilt/android/scopes/ViewModelScoped.java b/java/dagger/hilt/android/scopes/ViewModelScoped.java
deleted file mode 100644
index 8861125..0000000
--- a/java/dagger/hilt/android/scopes/ViewModelScoped.java
+++ /dev/null
@@ -1,76 +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.scopes;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import javax.inject.Scope;
-
-/**
- * Scope annotation for bindings that should exist for the life of a a single {@link
- * androidx.lifecycle.ViewModel}.
- *
- * <p>Use this scope annotation when you want to define a dependency in the {@link
- * dagger.hilt.android.components.ViewModelComponent} for which a single instance will be provided
- * across all other dependencies for a single {@link
- * dagger.hilt.android.lifecycle.HiltViewModel}-annotated {@code ViewModel}. Other {@code
- * ViewModel}s that request the scoped dependency will receive a different instance. For sharing the
- * same instance of a dependency across all {@code ViewModel}s use a scope from one of the parent
- * components of {@code dagger.hilt.android.components.ViewModelComponent}, such as {@link
- * javax.inject.Singleton} or {@link dagger.hilt.android.scopes.ActivityRetainedScoped}.
- *
- * <p>For example:
- *
- * <pre>
- * @Module
- * @InstallIn(ViewModelComponent.class)
- * public final class ViewModelMovieModule {
- * @Provides
- * @ViewModelScoped
- * public static MovieRepository provideRepo(SavedStateHandle handle) {
- * return new MovieRepository(handle.getString("movie-id"));
- * }
- * }
- *
- * public final class MovieDetailFetcher {
- * @Inject MovieDetailFetcher(MovieRepository movieRepo) {
- * // ...
- * }
- * }
- *
- * public final class MoviePosterFetcher {
- * @Inject MoviePosterFetcher(MovieRepository movieRepo) {
- * // ...
- * }
- * }
- *
- * @HiltViewModel
- * public class MovieViewModel extends ViewModel {
- * @Inject
- * public MovieViewModel(MovieDetailFetcher detailFetcher, MoviePosterFetcher posterFetcher) {
- * // Both detailFetcher and posterFetcher will contain the same instance of
- * // the MovieRepository.
- * }
- * }
- * </pre>
- *
- * @see dagger.hilt.android.lifecycle.HiltViewModel
- * @see dagger.hilt.android.components.ViewModelComponent
- */
-@Scope
-@Retention(RetentionPolicy.CLASS)
-public @interface ViewModelScoped {}
diff --git a/java/dagger/hilt/android/scopes/ViewScoped.java b/java/dagger/hilt/android/scopes/ViewScoped.java
deleted file mode 100644
index abf7c0a..0000000
--- a/java/dagger/hilt/android/scopes/ViewScoped.java
+++ /dev/null
@@ -1,32 +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.scopes;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import javax.inject.Scope;
-
-/**
- * Scope annotation for bindings that should exist for the life of a View.
- */
-@Scope
-@Retention(CLASS)
-@Target({ElementType.METHOD, ElementType.TYPE})
-public @interface ViewScoped {}
diff --git a/java/dagger/hilt/android/scopes/package-info.java b/java/dagger/hilt/android/scopes/package-info.java
deleted file mode 100644
index 6f8f989..0000000
--- a/java/dagger/hilt/android/scopes/package-info.java
+++ /dev/null
@@ -1,22 +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.
- */
-
-/**
- * This package contains Hilt's built-in Android {@link javax.inject.Scope} annotations.
- *
- * @see <a href="https://dagger.dev/hilt/components.md#component-lifetimes">Component Lifetimes</a>
- */
-package dagger.hilt.android.scopes;
diff --git a/java/dagger/hilt/android/testing/AndroidManifest.xml b/java/dagger/hilt/android/testing/AndroidManifest.xml
deleted file mode 100644
index 26ec669..0000000
--- a/java/dagger/hilt/android/testing/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.testing">
- <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/java/dagger/hilt/android/testing/BUILD b/java/dagger/hilt/android/testing/BUILD
deleted file mode 100644
index 47db287..0000000
--- a/java/dagger/hilt/android/testing/BUILD
+++ /dev/null
@@ -1,238 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# Description:
-# Testing libraries for Hilt Android.
-
-load("//:build_defs.bzl", "POM_VERSION_ALPHA")
-load("//tools:maven.bzl", "gen_maven_artifact")
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "custom_test_application",
- testonly = 1,
- srcs = ["CustomTestApplication.java"],
- exported_plugins = [
- "//java/dagger/hilt/android/processor/internal/customtestapplication:processor",
- ],
- exports = [
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager_holder",
- "//java/dagger/hilt/internal:component_manager",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-android_library(
- name = "hilt_android_test",
- testonly = 1,
- srcs = ["HiltAndroidTest.java"],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/root:plugin",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:plugin",
- "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin",
- ],
- exports = [
- ":hilt_android_rule",
- ":hilt_test_application",
- ":on_component_ready_runner",
- ":package_info",
- "//:dagger_with_compiler",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/components",
- "//java/dagger/hilt/android/internal/builders",
- "//java/dagger/hilt/android/internal/managers",
- "//java/dagger/hilt/android/internal/modules",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager_holder",
- "//java/dagger/hilt/android/internal/testing:test_injector",
- "//java/dagger/hilt/android/scopes",
- "//java/dagger/hilt/internal:component_entry_point",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:generated_entry_point",
- "//java/dagger/hilt/internal:preconditions",
- "//java/dagger/hilt/migration:disable_install_in_check",
- "@maven//:androidx_annotation_annotation",
- "@maven//:androidx_multidex_multidex",
- "@maven//:androidx_test_core",
- ],
- deps = [
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-android_library(
- name = "hilt_android_rule",
- testonly = 1,
- srcs = ["HiltAndroidRule.java"],
- deps = [
- ":package_info",
- "//java/dagger/hilt/android/internal/testing:mark_that_rules_ran_rule",
- "//java/dagger/hilt/internal:preconditions",
- "@maven//:junit_junit",
- ],
-)
-
-android_library(
- name = "hilt_test_application",
- testonly = 1,
- srcs = [
- "HiltTestApplication.java",
- ],
- deps = [
- ":on_component_ready_runner",
- ":package_info",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager_holder",
- "//java/dagger/hilt/internal:component_manager",
- "@maven//:androidx_multidex_multidex",
- ],
-)
-
-android_library(
- name = "on_component_ready_runner",
- testonly = 1,
- srcs = ["OnComponentReadyRunner.java"],
- deps = [
- ":package_info",
- "//:dagger_with_compiler",
- "//java/dagger/hilt:entry_point",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager_holder",
- "//java/dagger/hilt/internal:component_manager",
- "//java/dagger/hilt/internal:preconditions",
- "@google_bazel_common//third_party/java/auto:value",
- ],
-)
-
-android_library(
- name = "uninstall_modules",
- testonly = 1,
- srcs = ["UninstallModules.java"],
- exported_plugins = [
- "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor",
- ],
- deps = [
- ":package_info",
- ],
-)
-
-java_library(
- name = "bind_value",
- testonly = 1,
- srcs = [
- "BindElementsIntoSet.java",
- "BindValue.java",
- "BindValueIntoMap.java",
- "BindValueIntoSet.java",
- ],
- exported_plugins = [
- "//java/dagger/hilt/android/processor/internal/bindvalue:bind_value_processor",
- ],
- exports = [
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/qualifiers",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
- deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
-
-android_library(
- name = "artifact-lib",
- testonly = 1,
- tags = ["maven_coordinates=com.google.dagger:hilt-android-testing:" + POM_VERSION_ALPHA],
- exports = [
- ":bind_value",
- ":custom_test_application",
- ":hilt_android_test",
- ":package_info",
- ":uninstall_modules",
- "//java/dagger/hilt/android:artifact-lib",
- "//java/dagger/hilt/testing:test_install_in",
- ],
-)
-
-gen_maven_artifact(
- name = "artifact",
- testonly = 1,
- artifact_coordinates = "com.google.dagger:hilt-android-testing:" + POM_VERSION_ALPHA,
- artifact_name = "Hilt Android Testing",
- artifact_target = ":artifact-lib",
- artifact_target_libs = [
- "//java/dagger/hilt/android/internal/testing:mark_that_rules_ran_rule",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager",
- "//java/dagger/hilt/android/internal/testing:test_application_component_manager_holder",
- "//java/dagger/hilt/android/internal/testing:test_component_data",
- "//java/dagger/hilt/android/internal/testing:test_injector",
- "//java/dagger/hilt/android/testing:bind_value",
- "//java/dagger/hilt/android/testing:custom_test_application",
- "//java/dagger/hilt/android/testing:hilt_android_rule",
- "//java/dagger/hilt/android/testing:hilt_android_test",
- "//java/dagger/hilt/android/testing:hilt_test_application",
- "//java/dagger/hilt/android/testing:on_component_ready_runner",
- "//java/dagger/hilt/android/testing:package_info",
- "//java/dagger/hilt/testing:test_install_in",
- "//java/dagger/hilt/testing:package_info",
- "//java/dagger/hilt/android/testing:uninstall_modules",
- ],
- artifact_target_maven_deps = [
- "androidx.activity:activity",
- "androidx.annotation:annotation",
- "androidx.fragment:fragment",
- "androidx.lifecycle:lifecycle-viewmodel",
- "androidx.lifecycle:lifecycle-viewmodel-savedstate",
- "androidx.multidex:multidex",
- "androidx.test:core",
- "com.google.code.findbugs:jsr305",
- "com.google.dagger:dagger",
- "com.google.dagger:hilt-android",
- "javax.inject:javax.inject",
- "junit:junit",
- ],
- artifact_target_maven_deps_banned = [
- "com.google.guava:guava",
- "javax.annotation:jsr250-api",
- ],
- javadoc_android_api_level = 30,
- javadoc_exclude_packages = [
- "dagger.hilt.internal",
- "dagger.hilt.android.internal",
- ],
- javadoc_root_packages = [
- "dagger.hilt.android.testing",
- ],
- javadoc_srcs = [
- "//java/dagger/hilt:hilt_android_testing_filegroup",
- "//java/dagger/hilt:hilt_testing_filegroup",
- ],
- manifest = "AndroidManifest.xml",
- packaging = "aar",
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/android/testing/BindElementsIntoSet.java b/java/dagger/hilt/android/testing/BindElementsIntoSet.java
deleted file mode 100644
index 620e0c5..0000000
--- a/java/dagger/hilt/android/testing/BindElementsIntoSet.java
+++ /dev/null
@@ -1,60 +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.testing;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that can be used on a test field to contribute the value into the {@link
- * dagger.hilt.components.SingletonComponent} as an {@link
- * dagger.multibindings.ElementsIntoSet} for the given type. Example usage:
- *
- * <pre><code>
- * public class FooTest{
- * ...
- * {@literal @}BindElementsIntoSet Set<String> bindedSet = ImmutableSet.of("bar", "baz");
- * ...
- * }
- * </code></pre>
- *
- * Here, bindedSet will be accessible to the entire application for your test. This is functionally
- * equivalent to installing the following module in your test:
- *
- * <pre><code>
- * {@literal @}Module
- * {@literal @}InstallIn
- * interface MyModule {
- * {@literal @}Provides
- * {@literal @}ElementsIntoSet
- * Set<String> bindSet() {
- * return ImmutableSet.of("bar", "baz");
- * }
- * }
- * </code></pre>
- *
- * Also see {@link BindValueIntoSet}, where you can gather individual elements into one set and bind
- * it to the application.
- */
-@Retention(CLASS)
-@Target({ElementType.FIELD})
-@GeneratesRootInput
-public @interface BindElementsIntoSet {}
diff --git a/java/dagger/hilt/android/testing/BindValue.java b/java/dagger/hilt/android/testing/BindValue.java
deleted file mode 100644
index c0164f8..0000000
--- a/java/dagger/hilt/android/testing/BindValue.java
+++ /dev/null
@@ -1,43 +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.testing;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that can be used on a test field to contribute the value into the {@link
- * dagger.hilt.components.SingletonComponent}. Example usage:
- *
- * <pre><code>
- * public class FooTest{
- * ...
- * {@literal @}BindValue Bar boundBar = new Bar();
- * ...
- * }
- * </code></pre>
- *
- * Here {@code boundBar} will be accessible to the entire application for your test.
- */
-@Retention(CLASS)
-@Target({ElementType.FIELD})
-@GeneratesRootInput
-public @interface BindValue {}
diff --git a/java/dagger/hilt/android/testing/BindValueIntoMap.java b/java/dagger/hilt/android/testing/BindValueIntoMap.java
deleted file mode 100644
index b1dfcb3..0000000
--- a/java/dagger/hilt/android/testing/BindValueIntoMap.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 dagger.hilt.android.testing;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that can be used on a test field to contribute the value into the {@link
- * dagger.hilt.components.SingletonComponent} as an {@link dagger.multibindings.IntoMap}
- * for the given type. Example usage:
- *
- * <pre><code>
- * public class FooTest{
- * ...
- * {@literal @}BindValueIntoMap
- * {@literal @}MyMapKey(KEY1)
- * String boundBar = "bar";
- *
- * {@literal @}BindValueIntoMap
- * {@literal @}MyMapKey(KEY2)
- * String boundBaz = "baz";
- * ...
- * }
- * </code></pre>
- *
- * Here the map that contains all the bound elements (in this case "bar" and "baz") will be
- * accessible to the entire application for your test.
- */
-@Retention(CLASS)
-@Target({ElementType.FIELD})
-@GeneratesRootInput
-public @interface BindValueIntoMap {}
diff --git a/java/dagger/hilt/android/testing/BindValueIntoSet.java b/java/dagger/hilt/android/testing/BindValueIntoSet.java
deleted file mode 100644
index 690a55c..0000000
--- a/java/dagger/hilt/android/testing/BindValueIntoSet.java
+++ /dev/null
@@ -1,47 +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.testing;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that can be used on a test field to contribute the value into the {@link
- * dagger.hilt.components.SingletonComponent} as an {@link dagger.multibindings.IntoSet}
- * for the given type. Example usage:
- *
- * <pre><code>
- * public class FooTest{
- * ...
- * {@literal @}BindValueIntoSet String boundBar = "bar";
- * {@literal @}BindValueIntoSet String boundBaz = "baz";
- * ...
- * }
- * </code></pre>
- *
- * Here the set that contains all the bound elements (in this case "bar" and "baz") will be
- * accessible to the entire application for your test. Also see {@link BindElementsIntoSet}, where
- * you can gather individual elements into one set and bind it to the application.
- */
-@Retention(CLASS)
-@Target({ElementType.FIELD})
-@GeneratesRootInput
-public @interface BindValueIntoSet {}
diff --git a/java/dagger/hilt/android/testing/CustomTestApplication.java b/java/dagger/hilt/android/testing/CustomTestApplication.java
deleted file mode 100644
index 36a4410..0000000
--- a/java/dagger/hilt/android/testing/CustomTestApplication.java
+++ /dev/null
@@ -1,36 +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.testing;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that creates an application with the given base type that can be used for any
- * test in the given build.
- *
- * <p>This annotation is useful for creating an application that can be used with instrumentation
- * tests in gradle, since every instrumentation test must share the same application type.
- */
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface CustomTestApplication {
-
- /** Returns the base {@link android.app.Application} class. */
- Class<?> value();
-}
diff --git a/java/dagger/hilt/android/testing/HiltAndroidRule.java b/java/dagger/hilt/android/testing/HiltAndroidRule.java
deleted file mode 100644
index 32a34f7..0000000
--- a/java/dagger/hilt/android/testing/HiltAndroidRule.java
+++ /dev/null
@@ -1,79 +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.testing;
-
-import static dagger.hilt.internal.Preconditions.checkNotNull;
-
-import dagger.hilt.android.internal.testing.MarkThatRulesRanRule;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * A {@link TestRule} for Hilt that can be used with JVM or Instrumentation tests.
- *
- * <p>This rule is required. The Dagger component will not be created without this test rule.
- */
-public final class HiltAndroidRule implements TestRule {
- private final MarkThatRulesRanRule rule;
-
- /** Creates a new instance of the rules. Tests should pass {@code this}. */
- public HiltAndroidRule(Object testInstance) {
- this.rule = new MarkThatRulesRanRule(checkNotNull(testInstance));
- }
-
- @Override public Statement apply(Statement baseStatement, Description description) {
- return rule.apply(baseStatement, description);
- }
-
- /**
- * Completes Dagger injection. Must be called before accessing inject types. Must be called after
- * any non-static test module have been added. If {@link #delayComponentReady} was used, this must
- * be called after {@link #componentReady}.
- */
- public void inject() {
- rule.inject();
- }
-
- /**
- * Delays creating the component until {@link #componentReady} is called. This is only necessary
- * in the case that a dynamically bound value (e.g. configuring an @BindValue field in @Before
- * or @Test method) is requested before test case execution begins.
- *
- * <p>Examples of early binding requests include an Activity launched by a test rule, or an entry
- * points in a {@link OnComponentReadyRunner}.
- *
- * <p>If this method is called, {@link #componentReady} must be called before the test case
- * finishes.
- */
- public HiltAndroidRule delayComponentReady() {
- rule.delayComponentReady();
- return this;
- }
-
- /**
- * Completes Dagger component creation if {@link delayComponentReady} was used. Binds the current
- * value of {@link BindValue} fields. Normally this happens automatically. This method may only be
- * called if {@link delayComponentReady} was used to delay value binding.
- *
- * @return an instance of the test rule for chaining
- */
- public HiltAndroidRule componentReady() {
- rule.componentReady();
- return this;
- }
-}
diff --git a/java/dagger/hilt/android/testing/HiltAndroidTest.java b/java/dagger/hilt/android/testing/HiltAndroidTest.java
deleted file mode 100644
index fa15f92..0000000
--- a/java/dagger/hilt/android/testing/HiltAndroidTest.java
+++ /dev/null
@@ -1,31 +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.testing;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/** Annotation used for marking an Android emulator tests that require injection. */
-// Set the retention to RUNTIME because we check it via reflection in the HiltAndroidRule.
-@Retention(RUNTIME)
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface HiltAndroidTest {}
diff --git a/java/dagger/hilt/android/testing/HiltTestApplication.java b/java/dagger/hilt/android/testing/HiltTestApplication.java
deleted file mode 100644
index 97eb4cb..0000000
--- a/java/dagger/hilt/android/testing/HiltTestApplication.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 dagger.hilt.android.testing;
-
-import android.content.Context;
-import androidx.multidex.MultiDexApplication;
-import dagger.hilt.android.internal.testing.TestApplicationComponentManager;
-import dagger.hilt.android.internal.testing.TestApplicationComponentManagerHolder;
-import dagger.hilt.internal.GeneratedComponentManager;
-
-/**
- * An application that can be used for Android instrumentation or Robolectric tests using Hilt.
- */
-public final class HiltTestApplication extends MultiDexApplication
- implements GeneratedComponentManager<Object>, TestApplicationComponentManagerHolder {
-
- // This field is initialized in attachBaseContext to avoid pulling the generated component into
- // the main dex. We could possibly avoid this by class loading TestComponentDataSupplier lazily
- // rather than in the TestApplicationComponentManager constructor.
- private TestApplicationComponentManager componentManager;
-
- @Override
- protected final void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- componentManager = new TestApplicationComponentManager(this);
- }
-
- @Override
- public final Object componentManager() {
- return componentManager;
- }
-
- @Override
- public final Object generatedComponent() {
- return componentManager.generatedComponent();
- }
-}
diff --git a/java/dagger/hilt/android/testing/OnComponentReadyRunner.java b/java/dagger/hilt/android/testing/OnComponentReadyRunner.java
deleted file mode 100644
index 925a19f..0000000
--- a/java/dagger/hilt/android/testing/OnComponentReadyRunner.java
+++ /dev/null
@@ -1,112 +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.testing;
-
-import android.app.Application;
-import android.content.Context;
-import com.google.auto.value.AutoValue;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.android.internal.testing.TestApplicationComponentManagerHolder;
-import dagger.hilt.internal.GeneratedComponentManager;
-import dagger.hilt.internal.Preconditions;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Provides access to the Singleton component in tests, so that Rules can access it after custom
- * test modules have been added.
- */
-public final class OnComponentReadyRunner {
- private final List<EntryPointListener<?>> listeners = new ArrayList<>();
- private GeneratedComponentManager<?> componentManager;
- private boolean componentHostSet = false;
-
- /** Used by generated code, to notify listeners that the component has been created. */
- public void setComponentManager(GeneratedComponentManager<?> componentManager) {
- Preconditions.checkState(!componentHostSet, "Component host was already set.");
- componentHostSet = true;
- this.componentManager = componentManager;
- for (EntryPointListener<?> listener : listeners) {
- listener.deliverComponent(componentManager);
- }
- }
-
- /** Must be called on the test thread, before the Statement is evaluated. */
- public static <T> void addListener(
- Context context, Class<T> entryPoint, OnComponentReadyListener<T> listener) {
- Application application = (Application) context.getApplicationContext();
- if (application instanceof TestApplicationComponentManagerHolder) {
- TestApplicationComponentManagerHolder managerHolder =
- (TestApplicationComponentManagerHolder) application;
- OnComponentReadyRunnerHolder runnerHolder =
- (OnComponentReadyRunnerHolder) managerHolder.componentManager();
- runnerHolder.getOnComponentReadyRunner().addListenerInternal(entryPoint, listener);
- }
- }
-
- private <T> void addListenerInternal(Class<T> entryPoint, OnComponentReadyListener<T> listener) {
- if (componentHostSet) {
- // If the componentHost was already set, just call through immediately
- runListener(componentManager, entryPoint, listener);
- } else {
- listeners.add(EntryPointListener.create(entryPoint, listener));
- }
- }
-
- public boolean isEmpty() {
- return listeners.isEmpty();
- }
-
- @AutoValue
- abstract static class EntryPointListener<T> {
- static <T> EntryPointListener<T> create(
- Class<T> entryPoint, OnComponentReadyListener<T> listener) {
- return new AutoValue_OnComponentReadyRunner_EntryPointListener<T>(entryPoint, listener);
- }
-
- abstract Class<T> entryPoint();
-
- abstract OnComponentReadyListener<T> listener();
-
- private void deliverComponent(GeneratedComponentManager<?> object) {
- runListener(object, entryPoint(), listener());
- }
- }
-
- private static <T> void runListener(
- GeneratedComponentManager<?> componentManager,
- Class<T> entryPoint,
- OnComponentReadyListener<T> listener) {
- try {
- listener.onComponentReady(EntryPoints.get(componentManager, entryPoint));
- } catch (RuntimeException | Error t) {
- throw t;
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- /** Public for use by generated code and {@link TestApplicationComponentManager} */
- public interface OnComponentReadyRunnerHolder {
- OnComponentReadyRunner getOnComponentReadyRunner();
- }
-
- /** Rules should register an implementation of this to get access to the singleton component */
- public interface OnComponentReadyListener<T> {
- void onComponentReady(T entryPoint) throws Throwable;
- }
-}
diff --git a/java/dagger/hilt/android/testing/UninstallModules.java b/java/dagger/hilt/android/testing/UninstallModules.java
deleted file mode 100644
index 6480c10..0000000
--- a/java/dagger/hilt/android/testing/UninstallModules.java
+++ /dev/null
@@ -1,59 +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.testing;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
- * An annotation used to uninstall modules that have previously been installed with {@link
- * dagger.hilt.InstallIn}.
- *
- * <p>This feature should only be used in tests. It is useful for replacing production bindings with
- * fake bindings. The basic idea is to allow users to uninstall the module that provided the
- * production binding so that a fake binding can be provided by the test.
- *
- * <p>Example:
- *
- * <pre><code>
- * {@literal @}HiltAndroidTest
- * {@literal @}UninstallModules({
- * ProdFooModule.class,
- * })
- * public class MyTest {
- * {@literal @}Module
- * {@literal @}InstallIn(SingletonComponent.class)
- * interface FakeFooModule {
- * {@literal @}Binds Foo bindFoo(FakeFoo fakeFoo);
- * }
- * }
- * </code></pre>
- */
-@Target({ElementType.TYPE})
-public @interface UninstallModules {
-
- /**
- * Returns the list of classes to uninstall.
- *
- * <p>These classes must be annotated with both {@link dagger.Module} and {@link
- * dagger.hilt.InstallIn}.
- *
- * <p>Note:A module that is included as part of another module's {@link dagger.Module#includes()}
- * cannot be truly uninstalled until the including module is also uninstalled.
- */
- Class<?>[] value() default {};
-}
diff --git a/java/dagger/hilt/android/testing/package-info.java b/java/dagger/hilt/android/testing/package-info.java
deleted file mode 100644
index fae8e7d..0000000
--- a/java/dagger/hilt/android/testing/package-info.java
+++ /dev/null
@@ -1,25 +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.
- */
-
-/**
- * This package contains APIs for writing Android local or instrumentation tests with Hilt.
- *
- * @see <a href="https://dagger.dev/hilt/testing">Hilt Testing</a>
- */
-@ParametersAreNonnullByDefault
-package dagger.hilt.android.testing;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/java/dagger/hilt/codegen/BUILD b/java/dagger/hilt/codegen/BUILD
deleted file mode 100644
index c88182b..0000000
--- a/java/dagger/hilt/codegen/BUILD
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# This package contains sources used within code generated sources.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "originating_element",
- srcs = ["OriginatingElement.java"],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/originatingelement:processor",
- ],
- deps = [
- ":package_info",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/codegen/OriginatingElement.java b/java/dagger/hilt/codegen/OriginatingElement.java
deleted file mode 100644
index c53a430..0000000
--- a/java/dagger/hilt/codegen/OriginatingElement.java
+++ /dev/null
@@ -1,52 +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.codegen;
-
-/**
- * An annotation used to specify the originating element that triggered the code generation of a
- * type. This annotation should only be used on generated code and is meant to be used by code
- * generators that generate Hilt modules, entry points, etc. Failure to use this annotation may mean
- * improper test isolation for generated classes.
- *
- * <p>This annotation should be used on any generated top-level class that either contains generated
- * modules (or entry points) or contains annotations that will generate modules (or entry points).
- *
- * <p>Example: Suppose we have the following use of an annotation, {@code MyAnnotation}.
- *
- * <pre><code>
- * class Outer {
- * static class Inner {
- * {@literal @}MyAnnotation Foo foo;
- * }
- * }
- * </code></pre>
- *
- * <p>If {@code MyAnnotation} generates an entry point, it should be annotated as follows:
- *
- * <pre><code>
- * {@literal @}OriginatingElement(topLevelClass = Outer.class)
- * {@literal @}EntryPoint
- * {@literal @}InstallIn(SingletonComponent.class) {
- * ...
- * }
- * </code></pre>
- */
-// TODO(bcorso): Consider just advising/enforcing that all top-level classes use this annotation.
-public @interface OriginatingElement {
- /** Returns the top-level class enclosing the originating element. */
- Class<?> topLevelClass();
-}
diff --git a/java/dagger/hilt/codegen/package-info.java b/java/dagger/hilt/codegen/package-info.java
deleted file mode 100644
index b6bf709..0000000
--- a/java/dagger/hilt/codegen/package-info.java
+++ /dev/null
@@ -1,21 +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.
- */
-
-/**
- * This package contains APIs for code generators that produce code that will be processed by Hilt.
- */
-// TODO(danysantiago): Add documentation about other code generators that produce input for Hilt
-package dagger.hilt.codegen;
diff --git a/java/dagger/hilt/components/BUILD b/java/dagger/hilt/components/BUILD
deleted file mode 100644
index 48dc8cd..0000000
--- a/java/dagger/hilt/components/BUILD
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Hilt components
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "components",
- srcs = [
- "SingletonComponent.java",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:define_component",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/components/SingletonComponent.java b/java/dagger/hilt/components/SingletonComponent.java
deleted file mode 100644
index 07e8fe7..0000000
--- a/java/dagger/hilt/components/SingletonComponent.java
+++ /dev/null
@@ -1,25 +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.components;
-
-import dagger.hilt.DefineComponent;
-import javax.inject.Singleton;
-
-/** A Hilt component for singleton bindings. */
-@Singleton
-@DefineComponent
-public interface SingletonComponent {}
diff --git a/java/dagger/hilt/components/package-info.java b/java/dagger/hilt/components/package-info.java
deleted file mode 100644
index 3c8cb18..0000000
--- a/java/dagger/hilt/components/package-info.java
+++ /dev/null
@@ -1,22 +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.
- */
-
-/**
- * This package contains Hilt's built-in {@link dagger.Component}s.
- *
- * @see <a href="https://dagger.dev/hilt/components.md">Hilt Components</a>
- */
-package dagger.hilt.components;
diff --git a/java/dagger/hilt/internal/BUILD b/java/dagger/hilt/internal/BUILD
deleted file mode 100644
index dc245d1..0000000
--- a/java/dagger/hilt/internal/BUILD
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Internal Hilt libraries
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "generated_component",
- srcs = [
- "GeneratedComponent.java",
- ],
-)
-
-java_library(
- name = "component_manager",
- srcs = [
- "GeneratedComponentManager.java",
- "GeneratedComponentManagerHolder.java",
- ],
- exports = [
- ":preconditions",
- ":unsafe_casts",
- ],
-)
-
-java_library(
- name = "preconditions",
- srcs = [
- "Preconditions.java",
- ],
-)
-
-java_library(
- name = "unsafe_casts",
- srcs = [
- "UnsafeCasts.java",
- ],
-)
-
-java_library(
- name = "component_entry_point",
- srcs = ["ComponentEntryPoint.java"],
- deps = ["//java/dagger/hilt:generates_root_input"],
-)
-
-java_library(
- name = "generated_entry_point",
- srcs = ["GeneratedEntryPoint.java"],
- deps = ["//java/dagger/hilt:generates_root_input"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/internal/ComponentEntryPoint.java b/java/dagger/hilt/internal/ComponentEntryPoint.java
deleted file mode 100644
index 3967e1b..0000000
--- a/java/dagger/hilt/internal/ComponentEntryPoint.java
+++ /dev/null
@@ -1,35 +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.internal;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Annotation marking generated interfaces for entry points for which there is also a corresponding
- * generated Component. Component entry points differ from normal entry points in that they may be
- * filtered out in tests.
- */
-@Target(ElementType.TYPE)
-@Retention(CLASS)
-@GeneratesRootInput
-// TODO(bcorso): Rename and publicly strip these references out of hilt.
-public @interface ComponentEntryPoint {}
diff --git a/java/dagger/hilt/internal/GeneratedComponent.java b/java/dagger/hilt/internal/GeneratedComponent.java
deleted file mode 100644
index 4d85d37..0000000
--- a/java/dagger/hilt/internal/GeneratedComponent.java
+++ /dev/null
@@ -1,20 +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.internal;
-
-/** A marker interface indicating that this is a Hilt generated component. */
-public interface GeneratedComponent {}
diff --git a/java/dagger/hilt/internal/GeneratedComponentManager.java b/java/dagger/hilt/internal/GeneratedComponentManager.java
deleted file mode 100644
index bd837a3..0000000
--- a/java/dagger/hilt/internal/GeneratedComponentManager.java
+++ /dev/null
@@ -1,23 +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.internal;
-
-/** An interface that provides a managed generated component. */
-// TODO(bcorso): Consider either removing type parameter or using actual component type in usages.
-public interface GeneratedComponentManager<T> {
- T generatedComponent();
-}
diff --git a/java/dagger/hilt/internal/GeneratedComponentManagerHolder.java b/java/dagger/hilt/internal/GeneratedComponentManagerHolder.java
deleted file mode 100644
index f65e2df..0000000
--- a/java/dagger/hilt/internal/GeneratedComponentManagerHolder.java
+++ /dev/null
@@ -1,23 +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.internal;
-
-/** An interface that provides a managed generated component holder. */
-public interface GeneratedComponentManagerHolder extends GeneratedComponentManager<Object> {
-
- public GeneratedComponentManager<?> componentManager();
-}
diff --git a/java/dagger/hilt/internal/GeneratedEntryPoint.java b/java/dagger/hilt/internal/GeneratedEntryPoint.java
deleted file mode 100644
index 76319b9..0000000
--- a/java/dagger/hilt/internal/GeneratedEntryPoint.java
+++ /dev/null
@@ -1,26 +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.internal;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/** Do not use. Only for use from Hilt generators. */
-@Target(ElementType.TYPE)
-@GeneratesRootInput
-public @interface GeneratedEntryPoint {}
diff --git a/java/dagger/hilt/internal/Preconditions.java b/java/dagger/hilt/internal/Preconditions.java
deleted file mode 100644
index b2a84db..0000000
--- a/java/dagger/hilt/internal/Preconditions.java
+++ /dev/null
@@ -1,88 +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.internal;
-
-/**
- * A partial copy of Guava's {@code com.google.common.base.Preconditions} meant to be used by
- * generated code. TODO(danysantiago): Consolidate with dagger.internal.Preconditions
- */
-public final class Preconditions {
-
- /**
- * Ensures that an object reference passed as a parameter to the calling method is not null.
- *
- * @param reference an object reference
- * @return the non-null reference that was validated
- * @throws NullPointerException if {@code reference} is null
- */
- public static <T> T checkNotNull(T reference) {
- if (reference == null) {
- throw new NullPointerException();
- }
- return reference;
- }
-
- /**
- * Ensures that an object reference passed as a parameter to the calling method is not null.
- *
- * @param reference an object reference
- * @param errorMessage the exception message to use if the check fails
- * @return the non-null reference that was validated
- * @throws NullPointerException if {@code reference} is null
- */
- public static <T> T checkNotNull(T reference, String errorMessage) {
- if (reference == null) {
- throw new NullPointerException(errorMessage);
- }
- return reference;
- }
-
- /**
- * Ensures the truth of an expression involving one or more parameters to the calling method.
- *
- * @param expression a boolean expression
- * @param errorMessageTemplate a template for the exception message should the check fail. The
- * message is formed by replacing each occurrence of {@code "%s"} with the corresponding
- * argument value from {@code args}.
- * @param args the arguments to be substituted into the message template.
- * @throws IllegalArgumentException if {@code expression} is false
- */
- public static void checkArgument(
- boolean expression, String errorMessageTemplate, Object... args) {
- if (!expression) {
- throw new IllegalArgumentException(String.format(errorMessageTemplate, args));
- }
- }
-
- /**
- * Ensures the truth of an expression involving one or more parameters to the calling method.
- *
- * @param expression a boolean expression
- * @param errorMessageTemplate a template for the exception message should the check fail. The
- * message is formed by replacing each occurrence of {@code "%s"} with the corresponding
- * argument value from {@code args}.
- * @param args the arguments to be substituted into the message template.
- * @throws IllegalStateException if {@code expression} is false
- */
- public static void checkState(boolean expression, String errorMessageTemplate, Object... args) {
- if (!expression) {
- throw new IllegalStateException(String.format(errorMessageTemplate, args));
- }
- }
-
- private Preconditions() {}
-}
diff --git a/java/dagger/hilt/internal/UnsafeCasts.java b/java/dagger/hilt/internal/UnsafeCasts.java
deleted file mode 100644
index 796dfce..0000000
--- a/java/dagger/hilt/internal/UnsafeCasts.java
+++ /dev/null
@@ -1,29 +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.internal;
-
-/** Runtime utility method for performing a casting in generated code. */
-public final class UnsafeCasts {
-
- // Only used where code generations makes it safe.
- @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
- public static <T> T unsafeCast(Object obj) {
- return (T) obj;
- }
-
- private UnsafeCasts() {}
-}
diff --git a/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java b/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java
deleted file mode 100644
index 25ea704..0000000
--- a/java/dagger/hilt/internal/aliasof/AliasOfPropagatedData.java
+++ /dev/null
@@ -1,32 +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.internal.aliasof;
-
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/** An annotation used to aggregate AliasOf values in a common location. */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-public @interface AliasOfPropagatedData {
- Class<? extends Annotation> defineComponentScope();
-
- Class<? extends Annotation> alias();
-}
diff --git a/java/dagger/hilt/internal/aliasof/BUILD b/java/dagger/hilt/internal/aliasof/BUILD
deleted file mode 100644
index 3e96ed4..0000000
--- a/java/dagger/hilt/internal/aliasof/BUILD
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# The annotation for classes generated by @AliasOf.
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "aliasof",
- srcs = ["AliasOfPropagatedData.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/internal/definecomponent/BUILD b/java/dagger/hilt/internal/definecomponent/BUILD
deleted file mode 100644
index b1d56c4..0000000
--- a/java/dagger/hilt/internal/definecomponent/BUILD
+++ /dev/null
@@ -1,32 +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.
-
-# Description:
-# The annotations for classes generated by @DefineComponent and @DefineComponent.Factory.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "definecomponent",
- srcs = glob(["*.java"]),
- visibility = [
- "//java/dagger/hilt:__pkg__",
- "//java/dagger/hilt/android:__pkg__",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/internal/definecomponent/DefineComponentClasses.java b/java/dagger/hilt/internal/definecomponent/DefineComponentClasses.java
deleted file mode 100644
index 25555fb..0000000
--- a/java/dagger/hilt/internal/definecomponent/DefineComponentClasses.java
+++ /dev/null
@@ -1,46 +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.internal.definecomponent;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation used to aggregate {@link dagger.hilt.DefineComponent} types in a common location.
- *
- * <p>Note: The types are given using {@link String} rather than {@link Class} since the {@link
- * dagger.hilt.DefineComponent} type is not necessarily in the same package and not necessarily
- * public.
- */
-@Retention(CLASS)
-@Target(TYPE)
-public @interface DefineComponentClasses {
- /**
- * Returns the fully qualified name of the {@link dagger.hilt.DefineComponent} type, or an empty
- * string if it wasn't given.
- */
- String component() default "";
-
- /**
- * Returns the fully qualified name of the {@link dagger.hilt.DefineComponent.Builder} type, or an
- * empty string if it wasn't given.
- */
- String builder() default "";
-}
diff --git a/java/dagger/hilt/internal/definecomponent/DefineComponentNoParent.java b/java/dagger/hilt/internal/definecomponent/DefineComponentNoParent.java
deleted file mode 100644
index d5da760..0000000
--- a/java/dagger/hilt/internal/definecomponent/DefineComponentNoParent.java
+++ /dev/null
@@ -1,22 +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.internal.definecomponent;
-
-/** A class used by {@link DefineComponent#parent()} as the default type when no parent is given. */
-public final class DefineComponentNoParent {
- private DefineComponentNoParent() {}
-}
diff --git a/java/dagger/hilt/internal/generatesrootinput/BUILD b/java/dagger/hilt/internal/generatesrootinput/BUILD
deleted file mode 100644
index 8e54ac4..0000000
--- a/java/dagger/hilt/internal/generatesrootinput/BUILD
+++ /dev/null
@@ -1,28 +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.
-
-# Description:
-# The annotations for classes generated by @GeneratesRootInput.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "generatesrootinput",
- srcs = ["GeneratesRootInputPropagatedData.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/internal/generatesrootinput/GeneratesRootInputPropagatedData.java b/java/dagger/hilt/internal/generatesrootinput/GeneratesRootInputPropagatedData.java
deleted file mode 100644
index d4917f8..0000000
--- a/java/dagger/hilt/internal/generatesrootinput/GeneratesRootInputPropagatedData.java
+++ /dev/null
@@ -1,33 +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.internal.generatesrootinput;
-
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * An annotation used to aggregate {@link dagger.hilt.GeneratesRootInput} types in a common
- * location.
- */
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.CLASS)
-public @interface GeneratesRootInputPropagatedData {
- Class<? extends Annotation> value();
-}
diff --git a/java/dagger/hilt/migration/AliasOf.java b/java/dagger/hilt/migration/AliasOf.java
deleted file mode 100644
index b68d4f1..0000000
--- a/java/dagger/hilt/migration/AliasOf.java
+++ /dev/null
@@ -1,46 +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.migration;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Defines an alias between an existing Hilt scope and the annotated scope. For example, the
- * following code makes {@literal @}MyScope a functional replacement for {@literal @}ActivityScope.
- *
- * <p>
- *
- * <pre>
- * {@literal @}Scope
- * {@literal @}AliasOf(ActivityScope.class)
- * public {@literal @}interface MyScope{}
- * </pre>
- *
- * <p>
- */
-@Target(ElementType.ANNOTATION_TYPE)
-@Retention(RetentionPolicy.CLASS)
-@GeneratesRootInput
-public @interface AliasOf {
- /** Returns the existing Hilt scope that the annotated scope is aliasing. */
- Class<? extends Annotation> value();
-}
diff --git a/java/dagger/hilt/migration/BUILD b/java/dagger/hilt/migration/BUILD
deleted file mode 100644
index a14410d..0000000
--- a/java/dagger/hilt/migration/BUILD
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# Description:
-# Libraries for migration.
-
-package(default_visibility = ["//:src"])
-
-android_library(
- name = "alias_of",
- srcs = [
- "AliasOf.java",
- ],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/aliasof:processor",
- ],
- exports = [
- "//java/dagger/hilt/internal/aliasof",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-java_library(
- name = "disable_install_in_check",
- srcs = ["DisableInstallInCheck.java"],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/disableinstallincheck:processor",
- ],
- exports = [
- ],
- deps = [
- ":package_info",
- ],
-)
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/migration/DisableInstallInCheck.java b/java/dagger/hilt/migration/DisableInstallInCheck.java
deleted file mode 100644
index acb6252..0000000
--- a/java/dagger/hilt/migration/DisableInstallInCheck.java
+++ /dev/null
@@ -1,28 +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.migration;
-
-/**
- * Marks a {@link dagger.Module}-annotated class to allow it to have no {@link
- * dagger.hilt.InstallIn} annotation.
- *
- * <p>Use this annotation on modules to suppress the error of a missing {@link
- * dagger.hilt.InstallIn} annotation. This is useful in cases where non-Hilt Dagger code must be
- * used long-term. If the issue is widespread, consider changing the error behavior with the
- * compiler flag {@code dagger.hilt.disableModulesHaveInstallInCheck} instead.
- */
-public @interface DisableInstallInCheck {}
diff --git a/java/dagger/hilt/migration/package-info.java b/java/dagger/hilt/migration/package-info.java
deleted file mode 100644
index bc269e3..0000000
--- a/java/dagger/hilt/migration/package-info.java
+++ /dev/null
@@ -1,22 +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.
- */
-
-/**
- * This package contains APIs to help migrating a codebase to Hilt.
- *
- * @see <a href="https://dagger.dev/hilt/migration">Migration to Hilt</a>
- */
-package dagger.hilt.migration;
diff --git a/java/dagger/hilt/package-info.java b/java/dagger/hilt/package-info.java
deleted file mode 100644
index 568b060..0000000
--- a/java/dagger/hilt/package-info.java
+++ /dev/null
@@ -1,28 +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.
- */
-
-/**
- * This package contains the core APIs for Hilt.
- *
- * <p>Hilt provides a standard way to incorporate Dagger dependency injection into an Android
- * application.
- *
- * @see <a href="https://dagger.dev/hilt">Hilt Developer Docs</a>
- */
-@ParametersAreNonnullByDefault
-package dagger.hilt;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/java/dagger/hilt/processor/BUILD b/java/dagger/hilt/processor/BUILD
deleted file mode 100644
index 87adcf3..0000000
--- a/java/dagger/hilt/processor/BUILD
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Hilt android processors.
-
-load("//:build_defs.bzl", "POM_VERSION_ALPHA")
-load("//tools:maven.bzl", "gen_maven_artifact")
-
-package(default_visibility = ["//:src"])
-
-# TODO(bcorso): merge this into :artifact-lib once we remove hilt-android-compiler artifact.
-java_library(
- name = "artifact-lib-shared",
- exports = [
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
- "//java/dagger/hilt/android/processor/internal/bindvalue:bind_value_processor_lib",
- "//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib",
- "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib",
- "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
- "//java/dagger/hilt/processor/internal/aliasof:processor_lib",
- "//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
- "//java/dagger/internal/codegen:processor",
- ],
-)
-
-java_library(
- name = "artifact-lib",
- tags = ["maven_coordinates=com.google.dagger:hilt-compiler:" + POM_VERSION_ALPHA],
- visibility = ["//visibility:private"],
- exports = [
- ":artifact-lib-shared",
- ],
-)
-
-gen_maven_artifact(
- name = "artifact",
- artifact_coordinates = "com.google.dagger:hilt-compiler:" + POM_VERSION_ALPHA,
- artifact_name = "Hilt Processor",
- artifact_target = ":artifact-lib",
- artifact_target_libs = [
- "//java/dagger/hilt/android/processor/internal:android_classnames",
- "//java/dagger/hilt/android/processor/internal:utils",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:android_generators",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:compiler_options",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:metadata",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
- "//java/dagger/hilt/android/processor/internal/bindvalue:bind_value_processor_lib",
- "//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib",
- "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//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:kotlin",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
- "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
- "//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
- "//java/dagger/hilt/processor/internal/aliasof:processor_lib",
- "//java/dagger/hilt/processor/internal/definecomponent:define_components",
- "//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
- "//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
- "//java/dagger/hilt/processor/internal/root:root_metadata",
- "//java/dagger/hilt/processor/internal/root:root_type",
- ],
- 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.guava:failureaccess",
- "com.google.guava:guava",
- "com.squareup:javapoet",
- "javax.annotation:jsr250-api",
- "javax.inject:javax.inject",
- "net.ltgt.gradle.incap:incap",
- "org.jetbrains.kotlin:kotlin-stdlib",
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
- ],
- javadoc_android_api_level = 30,
- javadoc_root_packages = [
- "dagger.hilt.processor",
- "dagger.hilt.android.processor",
- ],
- javadoc_srcs = [
- "//java/dagger/hilt:hilt_processing_filegroup",
- ],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.hilt.android.shaded.auto.common.@1"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/AnnotationValues.java b/java/dagger/hilt/processor/internal/AnnotationValues.java
deleted file mode 100644
index 584d8f9..0000000
--- a/java/dagger/hilt/processor/internal/AnnotationValues.java
+++ /dev/null
@@ -1,186 +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.common.base.Preconditions.checkNotNull;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-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.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 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 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);
- }
-
- 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
deleted file mode 100644
index baff1d8..0000000
--- a/java/dagger/hilt/processor/internal/BUILD
+++ /dev/null
@@ -1,149 +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.
-
-# Description:
-# Internal code for implementing Hilt processors.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "base_processor",
- srcs = [
- "BaseProcessor.java",
- "ProcessorErrorHandler.java",
- ],
- deps = [
- ":processor_errors",
- ":processors",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "processor_errors",
- srcs = [
- "BadInputException.java",
- "ErrorTypeException.java",
- "ProcessorErrors.java",
- ],
- deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "processors",
- srcs = [
- "AnnotationValues.java",
- "Processors.java",
- ],
- deps = [
- ":classnames",
- ":kotlin",
- ":processor_errors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
- "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
- ],
-)
-
-java_library(
- name = "classnames",
- srcs = [
- "ClassNames.java",
- ],
- deps = [
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-java_library(
- name = "component_names",
- srcs = [
- "ComponentNames.java",
- ],
- deps = [
- ":processors",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-java_library(
- name = "component_descriptor",
- srcs = [
- "ComponentDescriptor.java",
- "ComponentGenerator.java",
- "ComponentTree.java",
- ],
- deps = [
- ":classnames",
- ":processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-java_library(
- name = "components",
- srcs = [
- "Components.java",
- ],
- deps = [
- ":classnames",
- ":component_descriptor",
- ":kotlin",
- ":processor_errors",
- ":processors",
- "//java/dagger/hilt/processor/internal/definecomponent:define_components",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "kotlin",
- srcs = ["KotlinMetadataUtils.java"],
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/internal/codegen/kotlin",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/BadInputException.java b/java/dagger/hilt/processor/internal/BadInputException.java
deleted file mode 100644
index d961768..0000000
--- a/java/dagger/hilt/processor/internal/BadInputException.java
+++ /dev/null
@@ -1,42 +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 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;
-
- public BadInputException(String message, Element badElement) {
- super(message);
- this.badElements = ImmutableList.of(badElement);
- }
-
- public BadInputException(String message, Iterable<? extends Element> badElements) {
- super(message);
- this.badElements = ImmutableList.copyOf(badElements);
- }
-
- public ImmutableList<Element> getBadElements() {
- return badElements;
- }
-}
diff --git a/java/dagger/hilt/processor/internal/BaseProcessor.java b/java/dagger/hilt/processor/internal/BaseProcessor.java
deleted file mode 100644
index 4961cd5..0000000
--- a/java/dagger/hilt/processor/internal/BaseProcessor.java
+++ /dev/null
@@ -1,224 +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.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;
-
- /** 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);
- }
-
- @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
deleted file mode 100644
index 234ea7b..0000000
--- a/java/dagger/hilt/processor/internal/ClassNames.java
+++ /dev/null
@@ -1,183 +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.squareup.javapoet.ClassName.get;
-
-import com.squareup.javapoet.ClassName;
-
-/** Holder for commonly used class names. */
-public final class ClassNames {
- public static final ClassName ORIGINATING_ELEMENT =
- get("dagger.hilt.codegen", "OriginatingElement");
- public static final ClassName AGGREGATED_DEPS =
- get("dagger.hilt.processor.internal.aggregateddeps", "AggregatedDeps");
- public static final ClassName GENERATED_COMPONENT =
- get("dagger.hilt.internal", "GeneratedComponent");
- public static final ClassName GENERATED_COMPONENT_MANAGER =
- get("dagger.hilt.internal", "GeneratedComponentManager");
- public static final ClassName GENERATED_COMPONENT_MANAGER_HOLDER =
- get("dagger.hilt.internal", "GeneratedComponentManagerHolder");
- public static final ClassName IGNORE_MODULES =
- get("dagger.hilt.android.testing", "UninstallModules");
-
- public static final ClassName DEFINE_COMPONENT = get("dagger.hilt", "DefineComponent");
- public static final ClassName DEFINE_COMPONENT_BUILDER =
- get("dagger.hilt", "DefineComponent", "Builder");
- public static final ClassName DEFINE_COMPONENT_NO_PARENT =
- get("dagger.hilt.internal.definecomponent", "DefineComponentNoParent");
- public static final ClassName DEFINE_COMPONENT_CLASSES =
- get("dagger.hilt.internal.definecomponent", "DefineComponentClasses");
-
- public static final ClassName ASSISTED_INJECT = get("dagger.assisted", "AssistedInject");
- public static final ClassName BINDS =
- get("dagger", "Binds");
- public static final ClassName BINDS_OPTIONAL_OF =
- get("dagger", "BindsOptionalOf");
- public static final ClassName MODULE = get("dagger", "Module");
- public static final ClassName MULTIBINDS =
- 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 STRING_KEY = get("dagger.multibindings", "StringKey");
- public static final ClassName PROVIDES =
- get("dagger", "Provides");
- public static final ClassName COMPONENT = get("dagger", "Component");
- public static final ClassName COMPONENT_BUILDER = get("dagger", "Component", "Builder");
- public static final ClassName SUBCOMPONENT = get("dagger", "Subcomponent");
- public static final ClassName SUBCOMPONENT_BUILDER =
- get("dagger", "Subcomponent", "Builder");
- public static final ClassName PRODUCTION_COMPONENT =
- get("dagger.producers", "ProductionComponent");
-
- public static final ClassName CONTRIBUTES_ANDROID_INJECTOR =
- get("dagger.android", "ContributesAndroidInjector");
-
- public static final ClassName INJECT =
- get("javax.inject", "Inject");
- public static final ClassName QUALIFIER =
- get("javax.inject", "Qualifier");
- public static final ClassName SCOPE =
- get("javax.inject", "Scope");
- public static final ClassName PROVIDER = get("javax.inject", "Provider");
- public static final ClassName DISABLE_INSTALL_IN_CHECK =
- get("dagger.hilt.migration", "DisableInstallInCheck");
- public static final ClassName ALIAS_OF = get("dagger.hilt.migration", "AliasOf");
- public static final ClassName ALIAS_OF_PROPAGATED_DATA =
- get("dagger.hilt.internal.aliasof", "AliasOfPropagatedData");
-
- public static final ClassName GENERATES_ROOT_INPUT = get("dagger.hilt", "GeneratesRootInput");
- public static final ClassName GENERATES_ROOT_INPUT_PROPAGATED_DATA =
- get("dagger.hilt.internal.generatesrootinput", "GeneratesRootInputPropagatedData");
-
- public static final ClassName ACTIVITY_SCOPED =
- get("dagger.hilt.android.scopes", "ActivityScoped");
- public static final ClassName FRAGMENT_SCOPED =
- get("dagger.hilt.android.scopes", "FragmentScoped");
- public static final ClassName SERVICE_SCOPED = get("dagger.hilt.android.scopes", "ServiceScoped");
- public static final ClassName VIEW_SCOPED = get("dagger.hilt.android.scopes", "ViewScoped");
-
- public static final ClassName INSTALL_IN =
- get("dagger.hilt", "InstallIn");
- public static final ClassName TEST_INSTALL_IN = get("dagger.hilt.testing", "TestInstallIn");
- public static final ClassName ENTRY_POINT =
- get("dagger.hilt", "EntryPoint");
- public static final ClassName ENTRY_POINTS = get("dagger.hilt", "EntryPoints");
- public static final ClassName COMPONENT_ENTRY_POINT =
- get("dagger.hilt.internal", "ComponentEntryPoint");
- public static final ClassName GENERATED_ENTRY_POINT =
- get("dagger.hilt.internal", "GeneratedEntryPoint");
- public static final ClassName UNSAFE_CASTS = get("dagger.hilt.internal", "UnsafeCasts");
- public static final ClassName ROOT_PROCESSOR =
- get("dagger.hilt.processor.internal.root", "RootProcessor");
-
- public static final ClassName SINGLETON = get("javax.inject", "Singleton");
-
- // TODO(erichang): Move these class names out when we factor out the android portion
- public static final ClassName APPLICATION = get("android.app", "Application");
- public static final ClassName MULTI_DEX_APPLICATION =
- get("androidx.multidex", "MultiDexApplication");
- public static final ClassName ANDROID_ENTRY_POINT =
- get("dagger.hilt.android", "AndroidEntryPoint");
- public static final ClassName HILT_ANDROID_APP =
- get("dagger.hilt.android", "HiltAndroidApp");
- public static final ClassName CONTEXT = get("android.content", "Context");
- public static final ClassName APPLICATION_PROVIDER =
- get("androidx.test.core.app", "ApplicationProvider");
- public static final ClassName COMPONENT_SUPPLIER =
- get("dagger.hilt.android.internal.managers", "ComponentSupplier");
- public static final ClassName APPLICATION_CONTEXT_MODULE =
- get("dagger.hilt.android.internal.modules", "ApplicationContextModule");
- public static final ClassName INTERNAL_TEST_ROOT =
- get("dagger.hilt.android.internal.testing", "InternalTestRoot");
- public static final ClassName TEST_INJECTOR =
- get("dagger.hilt.android.internal.testing", "TestInjector");
- public static final ClassName TEST_APPLICATION_INJECTOR =
- get("dagger.hilt.android.internal.testing", "TestApplicationInjector");
- public static final ClassName TEST_APPLICATION_COMPONENT_MANAGER =
- get("dagger.hilt.android.internal.testing", "TestApplicationComponentManager");
- public static final ClassName TEST_APPLICATION_COMPONENT_MANAGER_HOLDER =
- get("dagger.hilt.android.internal.testing", "TestApplicationComponentManagerHolder");
- public static final ClassName TEST_INSTANCE_HOLDER =
- get("dagger.hilt.android.internal.testing", "TestInstanceHolder");
- public static final ClassName HILT_ANDROID_TEST =
- get("dagger.hilt.android.testing", "HiltAndroidTest");
- public static final ClassName CUSTOM_TEST_APPLICATION =
- get("dagger.hilt.android.testing", "CustomTestApplication");
- public static final ClassName ON_COMPONENT_READY_RUNNER =
- get("dagger.hilt.android.testing", "OnComponentReadyRunner");
- public static final ClassName ON_COMPONENT_READY_RUNNER_HOLDER =
- get("dagger.hilt.android.testing", "OnComponentReadyRunner", "OnComponentReadyRunnerHolder");
- public static final ClassName ANDROID_BIND_VALUE =
- get("dagger.hilt.android.testing", "BindValue");
- public static final ClassName ANDROID_BIND_ELEMENTS_INTO_SET =
- get("dagger.hilt.android.testing", "BindElementsIntoSet");
- public static final ClassName ANDROID_BIND_VALUE_INTO_MAP =
- get("dagger.hilt.android.testing", "BindValueIntoMap");
- public static final ClassName ANDROID_BIND_VALUE_INTO_SET =
- get("dagger.hilt.android.testing", "BindValueIntoSet");
- public static final ClassName APPLICATION_CONTEXT =
- get("dagger.hilt.android.qualifiers", "ApplicationContext");
- public static final ClassName TEST_COMPONENT_DATA =
- get("dagger.hilt.android.internal.testing", "TestComponentData");
- public static final ClassName TEST_COMPONENT_DATA_SUPPLIER =
- get("dagger.hilt.android.internal.testing", "TestComponentDataSupplier");
-
- public static final ClassName CLASS = get("java.lang", "Class");
- public static final ClassName LIST = get("java.util", "List");
- public static final ClassName SET = get("java.util", "Set");
- public static final ClassName MAP = get("java.util", "Map");
- public static final ClassName HASH_MAP = get("java.util", "HashMap");
- public static final ClassName HASH_SET = get("java.util", "HashSet");
- public static final ClassName COLLECTIONS = get("java.util", "Collections");
- public static final ClassName ARRAYS = get("java.util", "Arrays");
-
- // Standard components
- public static final ClassName SINGLETON_COMPONENT =
- get("dagger.hilt.components", "SingletonComponent");
- public static final ClassName ACTIVITY_COMPONENT =
- get("dagger.hilt.android.components", "ActivityComponent");
-
- public static final ClassName PRECONDITIONS = get("dagger.hilt.internal", "Preconditions");
-
- public static final ClassName OBJECT = get("java.lang", "Object");
-
- // Kotlin-specific class names
- public static final ClassName KOTLIN_METADATA = get("kotlin", "Metadata");
-
- private ClassNames() {}
-}
diff --git a/java/dagger/hilt/processor/internal/ComponentDescriptor.java b/java/dagger/hilt/processor/internal/ComponentDescriptor.java
deleted file mode 100644
index 5d3cef9..0000000
--- a/java/dagger/hilt/processor/internal/ComponentDescriptor.java
+++ /dev/null
@@ -1,95 +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 com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import java.util.Optional;
-
-// TODO(bcorso): Reduce the visibility of this class and return ClassNames instead.
-// TODO(erichang): Rename this class so it doesn't conflict with
-// dagger.internal.codegen.ComponentDescriptor
-/** Represents a single component in the hierarchy. */
-@AutoValue
-public abstract class ComponentDescriptor {
- public static Builder builder() {
- return new AutoValue_ComponentDescriptor.Builder()
- .scopes(ImmutableSet.of());
- }
-
- /** Returns the {@link ClassName} for this component descriptor. */
- public abstract ClassName component();
-
- /** Returns the {@link ClassName}s for the scopes of this component descriptor. */
- public abstract ImmutableSet<ClassName> scopes();
-
- /** Returns the {@link ClassName} for the creator interface. if it exists. */
- public abstract Optional<ClassName> creator();
-
- /** Returns the {@link ClassName} for the parent, if it exists. */
- public abstract Optional<ComponentDescriptor> parent();
-
- /** Returns {@code true} if the descriptor represents a root component. */
- public boolean isRoot() {
- return !parent().isPresent();
- }
-
- /**
- * Returns {@code true} if the given {@link ComponentDescriptor} represents the same {@link
- * #component()}.
- */
- // TODO(b/144939893): Remove equals and hashcode once we have unique ComponentDescriptor instances
- @Override
- public final boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (!(obj instanceof ComponentDescriptor)) {
- return false;
- }
- ComponentDescriptor that = (ComponentDescriptor) obj;
-
- // Only check the component name, which should map 1:1 to each component descriptor created
- // by DefineComponents#componentDescriptor(Element). However, if users are building their own
- // ComponentDescriptors manually, then this might not be true. We should lock down the builder
- // method to avoid that.
- return component().equals(that.component());
- }
-
- @Override
- public final int hashCode() {
- return component().hashCode();
- }
-
- /** Builder for ComponentDescriptor. */
- @AutoValue.Builder
- public interface Builder {
- Builder component(ClassName component);
-
- Builder scopes(ImmutableSet<ClassName> scopes);
-
- Builder scopes(ClassName... scopes);
-
- Builder creator(ClassName creator);
-
- Builder parent(ComponentDescriptor parent);
-
-
- ComponentDescriptor build();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/ComponentGenerator.java b/java/dagger/hilt/processor/internal/ComponentGenerator.java
deleted file mode 100644
index 3a4bf1e..0000000
--- a/java/dagger/hilt/processor/internal/ComponentGenerator.java
+++ /dev/null
@@ -1,172 +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 dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static java.util.Comparator.comparing;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Utf8;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-
-/** Generates a Dagger component or subcomponent interface. */
-// TODO(bcorso): Make this non-public
-public final class ComponentGenerator {
- private static final Joiner JOINER = Joiner.on(".");
- private static final Comparator<ClassName> SIMPLE_NAME_SORTER =
- Comparator.comparing((ClassName c) -> JOINER.join(c.simpleNames()))
- .thenComparing(ClassName::compareTo);
- private static final Comparator<TypeName> TYPE_NAME_SORTER = comparing(TypeName::toString);
-
- private final ProcessingEnvironment processingEnv;
- private final ClassName name;
- private final TypeElement rootElement;
- private final Optional<ClassName> superclass;
- private final ImmutableList<ClassName> modules;
- private final ImmutableList<TypeName> entryPoints;
- private final ImmutableCollection<ClassName> scopes;
- private final ImmutableList<AnnotationSpec> extraAnnotations;
- private final ClassName componentAnnotation;
- private final Optional<TypeSpec> componentBuilder;
-
- public ComponentGenerator(
- ProcessingEnvironment processingEnv,
- ClassName name,
- TypeElement rootElement,
- Optional<ClassName> superclass,
- Set<? extends ClassName> modules,
- Set<? extends TypeName> entryPoints,
- ImmutableCollection<ClassName> scopes,
- ImmutableList<AnnotationSpec> extraAnnotations,
- ClassName componentAnnotation,
- Optional<TypeSpec> componentBuilder) {
- this.processingEnv = processingEnv;
- this.name = name;
- this.rootElement = rootElement;
- this.superclass = superclass;
- this.modules = modules.stream().sorted(SIMPLE_NAME_SORTER).collect(toImmutableList());
- this.entryPoints = entryPoints.stream().sorted(TYPE_NAME_SORTER).collect(toImmutableList());
- this.scopes = scopes;
- this.extraAnnotations = extraAnnotations;
- this.componentAnnotation = componentAnnotation;
- this.componentBuilder = componentBuilder;
- }
-
- public TypeSpec generate() throws IOException {
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(name)
- // Public because components from a scope below must reference to create
- .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addOriginatingElement(rootElement)
- .addAnnotation(getComponentAnnotation());
-
- componentBuilder.ifPresent(generator::addType);
-
- scopes.forEach(generator::addAnnotation);
-
- addEntryPoints(generator);
-
- superclass.ifPresent(generator::superclass);
-
- generator.addAnnotations(extraAnnotations);
-
- return generator.build();
- }
-
- /** Returns the component annotation with the list of modules to install for the component. */
- private AnnotationSpec getComponentAnnotation() {
- AnnotationSpec.Builder builder = AnnotationSpec.builder(componentAnnotation);
- modules.forEach(module -> builder.addMember("modules", "$T.class", module));
- return builder.build();
- }
-
- /**
- * Adds entry points to the component.
- *
- * See b/140979968. If the entry points exceed 65763 bytes, we have to partition them to avoid the
- * limit. To be safe, we split at 60000 bytes.
- */
- private void addEntryPoints(TypeSpec.Builder builder) throws IOException {
- int currBytes = 0;
- List<Integer> partitionIndexes = new ArrayList<>();
-
- partitionIndexes.add(0);
- for (int i = 0; i < entryPoints.size(); i++) {
- // This over estimates the actual length because it includes the fully qualified name (FQN).
- // TODO(bcorso): Have a better way to estimate the upper bound. For example, most types will
- // not include the FQN, but we'll have to consider all of the different subtypes of TypeName,
- // simple name collisions, etc...
- int nextBytes = Utf8.encodedLength(entryPoints.get(i).toString());
-
- // To be safe, we split at 60000 to account for the component name, spaces, commas, etc...
- if (currBytes + nextBytes > 60000) {
- partitionIndexes.add(i);
- currBytes = 0;
- }
-
- currBytes += nextBytes;
- }
- partitionIndexes.add(entryPoints.size());
-
- if (partitionIndexes.size() <= 2) {
- // No extra partitions are needed, so just add all of the entrypoints as is.
- builder.addSuperinterfaces(entryPoints);
- } else {
- // Create interfaces for each partition.
- // The partitioned interfaces will be added to the component instead of the real entry points.
- for (int i = 1; i < partitionIndexes.size(); i++) {
- int startIndex = partitionIndexes.get(i - 1);
- int endIndex = partitionIndexes.get(i);
- builder.addSuperinterface(
- createPartitionInterface(entryPoints.subList(startIndex, endIndex), i));
- }
- }
- }
-
- private ClassName createPartitionInterface(List<TypeName> partition, int partitionIndex)
- throws IOException {
- // TODO(bcorso): Nest the partion inside the HiltComponents wrapper rather than appending name
- ClassName partitionName =
- Processors.append(
- Processors.getEnclosedClassName(name), "_EntryPointPartition" + partitionIndex);
- TypeSpec.Builder builder =
- TypeSpec.interfaceBuilder(partitionName)
- .addOriginatingElement(rootElement)
- .addModifiers(Modifier.ABSTRACT)
- .addSuperinterfaces(partition);
-
- Processors.addGeneratedAnnotation(builder, processingEnv, ClassNames.ROOT_PROCESSOR.toString());
-
- JavaFile.builder(name.packageName(), builder.build()).build().writeTo(processingEnv.getFiler());
- return partitionName;
- }
-}
diff --git a/java/dagger/hilt/processor/internal/ComponentNames.java b/java/dagger/hilt/processor/internal/ComponentNames.java
deleted file mode 100644
index fab4d19..0000000
--- a/java/dagger/hilt/processor/internal/ComponentNames.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal;
-
-import com.squareup.javapoet.ClassName;
-
-/**
- * Utility class for getting the generated component name.
- *
- * <p>This should not be used externally.
- */
-public final class ComponentNames {
- private ComponentNames() {}
-
- /** Returns the name of the generated component wrapper. */
- public static ClassName generatedComponentsWrapper(ClassName root) {
- return Processors.append(Processors.getEnclosedClassName(root), "_HiltComponents");
- }
-
- /** Returns the name of the generated component. */
- public static ClassName generatedComponent(ClassName root, ClassName component) {
- return generatedComponentsWrapper(root).nestedClass(componentName(component));
- }
-
- /**
- * Returns the shortened component name by replacing the ending "Component" with "C" if it exists.
- *
- * <p>This is a hack because nested subcomponents in Dagger generate extremely long class names
- * that hit the 256 character limit.
- */
- // TODO(bcorso): See if this issue can be fixed in Dagger, e.g. by using static subcomponents.
- private static String componentName(ClassName component) {
- // TODO(bcorso): How do we want to handle collisions across packages? Currently, we only handle
- // collisions across enclosing elements since namespacing by package would likely lead to too
- // long of class names.
- // Note: This uses regex matching so we only match if the name ends in "Component"
- return Processors.getEnclosedName(component).replaceAll("Component$", "C");
- }
-}
diff --git a/java/dagger/hilt/processor/internal/ComponentTree.java b/java/dagger/hilt/processor/internal/ComponentTree.java
deleted file mode 100644
index 6d2137a..0000000
--- a/java/dagger/hilt/processor/internal/ComponentTree.java
+++ /dev/null
@@ -1,106 +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 dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
-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.graph.GraphBuilder;
-import com.google.common.graph.Graphs;
-import com.google.common.graph.ImmutableGraph;
-import com.google.common.graph.MutableGraph;
-import com.squareup.javapoet.ClassName;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/** A representation of the full tree of scopes. */
-public final class ComponentTree {
- private final ImmutableGraph<ComponentDescriptor> graph;
- private final ComponentDescriptor root;
-
- /** Creates a new tree from a set of descriptors. */
- public static ComponentTree from(Set<ComponentDescriptor> descriptors) {
- MutableGraph<ComponentDescriptor> graph =
- GraphBuilder.directed().allowsSelfLoops(false).build();
-
- descriptors.forEach(
- descriptor -> {
- graph.addNode(descriptor);
- descriptor.parent().ifPresent(parent -> graph.putEdge(parent, descriptor));
- });
-
- return new ComponentTree(ImmutableGraph.copyOf(graph));
- }
-
- private ComponentTree(ImmutableGraph<ComponentDescriptor> graph) {
- this.graph = Preconditions.checkNotNull(graph);
- Preconditions.checkState(
- !Graphs.hasCycle(graph),
- "Component graph has cycles: %s",
- graph.nodes());
-
- // Check that each component has a unique descriptor
- Map<ClassName, ComponentDescriptor> descriptors = new HashMap<>();
- for (ComponentDescriptor descriptor : graph.nodes()) {
- if (descriptors.containsKey(descriptor.component())) {
- ComponentDescriptor prevDescriptor = descriptors.get(descriptor.component());
- Preconditions.checkState(
- // TODO(b/144939893): Use "==" instead of ".equals()"?
- descriptor.equals(prevDescriptor),
- "%s has mismatching descriptors:\n"
- + " %s\n\n"
- + " %s\n\n",
- prevDescriptor.component(),
- prevDescriptor,
- descriptor);
- }
- descriptors.put(descriptor.component(), descriptor);
- }
-
- ImmutableList<ComponentDescriptor> roots =
- graph.nodes().stream()
- .filter(node -> graph.inDegree(node) == 0)
- .collect(toImmutableList());
-
- Preconditions.checkState(
- roots.size() == 1,
- "Component graph must have exactly 1 root. Found: %s",
- roots.stream().map(ComponentDescriptor::component).collect(toImmutableList()));
-
- root = Iterables.getOnlyElement(roots);
- }
-
- public ImmutableSet<ComponentDescriptor> getComponentDescriptors() {
- return ImmutableSet.copyOf(graph.nodes());
- }
-
- public ImmutableSet<ComponentDescriptor> childrenOf(ComponentDescriptor componentDescriptor) {
- return ImmutableSet.copyOf(graph.successors(componentDescriptor));
- }
-
- public ImmutableGraph<ComponentDescriptor> graph() {
- return graph;
- }
-
- public ComponentDescriptor root() {
- return root;
- }
-}
diff --git a/java/dagger/hilt/processor/internal/Components.java b/java/dagger/hilt/processor/internal/Components.java
deleted file mode 100644
index 661dd8a..0000000
--- a/java/dagger/hilt/processor/internal/Components.java
+++ /dev/null
@@ -1,122 +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 dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.definecomponent.DefineComponents;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-
-/** 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) {
- ImmutableSet<ClassName> components;
- if (Processors.hasAnnotation(element, ClassNames.INSTALL_IN)
- || Processors.hasAnnotation(element, ClassNames.TEST_INSTALL_IN)) {
- components = getHiltInstallInComponents(elements, 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();
- if (enclosing != null
- && MoreElements.isType(enclosing)
- && MoreElements.isType(element)
- && Processors.hasAnnotation(enclosing, ClassNames.MODULE)
- && KotlinMetadataUtils.getMetadataUtil().isCompanionObjectClass(
- MoreElements.asType(element))) {
- return getComponents(elements, enclosing);
- }
- if (Processors.hasErrorTypeAnnotation(element)) {
- throw new BadInputException(
- "Error annotation found on element " + element + ". Look above for compilation errors",
- element);
- } else {
- throw new BadInputException(
- String.format(
- "An @InstallIn annotation is required for: %s." ,
- element),
- element);
- }
- }
-
- return components;
- }
-
- public static AnnotationSpec getInstallInAnnotationSpec(ImmutableSet<ClassName> components) {
- Preconditions.checkArgument(!components.isEmpty());
- AnnotationSpec.Builder builder = AnnotationSpec.builder(ClassNames.INSTALL_IN);
- components.forEach(component -> builder.addMember("value", "$T.class", component));
- return builder.build();
- }
-
- private static ImmutableSet<ClassName> getHiltInstallInComponents(
- Elements elements, Element element) {
- Preconditions.checkArgument(
- Processors.hasAnnotation(element, ClassNames.INSTALL_IN)
- || Processors.hasAnnotation(element, 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"));
-
- ImmutableSet<TypeElement> undefinedComponents =
- components.stream()
- .filter(component -> !Processors.hasAnnotation(component, ClassNames.DEFINE_COMPONENT))
- .collect(toImmutableSet());
-
- ProcessorErrors.checkState(
- undefinedComponents.isEmpty(),
- element,
- "@InstallIn, can only be used with @DefineComponent-annotated classes, but found: %s",
- undefinedComponents);
-
- return components.stream().map(ClassName::get).collect(toImmutableSet());
- }
-
- private Components() {}
-}
diff --git a/java/dagger/hilt/processor/internal/ErrorTypeException.java b/java/dagger/hilt/processor/internal/ErrorTypeException.java
deleted file mode 100644
index 6f8f67e..0000000
--- a/java/dagger/hilt/processor/internal/ErrorTypeException.java
+++ /dev/null
@@ -1,37 +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 javax.lang.model.element.Element;
-
-/**
- * Exception to throw when a required {@link Element} is or inherits from an error kind.
- *
- * <p>Includes element to point to for the cause of the error
- */
-public final class ErrorTypeException extends RuntimeException {
- private final Element badElement;
-
- public ErrorTypeException(String message, Element badElement) {
- super(message);
- this.badElement = badElement;
- }
-
- public Element getBadElement() {
- return badElement;
- }
-}
diff --git a/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java b/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java
deleted file mode 100644
index ec5ddf8..0000000
--- a/java/dagger/hilt/processor/internal/KotlinMetadataUtils.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal;
-
-import dagger.Component;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import javax.inject.Singleton;
-
-/** A single-use provider of {@link KotlinMetadataUtil}. */
-// TODO(erichang): Revert this, should be wrapped with a Dagger module.
-public final class KotlinMetadataUtils {
-
- @Singleton
- @Component
- interface MetadataComponent {
- KotlinMetadataUtil get();
- }
-
- /** Gets the metadata util. */
- public static KotlinMetadataUtil getMetadataUtil() {
- return DaggerKotlinMetadataUtils_MetadataComponent.create().get();
- }
-
- private KotlinMetadataUtils() {}
-}
diff --git a/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java b/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java
deleted file mode 100644
index 460e8a9..0000000
--- a/java/dagger/hilt/processor/internal/ProcessorErrorHandler.java
+++ /dev/null
@@ -1,123 +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 com.google.auto.common.MoreElements;
-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";
-
- // 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
- // symbols when we can't generate code.
- 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;
-
- ProcessorErrorHandler(ProcessingEnvironment env) {
- this.messager = env.getMessager();
- this.elements = env.getElementUtils();
- this.hiltErrors = new ArrayList<>();
- }
-
- /**
- * Records an error message for some exception to the messager. This can be used to handle
- * exceptions gracefully that would otherwise be propagated out of the {@code process} method. The
- * message is stored in order to allow the build to continue as far as it can. The build will be
- * failed with a {@link Kind#ERROR} in {@link #checkErrors} if an error was recorded with this
- * method.
- */
- void recordError(Throwable t) {
- // Store messages to allow the build to continue as far as it can. The build will
- // be failed in checkErrors when processing is over.
-
- if (t instanceof BadInputException) {
- BadInputException badInput = (BadInputException) t;
- for (Element element : badInput.getBadElements()) {
- hiltErrors.add(HiltError.of(badInput.getMessage(), element));
- }
- } else if (t instanceof ErrorTypeException) {
- ErrorTypeException badInput = (ErrorTypeException) t;
- hiltErrors.add(HiltError.of(badInput.getMessage(), badInput.getBadElement()));
- } else if (t.getMessage() != null) {
- hiltErrors.add(HiltError.of(t.getMessage() + ": " + Throwables.getStackTraceAsString(t)));
- } else {
- hiltErrors.add(HiltError.of(t.getClass() + ": " + Throwables.getStackTraceAsString(t)));
- }
- }
-
- /** Checks for any recorded errors. This should be called at the end of process every round. */
- void checkErrors() {
- if (!hiltErrors.isEmpty()) {
- hiltErrors.forEach(
- hiltError -> {
- if (hiltError.element().isPresent()) {
- Element element = hiltError.element().get();
- if (MoreElements.isType(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());
- }
- messager.printMessage(Kind.ERROR, hiltError.message(), element);
- } else {
- messager.printMessage(Kind.ERROR, hiltError.message());
- }
- });
- hiltErrors.clear();
- }
- }
-
- @AutoValue
- abstract static class HiltError {
- static HiltError of(String message) {
- return of(message, Optional.empty());
- }
-
- static HiltError of(String message, Element element) {
- return of(message, Optional.of(element));
- }
-
- private static HiltError of(String message, Optional<Element> element) {
- return new AutoValue_ProcessorErrorHandler_HiltError(
- FAILURE_PREFIX + message + FAILURE_SUFFIX, element);
- }
-
- abstract String message();
-
- abstract Optional<Element> element();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/ProcessorErrors.java b/java/dagger/hilt/processor/internal/ProcessorErrors.java
deleted file mode 100644
index b1578da..0000000
--- a/java/dagger/hilt/processor/internal/ProcessorErrors.java
+++ /dev/null
@@ -1,164 +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 com.google.auto.common.MoreTypes;
-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 {
- /**
- * Ensures the truth of an expression involving the state of the calling instance, but not
- * involving any parameters to the calling method.
- *
- * @param expression a boolean expression
- * @param badElement the element that was at fault
- * @param errorMessage the exception message to use if the check fails; will be converted to a
- * string using {@link String#valueOf(Object)}
- * @throws BadInputException if {@code expression} is false
- */
- public static void checkState(
- boolean expression,
- Element badElement,
- @Nullable Object errorMessage) {
- Preconditions.checkNotNull(badElement);
- if (!expression) {
- throw new BadInputException(String.valueOf(errorMessage), badElement);
- }
- }
-
- /**
- * Ensures the truth of an expression involving the state of the calling instance, but not
- * involving any parameters to the calling method.
- *
- * <p>e.g. checkState(foo.isABar(), "Failed because of %s is not a bar", foo);
- *
- * @param expression a boolean expression
- * @param badElement the element that was 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
- * argument. These are matched by position - the first {@code %s} gets {@code
- * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
- * square braces. Unmatched placeholders will be left as-is.
- * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
- * are converted to strings using {@link String#valueOf(Object)}.
- * @throws BadInputException if {@code expression} is false
- * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
- * {@code errorMessageArgs} is null (don't let this happen)
- */
- @FormatMethod
- public static void checkState(
- boolean expression,
- Element badElement,
- @Nullable @FormatString String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
- Preconditions.checkNotNull(badElement);
- if (!expression) {
- throw new BadInputException(
- String.format(errorMessageTemplate, errorMessageArgs), badElement);
- }
- }
-
- /**
- * 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 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
- * argument. These are matched by position - the first {@code %s} gets {@code
- * errorMessageArgs[0]}, etc. Unmatched arguments will be appended to the formatted message in
- * square braces. Unmatched placeholders will be left as-is.
- * @param errorMessageArgs the arguments to be substituted into the message template. Arguments
- * are converted to strings using {@link String#valueOf(Object)}.
- * @throws BadInputException if {@code expression} is false
- * @throws NullPointerException if the check fails and either {@code errorMessageTemplate} or
- * {@code errorMessageArgs} is null (don't let this happen)
- */
- @FormatMethod
- public static void checkState(
- boolean expression,
- Collection<? extends Element> badElements,
- @Nullable @FormatString String errorMessageTemplate,
- @Nullable Object... errorMessageArgs) {
- Preconditions.checkNotNull(badElements);
- if (!expression) {
- Preconditions.checkState(!badElements.isEmpty());
- throw new BadInputException(
- String.format(errorMessageTemplate, errorMessageArgs), badElements);
- }
- }
-
- /**
- * 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
deleted file mode 100644
index b33c19d..0000000
--- a/java/dagger/hilt/processor/internal/Processors.java
+++ /dev/null
@@ -1,940 +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.MoreElements.asPackage;
-import static com.google.auto.common.MoreElements.asVariable;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.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 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.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.extension.DaggerStreams;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import java.lang.annotation.Annotation;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-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.inject.Qualifier;
-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 {
-
- public static final String CONSTRUCTOR_NAME = "<init>";
-
- public static final String STATIC_INITIALIZER_NAME = "<clinit>";
-
- private static final String JAVA_CLASS = "java.lang.Class";
-
- /** 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());
- }
- 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);
-
- ProcessorErrors.checkState(
- values.size() >= 1,
- // TODO(b/152801981): Point to the annotation value rather than the annotated element.
- annotation.getAnnotationType().asElement(),
- "@%s, '%s' class is invalid or missing: %s",
- annotation.getAnnotationType().asElement().getSimpleName(),
- key,
- 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());
- }
-
- @Override
- public DeclaredType visitDeclared(DeclaredType type, Void unused) {
- return type;
- }
-
- @Override
- public DeclaredType visitError(ErrorType type, Void unused) {
- return type;
- }
- },
- null /* the Void accumulator */));
- }
-
- /**
- * 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));
- }
-
- /** 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) {
- 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()) {
- if (isTopLevel(e)) {
- return MoreElements.asType(e);
- }
- }
- throw new IllegalStateException("Cannot find a top-level type for " + 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;
- }
-
- /** Returns true if the given element has an annotation with the given class name. */
- public static boolean hasAnnotation(Element element, ClassName className) {
- 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) {
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Returns all elements in the round that are annotated with at least 1 of the given
- * annotations.
- */
- @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();
- }
-
- /**
- * Returns the name of a class, including prefixing with enclosing class names. i.e. for inner
- * class Foo enclosed by Bar, returns Bar_Foo instead of just Foo
- */
- public static String getEnclosedName(ClassName name) {
- 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 _}.
- */
- public static ClassName getEnclosedClassName(ClassName className) {
- return ClassName.get(className.packageName(), getEnclosedName(className));
- }
-
- /** Returns the fully qualified class name, with _ instead of . */
- public static String getFullyQualifiedEnclosedClassName(ClassName className) {
- return className.packageName().replace('.', '_') + getEnclosedName(className);
- }
-
- /**
- * Returns the fully qualified class name, with _ instead of . For elements that are not type
- * elements, this continues to append the simple name of elements. For example,
- * foo_bar_Outer_Inner_fooMethod.
- */
- public static String getFullEnclosedName(Element element) {
- Preconditions.checkNotNull(element);
- String qualifiedName = "";
- while (element != null) {
- if (element.getKind().equals(ElementKind.PACKAGE)) {
- qualifiedName = asPackage(element).getQualifiedName() + 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;
- }
- }
- element = element.getEnclosingElement();
- }
- return qualifiedName.replace('.', '_');
- }
-
- /** Appends the given string to the end of the class name. */
- public static ClassName append(ClassName name, String suffix) {
- return name.peerClass(name.simpleName() + suffix);
- }
-
- /** Prepends the given string to the beginning of the class name. */
- public static ClassName prepend(ClassName name, String prefix) {
- return name.peerClass(prefix + name.simpleName());
- }
-
- /**
- * Removes the string {@code suffix} from the simple name of {@code type} and returns it.
- *
- * @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);
- String originalSimpleName = originalName.simpleName();
- 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));
- }
-
- /** @see #getAnnotationMirror(Element, ClassName) */
- public static AnnotationMirror getAnnotationMirror(Element element, String annotationClassName) {
- return getAnnotationMirror(element, ClassName.bestGuess(annotationClassName));
- }
-
- /**
- * 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) {
- 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) {
- for (ClassName className : classNames) {
- if (ClassName.get(element).equals(className)) {
- return true;
- }
- }
-
- TypeMirror 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)) {
- return true;
- }
- }
-
- for (TypeMirror iface : element.getInterfaces()) {
- // Skip errors and keep looking. This is especially needed for classes generated by this
- // processor.
- if (iface.getKind() == TypeKind.ERROR) {
- continue;
- }
- Preconditions.checkState(iface.getKind() == TypeKind.DECLARED,
- "Interface type is %s", iface.getKind());
- if (isAssignableFromAnyOf(MoreTypes.asTypeElement(iface), classNames)) {
- return true;
- }
- }
-
- 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) {
- return getAnnotationsAnnotatedWith(element, ClassName.get("dagger", "MapKey"));
- }
-
- /** 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, Qualifier.class);
- 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, Qualifier.class)
- .stream())
- .map(AnnotationMirrors.equivalence()::wrap)
- .distinct()
- .map(Wrapper::get)
- .collect(DaggerStreams.toImmutableList());
- } else {
- return ImmutableList.copyOf(qualifiers);
- }
- }
-
- /** 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();
- }
-
- /**
- * Shortcut for converting from upper camel to lower camel case
- *
- * <p>Example: "SomeString" => "someString"
- */
- public static String upperToLowerCamel(String upperCamel) {
- return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, upperCamel);
- }
-
- /** @return copy of the given MethodSpec as {@link MethodSpec.Builder} with method body removed */
- public static MethodSpec.Builder copyMethodSpecWithoutBody(MethodSpec methodSpec) {
- MethodSpec.Builder builder;
-
- if (methodSpec.isConstructor()) {
- // Constructors cannot have return types
- builder = MethodSpec.constructorBuilder();
- } else {
- builder = MethodSpec.methodBuilder(methodSpec.name)
- .returns(methodSpec.returnType);
- }
-
- return builder
- .addAnnotations(methodSpec.annotations)
- .addModifiers(methodSpec.modifiers)
- .addParameters(methodSpec.parameters)
- .addExceptions(methodSpec.exceptions)
- .addJavadoc(methodSpec.javadoc.toString())
- .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).
- */
- 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 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) {
- // 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));
- }
-
- 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);
- }
-
- public static void addGeneratedAnnotation(
- TypeSpec.Builder typeSpecBuilder, ProcessingEnvironment 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()));
- }
-
- public static AnnotationSpec getOriginatingElementAnnotation(TypeElement element) {
- TypeName rawType = rawTypeName(ClassName.get(getTopLevelType(element)));
- return AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
- .addMember("topLevelClass", "$T.class", rawType)
- .build();
- }
-
- /**
- * Returns the {@link TypeName} for the raw type of the given type name. If the argument isn't a
- * parameterized type, it returns the argument unchanged.
- */
- public static TypeName rawTypeName(TypeName typeName) {
- return (typeName instanceof ParameterizedTypeName)
- ? ((ParameterizedTypeName) typeName).rawType
- : typeName;
- }
-
- private Processors() {}
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDeps.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDeps.java
deleted file mode 100644
index cc955ef..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDeps.java
+++ /dev/null
@@ -1,42 +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.aggregateddeps;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Retention;
-
-// TODO(bcorso): Change this API to clearly represent that each AggeregatedDeps should only contain
-// a single module, entry point, or component entry point.
-/** Annotation for propagating dependency information through javac runs. */
-@Retention(CLASS)
-public @interface AggregatedDeps {
- /** Returns the components that this dependency will be installed in. */
- String[] components();
-
- /** Returns the test this dependency is associated with, otherwise an empty string. */
- String test() default "";
-
- /** Returns the deps that this dep replaces. */
- String[] replaces() default {};
-
- String[] modules() default {};
-
- String[] entryPoints() default {};
-
- String[] componentEntryPoints() default {};
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java
deleted file mode 100644
index bcc2dfe..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsGenerator.java
+++ /dev/null
@@ -1,86 +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.aggregateddeps;
-
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import java.util.Optional;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
-
-/**
- * Generates the @AggregatedDeps annotated class used to pass information
- * about modules and entry points through multiple javac runs.
- */
-final class AggregatedDepsGenerator {
- static final String AGGREGATING_PACKAGE = "hilt_aggregated_deps";
- private static final ClassName AGGREGATED_DEPS =
- ClassName.get("dagger.hilt.processor.internal.aggregateddeps", "AggregatedDeps");
-
- private final String dependencyType;
- private final TypeElement 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,
- Optional<ClassName> testName,
- ImmutableSet<ClassName> components,
- ImmutableSet<ClassName> replacedDependencies,
- ProcessingEnvironment processingEnv) {
- this.dependencyType = dependencyType;
- this.dependency = dependency;
- this.testName = testName;
- this.components = components;
- this.replacedDependencies = replacedDependencies;
- this.processingEnv = processingEnv;
- }
-
- void generate() throws IOException {
- ClassName name =
- ClassName.get(
- AGGREGATING_PACKAGE, Processors.getFullEnclosedName(dependency) + "ModuleDeps");
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(name.simpleName())
- .addOriginatingElement(dependency)
- .addAnnotation(aggregatedDepsAnnotation())
- .addJavadoc("Generated class to pass information through multiple javac runs.\n");
-
- Processors.addGeneratedAnnotation(generator, processingEnv, getClass());
-
- JavaFile.builder(name.packageName(), generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-
- private AnnotationSpec aggregatedDepsAnnotation() {
- AnnotationSpec.Builder annotationBuilder = AnnotationSpec.builder(AGGREGATED_DEPS);
- components.forEach(component -> annotationBuilder.addMember("components", "$S", component));
- replacedDependencies.forEach(dep -> annotationBuilder.addMember("replaces", "$S", dep));
- testName.ifPresent(test -> annotationBuilder.addMember("test", "$S", test));
- annotationBuilder.addMember(dependencyType, "$S", dependency.getQualifiedName());
- return annotationBuilder.build();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
deleted file mode 100644
index 58c938f..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
+++ /dev/null
@@ -1,469 +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.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.android.processor.internal.androidentrypoint.HiltCompilerOptions.BooleanOption.DISABLE_MODULES_HAVE_INSTALL_IN_CHECK;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.lang.model.element.ElementKind.CLASS;
-import static javax.lang.model.element.ElementKind.INTERFACE;
-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 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.KotlinMetadataUtils;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-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.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<>();
-
- @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/compiler-options#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(
- !daggerRequiresModuleInstance(module) || 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 = 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(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 -> 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);
- }
-
- 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);
-
- 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 = getOriginatingTestElement(element).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 Optional<TypeElement> getOriginatingTestElement(Element element) {
- TypeElement topLevelType = getOriginatingTopLevelType(element);
- return Processors.hasAnnotation(topLevelType, ClassNames.HILT_ANDROID_TEST)
- ? Optional.of(asType(topLevelType))
- : Optional.empty();
- }
-
- private TypeElement getOriginatingTopLevelType(Element element) {
- TypeElement topLevelType = Processors.getTopLevelType(element);
- if (Processors.hasAnnotation(topLevelType, ClassNames.ORIGINATING_ELEMENT)) {
- return getOriginatingTopLevelType(
- Processors.getAnnotationClassValue(
- getElementUtils(),
- Processors.getAnnotationMirror(topLevelType, ClassNames.ORIGINATING_ELEMENT),
- "topLevelClass"));
- }
- return topLevelType;
- }
-
- private static boolean isValidKind(Element element) {
- // don't go down the rabbit hole of analyzing undefined types. N.B. we don't issue
- // an error here because javac already has and we don't want to spam the user.
- return element.asType().getKind() != TypeKind.ERROR;
- }
-
- private boolean installInCheckDisabled(Element element) {
- return DISABLE_MODULES_HAVE_INSTALL_IN_CHECK.get(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");
- }
-
- private static boolean daggerRequiresModuleInstance(TypeElement module) {
- return !module.getModifiers().contains(ABSTRACT)
- && !hasOnlyStaticProvides(module)
- // Skip ApplicationContextModule, since Hilt manages this module internally.
- && !ClassNames.APPLICATION_CONTEXT_MODULE.equals(ClassName.get(module))
- // Skip Kotlin object modules since all their provision methods are static
- && !isKotlinObject(module);
- }
-
- private static boolean isKotlinObject(TypeElement type) {
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- return metadataUtil.isObjectClass(type) || metadataUtil.isCompanionObjectClass(type);
- }
-
- private static boolean hasOnlyStaticProvides(TypeElement module) {
- // TODO(erichang): Check for @Produces too when we have a producers story
- return ElementFilter.methodsIn(module.getEnclosedElements()).stream()
- .filter(method -> Processors.hasAnnotation(method, ClassNames.PROVIDES))
- .allMatch(method -> method.getModifiers().contains(STATIC));
- }
-
- private static boolean hasVisibleEmptyConstructor(TypeElement type) {
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
- return constructors.isEmpty()
- || constructors.stream()
- .filter(constructor -> constructor.getParameters().isEmpty())
- .anyMatch(
- constructor ->
- !constructor.getModifiers().contains(PRIVATE)
- );
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD b/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
deleted file mode 100644
index ebbc941..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ /dev/null
@@ -1,88 +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.
-
-# Description:
-# A processor that aggregates metadata about Hilt @InstallIn annotations
-
-package(default_visibility = ["//:src"])
-
-# TODO(bcorso): Remove all AggregatedDeps usage from the processor class path.
-java_library(
- name = "annotation",
- srcs = ["AggregatedDeps.java"],
- exports = [
- "//java/dagger/hilt/codegen:originating_element",
- ],
-)
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "AggregatedDepsGenerator.java",
- "AggregatedDepsProcessor.java",
- "PkgPrivateEntryPointGenerator.java",
- "PkgPrivateMetadata.java",
- "PkgPrivateModuleGenerator.java",
- ],
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:compiler_options",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:components",
- "//java/dagger/hilt/processor/internal:kotlin",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "component_dependencies",
- srcs = [
- "ComponentDependencies.java",
- ],
- deps = [
- ":processor_lib",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:component_descriptor",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java b/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
deleted file mode 100644
index 23ed148..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/ComponentDependencies.java
+++ /dev/null
@@ -1,459 +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.aggregateddeps;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsGenerator.AGGREGATING_PACKAGE;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.SetMultimap;
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.AnnotationValues;
-import dagger.hilt.processor.internal.BadInputException;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentDescriptor;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies.AggregatedDepMetadata.DependencyType;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-
-/** Represents information needed to create a component (i.e. modules, entry points, etc) */
-@AutoValue
-public abstract class ComponentDependencies {
- private static Builder builder() {
- return new AutoValue_ComponentDependencies.Builder();
- }
-
- /** Returns the modules for a component, without any filtering. */
- public abstract Dependencies modules();
-
- /** Returns the entry points associated with the given a component. */
- public abstract Dependencies entryPoints();
-
- /** Returns the component entry point associated with the given a component. */
- public abstract Dependencies componentEntryPoints();
-
- @AutoValue.Builder
- abstract static class Builder {
- abstract Dependencies.Builder modulesBuilder();
-
- abstract Dependencies.Builder entryPointsBuilder();
-
- abstract Dependencies.Builder componentEntryPointsBuilder();
-
- abstract ComponentDependencies autoBuild();
-
- ComponentDependencies build(Elements elements) {
- validateModules(modulesBuilder().build(), elements);
- return autoBuild();
- }
- }
-
- /** A key used for grouping a test dependency by both its component and test name. */
- @AutoValue
- abstract static class TestDepKey {
- static TestDepKey of(ClassName component, ClassName test) {
- return new AutoValue_ComponentDependencies_TestDepKey(component, test);
- }
-
- /** Returns the name of the component this dependency should be installed in. */
- abstract ClassName component();
-
- /** Returns the name of the test that this dependency should be installed in. */
- abstract ClassName test();
- }
-
- /**
- * Holds a set of component dependencies, e.g. modules or entry points.
- *
- * <p>This class handles separating dependencies into global and test dependencies. Global
- * dependencies are installed with every test, where test dependencies are only installed with the
- * specified test. The total set of dependencies includes all global + test dependencies.
- */
- @AutoValue
- public abstract static class Dependencies {
- static Builder builder() {
- return new AutoValue_ComponentDependencies_Dependencies.Builder();
- }
-
- /** Returns the global deps keyed by component. */
- abstract ImmutableSetMultimap<ClassName, TypeElement> globalDeps();
-
- /** Returns the global test deps keyed by component. */
- abstract ImmutableSetMultimap<ClassName, TypeElement> globalTestDeps();
-
- /** Returns the test deps keyed by component and test. */
- abstract ImmutableSetMultimap<TestDepKey, TypeElement> testDeps();
-
- /** Returns the uninstalled test deps keyed by test. */
- abstract ImmutableSetMultimap<ClassName, TypeElement> uninstalledTestDeps();
-
- /** Returns the global uninstalled test deps. */
- abstract ImmutableSet<TypeElement> globalUninstalledTestDeps();
-
- /** Returns the dependencies to be installed in the given component for the given root. */
- public ImmutableSet<TypeElement> get(ClassName component, ClassName root, boolean isTestRoot) {
- if (!isTestRoot) {
- return globalDeps().get(component);
- }
-
- ImmutableSet<TypeElement> uninstalledTestDepsForRoot = uninstalledTestDeps().get(root);
- return ImmutableSet.<TypeElement>builder()
- .addAll(
- globalDeps().get(component).stream()
- .filter(dep -> !uninstalledTestDepsForRoot.contains(dep))
- .filter(dep -> !globalUninstalledTestDeps().contains(dep))
- .collect(toImmutableSet()))
- .addAll(globalTestDeps().get(component))
- .addAll(testDeps().get(TestDepKey.of(component, root)))
- .build();
- }
-
- @AutoValue.Builder
- abstract static class Builder {
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> globalDepsBuilder();
-
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> globalTestDepsBuilder();
-
- abstract ImmutableSetMultimap.Builder<TestDepKey, TypeElement> testDepsBuilder();
-
- abstract ImmutableSetMultimap.Builder<ClassName, TypeElement> uninstalledTestDepsBuilder();
-
- abstract ImmutableSet.Builder<TypeElement> globalUninstalledTestDepsBuilder();
-
- abstract Dependencies build();
- }
- }
-
- /**
- * Pulls the component dependencies from the {@code packageName}.
- *
- * <p>Dependency files are generated by the {@link AggregatedDepsProcessor}, and have the form:
- *
- * <pre>{@code
- * {@literal @}AggregatedDeps(
- * components = {
- * "foo.FooComponent",
- * "bar.BarComponent"
- * },
- * modules = "baz.BazModule"
- * )
- *
- * }</pre>
- */
- public static ComponentDependencies from(
- ImmutableSet<ComponentDescriptor> descriptors, Elements elements) {
- Map<String, ComponentDescriptor> descriptorLookup = descriptorLookupMap(descriptors);
- ImmutableList<AggregatedDepMetadata> metadatas =
- getAggregatedDeps(elements).stream()
- .map(deps -> AggregatedDepMetadata.create(deps, descriptorLookup, elements))
- .collect(toImmutableList());
-
- ComponentDependencies.Builder componentDependencies = ComponentDependencies.builder();
- for (AggregatedDepMetadata metadata : metadatas) {
- Dependencies.Builder builder = null;
- switch (metadata.dependencyType()) {
- case MODULE:
- builder = componentDependencies.modulesBuilder();
- break;
- case ENTRY_POINT:
- builder = componentDependencies.entryPointsBuilder();
- break;
- case COMPONENT_ENTRY_POINT:
- builder = componentDependencies.componentEntryPointsBuilder();
- break;
- }
-
- for (ComponentDescriptor componentDescriptor : metadata.componentDescriptors()) {
- ClassName component = componentDescriptor.component();
- if (metadata.testElement().isPresent()) {
- // In this case the @InstallIn or @TestInstallIn applies to only the given test root.
- ClassName test = ClassName.get(metadata.testElement().get());
- builder.testDepsBuilder().put(TestDepKey.of(component, test), metadata.dependency());
- builder.uninstalledTestDepsBuilder().putAll(test, metadata.replacedDependencies());
- } else {
- // In this case the @InstallIn or @TestInstallIn applies to all roots
- if (!metadata.replacedDependencies().isEmpty()) {
- // If there are replacedDependencies() it means this is a @TestInstallIn
- builder.globalTestDepsBuilder().put(component, metadata.dependency());
- builder.globalUninstalledTestDepsBuilder().addAll(metadata.replacedDependencies());
- } else {
- builder.globalDepsBuilder().put(component, metadata.dependency());
- }
- }
- }
- }
-
- // Collect all @UninstallModules.
- // TODO(b/176438516): Filter @UninstallModules at the root.
- metadatas.stream()
- .filter(metadata -> metadata.testElement().isPresent())
- .map(metadata -> metadata.testElement().get())
- .distinct()
- .filter(testElement -> Processors.hasAnnotation(testElement, ClassNames.IGNORE_MODULES))
- .forEach(
- testElement ->
- componentDependencies
- .modulesBuilder()
- .uninstalledTestDepsBuilder()
- .putAll(
- ClassName.get(testElement), getUninstalledModules(testElement, elements)));
-
- return componentDependencies.build(elements);
- }
-
- private static ImmutableMap<String, ComponentDescriptor> descriptorLookupMap(
- ImmutableSet<ComponentDescriptor> descriptors) {
- ImmutableMap.Builder<String, ComponentDescriptor> builder = ImmutableMap.builder();
- for (ComponentDescriptor descriptor : descriptors) {
- // This is a temporary hack to map the old ApplicationComponent to the new SingletonComponent.
- // Technically, this is only needed for backwards compatibility with libraries using the old
- // processor since new processors should convert to the new SingletonComponent when generating
- // the metadata class.
- if (descriptor.component().equals(ClassNames.SINGLETON_COMPONENT)) {
- builder.put("dagger.hilt.android.components.ApplicationComponent", descriptor);
- }
- builder.put(descriptor.component().toString(), descriptor);
- }
- return builder.build();
- }
-
- // Validate that the @UninstallModules doesn't contain any test modules.
- private static Dependencies validateModules(Dependencies moduleDeps, Elements elements) {
- SetMultimap<ClassName, TypeElement> invalidTestModules = HashMultimap.create();
- moduleDeps.testDeps().entries().stream()
- .filter(
- e -> moduleDeps.uninstalledTestDeps().containsEntry(e.getKey().test(), e.getValue()))
- .forEach(e -> invalidTestModules.put(e.getKey().test(), e.getValue()));
-
- // Currently we don't have a good way to throw an error for all tests, so we sort (to keep the
- // error reporting order stable) and then choose the first test.
- // TODO(bcorso): Consider using ProcessorErrorHandler directly to report all errors at once?
- Optional<ClassName> invalidTest =
- invalidTestModules.keySet().stream()
- .min((test1, test2) -> test1.toString().compareTo(test2.toString()));
- if (invalidTest.isPresent()) {
- throw new BadInputException(
- String.format(
- "@UninstallModules on test, %s, should not containing test modules, "
- + "but found: %s",
- invalidTest.get(),
- invalidTestModules.get(invalidTest.get()).stream()
- // Sort modules to keep stable error messages.
- .sorted((test1, test2) -> test1.toString().compareTo(test2.toString()))
- .collect(toImmutableList())),
- elements.getTypeElement(invalidTest.get().toString()));
- }
- return moduleDeps;
- }
-
- private static ImmutableSet<TypeElement> getUninstalledModules(
- TypeElement testElement, Elements elements) {
- ImmutableList<TypeElement> userUninstallModules =
- Processors.getAnnotationClassValues(
- elements,
- Processors.getAnnotationMirror(testElement, ClassNames.IGNORE_MODULES),
- "value");
-
- // For pkg-private modules, find the generated wrapper class and uninstall that instead.
- return userUninstallModules.stream()
- .map(uninstallModule -> getPublicDependency(uninstallModule, elements))
- .collect(toImmutableSet());
- }
-
- /** Returns the public Hilt wrapper module, or the module itself if its already public. */
- private static TypeElement getPublicDependency(TypeElement dependency, Elements elements) {
- return PkgPrivateMetadata.of(elements, dependency, ClassNames.MODULE)
- .map(metadata -> elements.getTypeElement(metadata.generatedClassName().toString()))
- .orElse(dependency);
- }
-
- /** Returns the top-level elements of the aggregated deps package. */
- private static ImmutableList<AnnotationMirror> getAggregatedDeps(Elements elements) {
- PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE);
- checkState(
- packageElement != null,
- "Couldn't find package %s. Did you mark your @Module classes with @InstallIn annotations?",
- AGGREGATING_PACKAGE);
-
- List<? extends Element> aggregatedDepsElements = packageElement.getEnclosedElements();
- checkState(
- !aggregatedDepsElements.isEmpty(),
- "No dependencies found. Did you mark your @Module classes with @InstallIn annotations?");
-
- ImmutableList.Builder<AnnotationMirror> builder = ImmutableList.builder();
- for (Element element : aggregatedDepsElements) {
- ProcessorErrors.checkState(
- element.getKind() == ElementKind.CLASS,
- element,
- "Only classes may be in package %s. Did you add custom code in the package?",
- AGGREGATING_PACKAGE);
-
- AnnotationMirror aggregatedDeps =
- Processors.getAnnotationMirror(element, ClassNames.AGGREGATED_DEPS);
- ProcessorErrors.checkState(
- aggregatedDeps != null,
- element,
- "Classes in package %s must be annotated with @AggregatedDeps: %s. Found: %s.",
- AGGREGATING_PACKAGE,
- element.getSimpleName(),
- element.getAnnotationMirrors());
-
- builder.add(aggregatedDeps);
- }
- return builder.build();
- }
-
- @AutoValue
- abstract static class AggregatedDepMetadata {
- static AggregatedDepMetadata create(
- AnnotationMirror aggregatedDeps,
- Map<String, ComponentDescriptor> descriptorLookup,
- Elements elements) {
- ImmutableMap<String, AnnotationValue> aggregatedDepsValues =
- Processors.getAnnotationValues(elements, aggregatedDeps);
-
- return new AutoValue_ComponentDependencies_AggregatedDepMetadata(
- getTestElement(aggregatedDepsValues.get("test"), elements),
- getComponents(aggregatedDepsValues.get("components"), descriptorLookup),
- getDependencyType(
- aggregatedDepsValues.get("modules"),
- aggregatedDepsValues.get("entryPoints"),
- aggregatedDepsValues.get("componentEntryPoints")),
- getDependency(
- aggregatedDepsValues.get("modules"),
- aggregatedDepsValues.get("entryPoints"),
- aggregatedDepsValues.get("componentEntryPoints"),
- elements),
- getReplacedDependencies(aggregatedDepsValues.get("replaces"), elements));
- }
-
- enum DependencyType {
- MODULE,
- ENTRY_POINT,
- COMPONENT_ENTRY_POINT
- }
-
- abstract Optional<TypeElement> testElement();
-
- abstract ImmutableList<ComponentDescriptor> componentDescriptors();
-
- abstract DependencyType dependencyType();
-
- abstract TypeElement dependency();
-
- abstract ImmutableSet<TypeElement> replacedDependencies();
-
- private static Optional<TypeElement> getTestElement(
- AnnotationValue testValue, Elements elements) {
- checkNotNull(testValue);
- String test = AnnotationValues.getString(testValue);
- return test.isEmpty() ? Optional.empty() : Optional.of(elements.getTypeElement(test));
- }
-
- private static ImmutableList<ComponentDescriptor> getComponents(
- AnnotationValue componentsValue, Map<String, ComponentDescriptor> descriptorLookup) {
- checkNotNull(componentsValue);
- ImmutableList<String> componentNames =
- AnnotationValues.getAnnotationValues(componentsValue).stream()
- .map(AnnotationValues::getString)
- .collect(toImmutableList());
-
- checkState(!componentNames.isEmpty());
- ImmutableList.Builder<ComponentDescriptor> components = ImmutableList.builder();
- for (String componentName : componentNames) {
- checkState(
- descriptorLookup.containsKey(componentName),
- "%s is not a valid Component. Did you add or remove code in package %s?",
- componentName,
- AGGREGATING_PACKAGE);
- components.add(descriptorLookup.get(componentName));
- }
- return components.build();
- }
-
- private static DependencyType getDependencyType(
- AnnotationValue modulesValue,
- AnnotationValue entryPointsValue,
- AnnotationValue componentEntryPointsValue) {
- checkNotNull(modulesValue);
- checkNotNull(entryPointsValue);
- checkNotNull(componentEntryPointsValue);
-
- ImmutableSet.Builder<DependencyType> dependencyTypes = ImmutableSet.builder();
- if (!AnnotationValues.getAnnotationValues(modulesValue).isEmpty()) {
- dependencyTypes.add(DependencyType.MODULE);
- }
- if (!AnnotationValues.getAnnotationValues(entryPointsValue).isEmpty()) {
- dependencyTypes.add(DependencyType.ENTRY_POINT);
- }
- if (!AnnotationValues.getAnnotationValues(componentEntryPointsValue).isEmpty()) {
- dependencyTypes.add(DependencyType.COMPONENT_ENTRY_POINT);
- }
- return getOnlyElement(dependencyTypes.build());
- }
-
- private static TypeElement getDependency(
- AnnotationValue modulesValue,
- AnnotationValue entryPointsValue,
- AnnotationValue componentEntryPointsValue,
- Elements elements) {
- checkNotNull(modulesValue);
- checkNotNull(entryPointsValue);
- checkNotNull(componentEntryPointsValue);
-
- return elements.getTypeElement(
- AnnotationValues.getString(
- getOnlyElement(
- ImmutableList.<AnnotationValue>builder()
- .addAll(AnnotationValues.getAnnotationValues(modulesValue))
- .addAll(AnnotationValues.getAnnotationValues(entryPointsValue))
- .addAll(AnnotationValues.getAnnotationValues(componentEntryPointsValue))
- .build())));
- }
-
- private static ImmutableSet<TypeElement> getReplacedDependencies(
- AnnotationValue replacedDependenciesValue, Elements elements) {
- // Allow null values to support libraries using a Hilt version before @TestInstallIn was added
- return replacedDependenciesValue == null
- ? ImmutableSet.of()
- : AnnotationValues.getAnnotationValues(replacedDependenciesValue).stream()
- .map(AnnotationValues::getString)
- .map(elements::getTypeElement)
- .map(replacedDep -> getPublicDependency(replacedDep, elements))
- .collect(toImmutableSet());
- }
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java
deleted file mode 100644
index 6dac59f..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateEntryPointGenerator.java
+++ /dev/null
@@ -1,77 +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.aggregateddeps;
-
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-
-/**
- * Generates a public Dagger entrypoint that includes a user's pkg-private entrypoint. This allows a
- * user's entrypoint to use pkg-private visibility to hide from external packages.
- */
-final class PkgPrivateEntryPointGenerator {
- private final ProcessingEnvironment env;
- private final PkgPrivateMetadata metadata;
-
- PkgPrivateEntryPointGenerator(ProcessingEnvironment env, PkgPrivateMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
- }
-
- // This method creates the following generated code for an EntryPoint in pkg.MyEntryPoint that is
- // package
- // private
- //
- // package pkg; //same package
- //
- // import dagger.hilt.InstallIn;
- // import dagger.hilt.EntryPoint;;
- // import javax.annotation.Generated;
- //
- // @Generated("dagger.hilt.processor.internal.aggregateddeps.PkgPrivateEntryPointGenerator")
- // @InstallIn(InstallIn.Component.ACTIVITY)
- // @EntryPoint
- // public final class HiltWrapper_MyEntryPoint extends MyEntryPoint {
- // }
- void generate() throws IOException {
-
- TypeSpec.Builder entryPointInterfaceBuilder =
- TypeSpec.interfaceBuilder(metadata.generatedClassName().simpleName())
- .addOriginatingElement(metadata.getTypeElement())
- .addAnnotation(Processors.getOriginatingElementAnnotation(metadata.getTypeElement()))
- .addModifiers(Modifier.PUBLIC)
- .addSuperinterface(metadata.baseClassName())
- .addAnnotation(metadata.getAnnotation());
-
- Processors.addGeneratedAnnotation(entryPointInterfaceBuilder, env, getClass());
-
- if (metadata.getOptionalInstallInAnnotationMirror().isPresent()) {
- entryPointInterfaceBuilder.addAnnotation(
- AnnotationSpec.get(metadata.getOptionalInstallInAnnotationMirror().get()));
- }
-
- JavaFile.builder(
- metadata.generatedClassName().packageName(), entryPointInterfaceBuilder.build())
- .build()
- .writeTo(env.getFiler());
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
deleted file mode 100644
index 66f1751..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateMetadata.java
+++ /dev/null
@@ -1,93 +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.aggregateddeps;
-
-import static com.google.auto.common.Visibility.effectiveVisibilityOfElement;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.Visibility;
-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 java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-
-/** PkgPrivateModuleMetadata contains a set of utilities for processing package private modules. */
-@AutoValue
-abstract class PkgPrivateMetadata {
- private static final String PREFIX = "HiltWrapper_";
-
- /** Returns the base class name of the elemenet. */
- TypeName baseClassName() {
- return TypeName.get(getTypeElement().asType());
- }
-
- /** Returns TypeElement for the module element the metadata object represents */
- abstract TypeElement getTypeElement();
-
- /**
- * Returns an optional @InstallIn AnnotationMirror for the module element the metadata object
- * represents
- */
- abstract Optional<AnnotationMirror> getOptionalInstallInAnnotationMirror();
-
- /** Return the Type of this package private element. */
- abstract ClassName getAnnotation();
-
- /** Returns the expected genenerated classname for the element the metadata object represents */
- final ClassName generatedClassName() {
- return Processors.prepend(
- Processors.getEnclosedClassName(ClassName.get(getTypeElement())), PREFIX);
- }
-
- /**
- * Returns an Optional PkgPrivateMetadata requiring Hilt processing, otherwise returns an empty
- * Optional.
- */
- static Optional<PkgPrivateMetadata> of(Elements elements, Element element, ClassName annotation) {
- // If this is a public element no wrapping is needed
- if (effectiveVisibilityOfElement(element) == Visibility.PUBLIC) {
- 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));
- } else {
- throw new IllegalStateException(
- "Expected element to be annotated with @InstallIn: " + element);
- }
-
- if (annotation.equals(ClassNames.MODULE)
- ) {
- // Skip modules that require a module instance. Required by
- // dagger (b/31489617)
- if (Processors.requiresModuleInstance(elements, MoreElements.asType(element))) {
- return Optional.empty();
- }
- }
- return Optional.of(
- new AutoValue_PkgPrivateMetadata(MoreElements.asType(element), installIn, annotation));
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java b/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java
deleted file mode 100644
index 18ff0bd..0000000
--- a/java/dagger/hilt/processor/internal/aggregateddeps/PkgPrivateModuleGenerator.java
+++ /dev/null
@@ -1,73 +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.aggregateddeps;
-
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-
-/**
- * Generates a public Dagger module that includes a user's pkg-private module. This allows a user's
- * module to use pkg-private visibility to hide from external packages, but still allows Hilt to
- * install the module when the component is created in another package.
- */
-final class PkgPrivateModuleGenerator {
- private final ProcessingEnvironment env;
- private final PkgPrivateMetadata metadata;
-
- PkgPrivateModuleGenerator(ProcessingEnvironment env, PkgPrivateMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
- }
-
- // This method creates the following generated code for a pkg-private module, pkg.MyModule:
- //
- // package pkg; //same as module
- //
- // import dagger.Module;
- // import dagger.hilt.InstallIn;
- // import javax.annotation.Generated;
- //
- // @Generated("dagger.hilt.processor.internal.aggregateddeps.PkgPrivateModuleGenerator")
- // @InstallIn(ActivityComponent.class)
- // @Module(includes = MyModule.class)
- // public final class HiltModuleWrapper_MyModule {}
- 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()))
- .addAnnotation(
- AnnotationSpec.builder(metadata.getAnnotation())
- .addMember("includes", "$T.class", metadata.getTypeElement())
- .build());
-
- Processors.addGeneratedAnnotation(builder, env, getClass());
-
- JavaFile.builder(metadata.generatedClassName().packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
deleted file mode 100644
index 6efd643..0000000
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfProcessor.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.aliasof;
-
-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 java.util.Set;
-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 {
- @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);
-
- Element defineComponentScope =
- Processors.getAnnotationClassValue(getElementUtils(), annotationMirror, "value");
-
- new AliasOfPropagatedDataGenerator(getProcessingEnv(), element, defineComponentScope)
- .generate();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
deleted file mode 100644
index 75c4c15..0000000
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfPropagatedDataGenerator.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.aliasof;
-
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-
-/** Generates resource files for {@link dagger.hilt.migration.AliasOf}. */
-final class AliasOfPropagatedDataGenerator {
-
- private final ProcessingEnvironment processingEnv;
- private final Element aliasScope;
- private final Element defineComponentScope;
-
- AliasOfPropagatedDataGenerator(
- ProcessingEnvironment processingEnv, Element aliasScope, Element defineComponentScope) {
- this.processingEnv = processingEnv;
- this.aliasScope = aliasScope;
- this.defineComponentScope = defineComponentScope;
- }
-
- void generate() throws IOException {
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(Processors.getFullEnclosedName(aliasScope))
- .addOriginatingElement(aliasScope)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.ALIAS_OF_PROPAGATED_DATA)
- .addMember("defineComponentScope", "$T.class", defineComponentScope)
- .addMember("alias", "$T.class", aliasScope)
- .build())
- .addJavadoc("Generated class for aggregating scope aliases. \n");
-
- Processors.addGeneratedAnnotation(generator, processingEnv, getClass());
-
- JavaFile.builder(AliasOfs.AGGREGATING_PACKAGE, generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java b/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
deleted file mode 100644
index 930a72e..0000000
--- a/java/dagger/hilt/processor/internal/aliasof/AliasOfs.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.aliasof;
-
-import static com.google.common.base.Suppliers.memoize;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-
-/**
- * Extracts a multimap of aliases annotated with {@link dagger.hilt.migration.AliasOf} mapping them
- * to scopes they are alias of.
- */
-public final class AliasOfs {
- static final String AGGREGATING_PACKAGE = AliasOfs.class.getPackage().getName() + ".codegen";
-
- private final ProcessingEnvironment processingEnvironment;
- private final ImmutableSet<ClassName> defineComponentScopes;
- private final Supplier<ImmutableMultimap<ClassName, ClassName>> aliases =
- memoize(() -> getAliases());
-
- public AliasOfs(
- ProcessingEnvironment processingEnvironment, ImmutableSet<ClassName> defineComponentScopes) {
- this.defineComponentScopes = defineComponentScopes;
- this.processingEnvironment = processingEnvironment;
- }
-
- public ImmutableSet<ClassName> getAliasesFor(ClassName defineComponentScope) {
- return ImmutableSet.copyOf(aliases.get().get(defineComponentScope));
- }
-
- private ImmutableMultimap<ClassName, ClassName> getAliases() {
- Elements elements = processingEnvironment.getElementUtils();
- PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE);
- if (packageElement == null) {
- return ImmutableMultimap.of();
- }
- List<? extends Element> scopeAliasElements = packageElement.getEnclosedElements();
- Preconditions.checkState(
- !scopeAliasElements.isEmpty(), "No scope aliases Found in package %s.", packageElement);
-
- ImmutableMultimap.Builder<ClassName, ClassName> builder = ImmutableMultimap.builder();
- for (Element element : scopeAliasElements) {
- ProcessorErrors.checkState(
- element.getKind() == ElementKind.CLASS,
- element,
- "Only classes may be in package %s. Did you add custom code in the package?",
- packageElement);
-
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.ALIAS_OF_PROPAGATED_DATA);
-
- ProcessorErrors.checkState(
- annotationMirror != null,
- element,
- "Classes in package %s must be annotated with @%s: %s."
- + " Found: %s. Files in this package are generated, did you add custom code in the"
- + " package? ",
- packageElement,
- ClassNames.ALIAS_OF_PROPAGATED_DATA,
- element.getSimpleName(),
- element.getAnnotationMirrors());
-
- TypeElement defineComponentScope =
- Processors.getAnnotationClassValue(elements, annotationMirror, "defineComponentScope");
- TypeElement alias = Processors.getAnnotationClassValue(elements, annotationMirror, "alias");
-
- Preconditions.checkState(
- defineComponentScopes.contains(ClassName.get(defineComponentScope)),
- "The scope %s cannot be an alias for %s. You can only have aliases of a scope defined"
- + " directly on a @DefineComponent type.",
- ClassName.get(alias),
- ClassName.get(defineComponentScope));
-
- builder.put(ClassName.get(defineComponentScope), ClassName.get(alias));
- }
-
- return builder.build();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/aliasof/BUILD b/java/dagger/hilt/processor/internal/aliasof/BUILD
deleted file mode 100644
index d3f90f2..0000000
--- a/java/dagger/hilt/processor/internal/aliasof/BUILD
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A processor for @dagger.hilt.AliasOfProcessor.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.aliasof.AliasOfProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "AliasOfProcessor.java",
- "AliasOfPropagatedDataGenerator.java",
- ],
- deps = [
- ":alias_ofs",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-java_library(
- name = "alias_ofs",
- srcs = [
- "AliasOfs.java",
- ],
- deps = [
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/definecomponent/BUILD b/java/dagger/hilt/processor/internal/definecomponent/BUILD
deleted file mode 100644
index 7edec1c..0000000
--- a/java/dagger/hilt/processor/internal/definecomponent/BUILD
+++ /dev/null
@@ -1,69 +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.
-
-# Description:
-# A processor for @dagger.hilt.DefineComponent.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "DefineComponentProcessor.java",
- ],
- deps = [
- ":define_components",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-java_library(
- name = "define_components",
- srcs = [
- "DefineComponentBuilderMetadatas.java",
- "DefineComponentMetadatas.java",
- "DefineComponents.java",
- ],
- deps = [
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:component_descriptor",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java
deleted file mode 100644
index 0f10f39..0000000
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentBuilderMetadatas.java
+++ /dev/null
@@ -1,161 +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.definecomponent;
-
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-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.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
-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 {
- static DefineComponentBuilderMetadatas create(DefineComponentMetadatas componentMetadatas) {
- return new DefineComponentBuilderMetadatas(componentMetadatas);
- }
-
- private final Map<Element, DefineComponentBuilderMetadata> builderMetadatas = new HashMap<>();
- private final DefineComponentMetadatas componentMetadatas;
-
- private DefineComponentBuilderMetadatas(DefineComponentMetadatas componentMetadatas) {
- this.componentMetadatas = componentMetadatas;
- }
-
- DefineComponentBuilderMetadata get(Element element) {
- if (!builderMetadatas.containsKey(element)) {
- builderMetadatas.put(element, getUncached(element));
- }
- return builderMetadatas.get(element);
- }
-
- private DefineComponentBuilderMetadata getUncached(Element element) {
- ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.DEFINE_COMPONENT_BUILDER),
- element,
- "%s, expected to be annotated with @DefineComponent.Builder. Found: %s",
- element,
- element.getAnnotationMirrors());
-
- // TODO(bcorso): Allow abstract classes?
- ProcessorErrors.checkState(
- element.getKind().equals(ElementKind.INTERFACE),
- element,
- "@DefineComponent.Builder is only allowed on interfaces. Found: %s",
- element);
- TypeElement builder = MoreElements.asType(element);
-
- // TODO(bcorso): Allow extending interfaces?
- ProcessorErrors.checkState(
- builder.getInterfaces().isEmpty(),
- builder,
- "@DefineComponent.Builder %s, cannot extend a super class or interface. Found: %s",
- builder,
- builder.getInterfaces());
-
- // TODO(bcorso): Allow type parameters?
- ProcessorErrors.checkState(
- builder.getTypeParameters().isEmpty(),
- builder,
- "@DefineComponent.Builder %s, cannot have type parameters.",
- builder.asType());
-
- List<VariableElement> nonStaticFields =
- ElementFilter.fieldsIn(builder.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
- .collect(Collectors.toList());
- ProcessorErrors.checkState(
- nonStaticFields.isEmpty(),
- builder,
- "@DefineComponent.Builder %s, cannot have non-static fields. Found: %s",
- builder,
- nonStaticFields);
-
- List<ExecutableElement> buildMethods =
- ElementFilter.methodsIn(builder.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
- .filter(method -> method.getParameters().isEmpty())
- .collect(Collectors.toList());
-
- ProcessorErrors.checkState(
- buildMethods.size() == 1,
- builder,
- "@DefineComponent.Builder %s, must have exactly 1 build method that takes no parameters. "
- + "Found: %s",
- builder,
- buildMethods);
-
- ExecutableElement buildMethod = buildMethods.get(0);
- TypeMirror component = buildMethod.getReturnType();
- ProcessorErrors.checkState(
- buildMethod.getReturnType().getKind().equals(TypeKind.DECLARED)
- && Processors.hasAnnotation(
- MoreTypes.asTypeElement(component), ClassNames.DEFINE_COMPONENT),
- builder,
- "@DefineComponent.Builder method, %s#%s, must return a @DefineComponent type. Found: %s",
- builder,
- buildMethod,
- component);
-
- List<ExecutableElement> nonStaticNonBuilderMethods =
- ElementFilter.methodsIn(builder.getEnclosedElements()).stream()
- .filter(method -> !method.getModifiers().contains(STATIC))
- .filter(method -> !method.equals(buildMethod))
- .filter(method -> !TypeName.get(method.getReturnType()).equals(ClassName.get(builder)))
- .collect(Collectors.toList());
-
- ProcessorErrors.checkState(
- nonStaticNonBuilderMethods.isEmpty(),
- nonStaticNonBuilderMethods,
- "@DefineComponent.Builder %s, all non-static methods must return %s or %s. Found: %s",
- builder,
- builder,
- component,
- nonStaticNonBuilderMethods);
-
- return new AutoValue_DefineComponentBuilderMetadatas_DefineComponentBuilderMetadata(
- builder,
- buildMethod,
- componentMetadatas.get(MoreTypes.asTypeElement(component)));
- }
-
- @AutoValue
- abstract static class DefineComponentBuilderMetadata {
- abstract TypeElement builder();
-
- abstract ExecutableElement buildMethod();
-
- abstract DefineComponentMetadata componentMetadata();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java
deleted file mode 100644
index aa69e40..0000000
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentMetadatas.java
+++ /dev/null
@@ -1,195 +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.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 dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreTypes;
-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 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 {
- static DefineComponentMetadatas create() {
- return new DefineComponentMetadatas();
- }
-
- private final Map<Element, DefineComponentMetadata> metadatas = new HashMap<>();
-
- private DefineComponentMetadatas() {}
-
- /** Returns the metadata for an element annotated with {@link dagger.hilt.DefineComponent}. */
- DefineComponentMetadata get(Element element) {
- return get(element, new LinkedHashSet<>());
- }
-
- private DefineComponentMetadata get(Element element, LinkedHashSet<Element> childPath) {
- if (!metadatas.containsKey(element)) {
- metadatas.put(element, getUncached(element, childPath));
- }
- return metadatas.get(element);
- }
-
- private DefineComponentMetadata getUncached(
- Element element, LinkedHashSet<Element> childPath) {
- ProcessorErrors.checkState(
- childPath.add(element),
- element,
- "@DefineComponent cycle: %s -> %s",
- childPath.stream().map(Object::toString).collect(joining(" -> ")),
- element);
-
- ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.DEFINE_COMPONENT),
- element,
- "%s, expected to be annotated with @DefineComponent. Found: %s",
- element,
- element.getAnnotationMirrors());
-
- // TODO(bcorso): Allow abstract classes?
- ProcessorErrors.checkState(
- element.getKind().equals(ElementKind.INTERFACE),
- element,
- "@DefineComponent is only allowed on interfaces. Found: %s",
- element);
- TypeElement component = asType(element);
-
- // TODO(bcorso): Allow extending interfaces?
- ProcessorErrors.checkState(
- component.getInterfaces().isEmpty(),
- component,
- "@DefineComponent %s, cannot extend a super class or interface. Found: %s",
- component,
- component.getInterfaces());
-
- // TODO(bcorso): Allow type parameters?
- ProcessorErrors.checkState(
- component.getTypeParameters().isEmpty(),
- component,
- "@DefineComponent %s, cannot have type parameters.",
- component.asType());
-
- // 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());
- ProcessorErrors.checkState(
- nonStaticMethods.isEmpty(),
- component,
- "@DefineComponent %s, cannot have non-static methods. Found: %s",
- component,
- nonStaticMethods);
-
- // No need to check non-static fields since interfaces can't have them.
-
- ImmutableList<TypeElement> scopes =
- Processors.getScopeAnnotations(component).stream()
- .map(AnnotationMirror::getAnnotationType)
- .map(MoreTypes::asTypeElement)
- .collect(toImmutableList());
-
- ImmutableList<AnnotationMirror> aliasScopes =
- Processors.getAnnotationsAnnotatedWith(component, 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);
-
- AnnotationMirror mirror =
- Processors.getAnnotationMirror(component, ClassNames.DEFINE_COMPONENT);
- AnnotationValue parentValue = getAnnotationElementAndValue(mirror, "parent").getValue();
-
- 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);
-
- TypeElement parent = asTypeElement(AnnotationValues.getTypeMirror(parentValue));
-
- ProcessorErrors.checkState(
- ClassName.get(parent).equals(ClassNames.DEFINE_COMPONENT_NO_PARENT)
- || Processors.hasAnnotation(parent, ClassNames.DEFINE_COMPONENT),
- component,
- "@DefineComponent %s, references a type not annotated with @DefineComponent: %s",
- component,
- parent);
-
- Optional<DefineComponentMetadata> parentComponent =
- ClassName.get(parent).equals(ClassNames.DEFINE_COMPONENT_NO_PARENT)
- ? Optional.empty()
- : Optional.of(get(parent, childPath));
-
- ProcessorErrors.checkState(
- parentComponent.isPresent()
- || ClassName.get(component).equals(ClassNames.SINGLETON_COMPONENT),
- component,
- "@DefineComponent %s is missing a parent declaration.\n"
- + "Please declare the parent, for example: @DefineComponent(parent ="
- + " SingletonComponent.class)",
- component);
-
- return new AutoValue_DefineComponentMetadatas_DefineComponentMetadata(
- component, scopes, parentComponent);
- }
-
- @AutoValue
- abstract static class DefineComponentMetadata {
-
- /** Returns the component annotated with {@link dagger.hilt.DefineComponent}. */
- abstract TypeElement component();
-
- /** Returns the scopes of the component. */
- abstract ImmutableList<TypeElement> scopes();
-
- /** Returns the parent component, if one exists. */
- abstract Optional<DefineComponentMetadata> parentMetadata();
-
- boolean isRoot() {
- return !parentMetadata().isPresent();
- }
- }
-}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java
deleted file mode 100644
index e0bfca9..0000000
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessor.java
+++ /dev/null
@@ -1,87 +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.definecomponent;
-
-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 com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-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 javax.annotation.processing.Processor;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
-
-/**
- * A processor for {@link dagger.hilt.DefineComponent} and {@link
- * dagger.hilt.DefineComponent.Builder}.
- */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class DefineComponentProcessor extends BaseProcessor {
- private final DefineComponentMetadatas componentMetadatas = DefineComponentMetadatas.create();
- private final DefineComponentBuilderMetadatas componentBuilderMetadatas =
- DefineComponentBuilderMetadatas.create(componentMetadatas);
-
- @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 {
- TypeSpec.Builder builder =
- TypeSpec.interfaceBuilder(Processors.getFullEnclosedName(typeElement))
- .addOriginatingElement(typeElement)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.DEFINE_COMPONENT_CLASSES)
- .addMember(member, "$S", typeElement.getQualifiedName())
- .build());
-
- Processors.addGeneratedAnnotation(builder, processingEnv, getClass());
-
- JavaFile.builder(DefineComponents.AGGREGATING_PACKAGE, builder.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-}
diff --git a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java b/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
deleted file mode 100644
index 0b33011..0000000
--- a/java/dagger/hilt/processor/internal/definecomponent/DefineComponents.java
+++ /dev/null
@@ -1,225 +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.definecomponent;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationElementAndValue;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ListMultimap;
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.AnnotationValues;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentDescriptor;
-import dagger.hilt.processor.internal.ComponentTree;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentBuilderMetadatas.DefineComponentBuilderMetadata;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentMetadatas.DefineComponentMetadata;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-
-/**
- * A utility class for getting {@link DefineComponentMetadata} and {@link
- * DefineComponentBuilderMetadata}.
- */
-public final class DefineComponents {
- static final String AGGREGATING_PACKAGE =
- DefineComponents.class.getPackage().getName() + ".codegen";
-
- 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 {@link ComponentTree} from the aggregated {@link ComponentDescriptor}s. */
- public ComponentTree getComponentTree(Elements elements) {
- AggregatedMetadata aggregatedMetadata =
- AggregatedMetadata.from(elements, componentMetadatas, componentBuilderMetadatas);
- ListMultimap<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMultimap =
- ArrayListMultimap.create();
- aggregatedMetadata.builders()
- .forEach(builder -> builderMultimap.put(builder.componentMetadata(), builder));
-
- // Check that there are not multiple builders per component
- for (DefineComponentMetadata componentMetadata : builderMultimap.keySet()) {
- TypeElement 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,
- builderMultimap.get(componentMetadata).stream()
- .map(DefineComponentBuilderMetadata::builder)
- .map(TypeElement::toString)
- .sorted()
- .collect(toImmutableList()));
- }
-
- // Now that we know there is at most 1 builder per component, convert the Multimap to Map.
- Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap = new LinkedHashMap<>();
- builderMultimap.entries().forEach(e -> builderMap.put(e.getKey(), e.getValue()));
-
-
- return ComponentTree.from(aggregatedMetadata.components().stream()
- .map(componentMetadata -> toComponentDescriptor(componentMetadata, builderMap))
- .collect(toImmutableSet()));
- }
-
- private static ComponentDescriptor toComponentDescriptor(
- DefineComponentMetadata componentMetadata,
- Map<DefineComponentMetadata, DefineComponentBuilderMetadata> builderMap) {
- ComponentDescriptor.Builder builder =
- ComponentDescriptor.builder()
- .component(ClassName.get(componentMetadata.component()))
- .scopes(
- componentMetadata.scopes().stream().map(ClassName::get).collect(toImmutableSet()));
-
-
- if (builderMap.containsKey(componentMetadata)) {
- builder.creator(ClassName.get(builderMap.get(componentMetadata).builder()));
- }
-
- componentMetadata
- .parentMetadata()
- .map(parent -> toComponentDescriptor(parent, builderMap))
- .ifPresent(builder::parent);
-
- return builder.build();
- }
-
- @AutoValue
- abstract static class AggregatedMetadata {
- /** Returns the aggregated metadata for {@link DefineComponentClasses#component()}. */
- abstract ImmutableList<DefineComponentMetadata> components();
-
- /** Returns the aggregated metadata for {@link DefineComponentClasses#builder()}. */
- abstract ImmutableList<DefineComponentBuilderMetadata> builders();
-
- static AggregatedMetadata from(
- Elements elements,
- DefineComponentMetadatas componentMetadatas,
- DefineComponentBuilderMetadatas componentBuilderMetadatas) {
- PackageElement packageElement = elements.getPackageElement(AGGREGATING_PACKAGE);
-
- if (packageElement == null) {
- return new AutoValue_DefineComponents_AggregatedMetadata(
- ImmutableList.of(), ImmutableList.of());
- }
-
- ImmutableList.Builder<DefineComponentMetadata> components = ImmutableList.builder();
- ImmutableList.Builder<DefineComponentBuilderMetadata> builders = ImmutableList.builder();
- for (Element element : packageElement.getEnclosedElements()) {
- ProcessorErrors.checkState(
- MoreElements.isType(element),
- element,
- "Only types may be in package %s. Did you add custom code in the package?",
- packageElement);
-
- TypeElement typeElement = MoreElements.asType(element);
- ProcessorErrors.checkState(
- Processors.hasAnnotation(typeElement, ClassNames.DEFINE_COMPONENT_CLASSES),
- typeElement,
- "Class, %s, must be annotated with @%s. Found: %s.",
- typeElement,
- ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(),
- typeElement.getAnnotationMirrors());
-
- Optional<TypeElement> component = defineComponentClass(elements, typeElement, "component");
- Optional<TypeElement> builder = defineComponentClass(elements, typeElement, "builder");
- ProcessorErrors.checkState(
- component.isPresent() || builder.isPresent(),
- typeElement,
- "@DefineComponentClasses missing both `component` and `builder` members.");
-
- component.map(componentMetadatas::get).ifPresent(components::add);
- builder.map(componentBuilderMetadatas::get).ifPresent(builders::add);
- }
-
- return new AutoValue_DefineComponents_AggregatedMetadata(
- components.build(), builders.build());
- }
-
- private static Optional<TypeElement> defineComponentClass(
- Elements elements, Element element, String annotationMember) {
- AnnotationMirror mirror =
- Processors.getAnnotationMirror(element, ClassNames.DEFINE_COMPONENT_CLASSES);
- AnnotationValue value = getAnnotationElementAndValue(mirror, annotationMember).getValue();
- String className = AnnotationValues.getString(value);
-
- if (className.isEmpty()) { // The default value.
- return Optional.empty();
- }
-
- TypeElement type = elements.getTypeElement(className);
- ProcessorErrors.checkState(
- type != null,
- element,
- "%s.%s(), has invalid value: `%s`.",
- ClassNames.DEFINE_COMPONENT_CLASSES.simpleName(),
- annotationMember,
- className);
-
- return Optional.of(type);
- }
- }
-}
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
deleted file mode 100644
index e3865a6..0000000
--- a/java/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A processor for @dagger.hilt.AliasOfProcessor.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.disableinstallincheck.DisableInstallInCheckProcessor",
- visibility = [
- "//java/dagger/hilt/migration:__pkg__",
- ],
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "DisableInstallInCheckProcessor.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/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java b/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java
deleted file mode 100644
index c51f350..0000000
--- a/java/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessor.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.disableinstallincheck;
-
-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 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 {
- @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);
- }
-}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD b/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
deleted file mode 100644
index f24ffb7..0000000
--- a/java/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ /dev/null
@@ -1,65 +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.
-
-# Description:
-# A processor for @dagger.hilt.GeneratesRootInput.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "GeneratesRootInputProcessor.java",
- "GeneratesRootInputPropagatedDataGenerator.java",
- ],
- deps = [
- ":generates_root_inputs",
- "//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/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-java_library(
- name = "generates_root_inputs",
- srcs = [
- "GeneratesRootInputs.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/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java
deleted file mode 100644
index 6588e09..0000000
--- a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessor.java
+++ /dev/null
@@ -1,57 +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.generatesrootinput;
-
-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 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;
-
-/**
- * Processes the annotations annotated with {@link dagger.hilt.GeneratesRootInput} which generate
- * input for components and should be processed before component creation.
- */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class GeneratesRootInputProcessor extends BaseProcessor {
-
- @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();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java
deleted file mode 100644
index 5c53894..0000000
--- a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputPropagatedDataGenerator.java
+++ /dev/null
@@ -1,56 +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.generatesrootinput;
-
-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;
-
- GeneratesRootInputPropagatedDataGenerator(ProcessingEnvironment processingEnv, Element 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");
-
- Processors.addGeneratedAnnotation(generator, processingEnv, getClass());
-
- JavaFile.builder(GeneratesRootInputs.AGGREGATING_PACKAGE, generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-}
diff --git a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java b/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java
deleted file mode 100644
index 139592e..0000000
--- a/java/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputs.java
+++ /dev/null
@@ -1,106 +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.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 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 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 Supplier<ImmutableList<ClassName>> generatesRootInputAnnotations =
- memoize(() -> getAnnotationList());
-
- public GeneratesRootInputs(ProcessingEnvironment processingEnvironment) {
- this.elements = processingEnvironment.getElementUtils();
- }
-
- public ImmutableSet<Element> getElementsToWaitFor(RoundEnvironment 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()))
- .filter(element -> element != null)
- .flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).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);
-
- ImmutableList.Builder<ClassName> builder = ImmutableList.builder();
- for (Element element : annotationElements) {
- ProcessorErrors.checkState(
- element.getKind() == ElementKind.CLASS,
- element,
- "Only classes may be in package %s. Did you add custom code in the package?",
- packageElement);
-
- AnnotationMirror annotationMirror =
- Processors.getAnnotationMirror(element, ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA);
- ProcessorErrors.checkState(
- annotationMirror != null,
- element,
- "Classes in package %s must be annotated with @%s: %s."
- + " Found: %s. Files in this package are generated, did you add custom code in the"
- + " package? ",
- packageElement,
- ClassNames.GENERATES_ROOT_INPUT_PROPAGATED_DATA,
- element.getSimpleName(),
- element.getAnnotationMirrors());
-
- TypeElement annotation =
- Processors.getAnnotationClassValue(elements, annotationMirror, "value");
-
- builder.add(ClassName.get(annotation));
- }
- // 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.
- builder.add(ClassNames.PRODUCTION_COMPONENT);
- return builder.build();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/originatingelement/BUILD b/java/dagger/hilt/processor/internal/originatingelement/BUILD
deleted file mode 100644
index 50dbcf6..0000000
--- a/java/dagger/hilt/processor/internal/originatingelement/BUILD
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A processor for @dagger.hilt.codegen.OriginatingElement.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor",
- deps = [":processor_lib"],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "OriginatingElementProcessor.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/guava:collect",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java b/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java
deleted file mode 100644
index 723cf04..0000000
--- a/java/dagger/hilt/processor/internal/originatingelement/OriginatingElementProcessor.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.originatingelement;
-
-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 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.codegen.OriginatingElement} to check
- * that they're only used on top-level classes and the value passed is also a top-level class.
- */
-@IncrementalAnnotationProcessor(ISOLATING)
-@AutoService(Processor.class)
-public final class OriginatingElementProcessor extends BaseProcessor {
-
- @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);
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/BUILD b/java/dagger/hilt/processor/internal/root/BUILD
deleted file mode 100644
index 709eb7f..0000000
--- a/java/dagger/hilt/processor/internal/root/BUILD
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Annotation processor for Hilt.
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.root.RootProcessor",
- deps = [
- ":processor_lib",
- ],
-)
-
-java_library(
- name = "processor_lib",
- srcs = [
- "RootFileFormatter.java",
- "RootGenerator.java",
- "RootProcessor.java",
- "TestComponentDataGenerator.java",
- "TestComponentDataSupplierGenerator.java",
- "TestInjectorGenerator.java",
- ],
- deps = [
- ":root_metadata",
- ":root_type",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:component_descriptor",
- "//java/dagger/hilt/processor/internal:component_names",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
- "//java/dagger/hilt/processor/internal/definecomponent:define_components",
- "//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "root_metadata",
- srcs = [
- "Root.java",
- "RootMetadata.java",
- "TestRootMetadata.java",
- ],
- deps = [
- ":root_type",
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:component_descriptor",
- "//java/dagger/hilt/processor/internal:kotlin",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "//java/dagger/hilt/processor/internal/aggregateddeps:component_dependencies",
- "//java/dagger/hilt/processor/internal/aliasof:alias_ofs",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-java_library(
- name = "root_type",
- srcs = ["RootType.java"],
- deps = [
- "//java/dagger/hilt/processor/internal:classnames",
- "//java/dagger/hilt/processor/internal:processor_errors",
- "//java/dagger/hilt/processor/internal:processors",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/processor/internal/root/Root.java b/java/dagger/hilt/processor/internal/root/Root.java
deleted file mode 100644
index 981636d..0000000
--- a/java/dagger/hilt/processor/internal/root/Root.java
+++ /dev/null
@@ -1,54 +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.root;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.value.AutoValue;
-import com.squareup.javapoet.ClassName;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/** Metadata for a root element that can trigger the {@link RootProcessor}. */
-@AutoValue
-abstract class Root {
- /** Creates a {@plainlink Root root} for the given {@plainlink Element element}. */
- static Root create(Element element, ProcessingEnvironment env) {
- TypeElement rootElement = MoreElements.asType(element);
- return new AutoValue_Root(RootType.of(env, rootElement), rootElement);
- }
-
- /** Returns the type of the root {@code element}. */
- abstract RootType type();
-
- /** Returns the root element that should be used with processing. */
- abstract TypeElement element();
-
- /** Returns the class name of the root element. */
- ClassName classname() {
- return ClassName.get(element());
- }
-
- @Override
- public final String toString() {
- return element().toString();
- }
-
- boolean isTestRoot() {
- return type().isTestRoot();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/RootFileFormatter.java b/java/dagger/hilt/processor/internal/root/RootFileFormatter.java
deleted file mode 100644
index 45cdd22..0000000
--- a/java/dagger/hilt/processor/internal/root/RootFileFormatter.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-import com.squareup.javapoet.JavaFile;
-import java.io.IOException;
-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
- * exists to add new lines inbetween interfaces. This can be important for classes with many
- * interfaces (e.g. Dagger components) to avoid spamming the entire list of interfaces when
- * reporting errors to the user.
- *
- * <p>See b/33108646.
- */
-final class RootFileFormatter {
- 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]);
-
- 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()) {
- writer.write(fileContent);
- } catch (Exception e) {
- try {
- filerSourceFile.delete();
- } catch (Exception ignored) {
- // Nothing to do.
- }
- throw e;
- }
- }
-
- private static String formatInterfaces(String content, Pattern pattern) {
- Matcher matcher = pattern.matcher(content);
- StringBuffer sb = new StringBuffer(content.length());
- while (matcher.find()) {
- MatchResult result = matcher.toMatchResult();
- String spaces = result.group(1);
- String prefix = result.group(2);
- String interfaces = result.group(3);
- String formattedInterfaces = formatInterfaces(spaces, interfaces);
- matcher.appendReplacement(
- sb, Matcher.quoteReplacement(spaces + prefix + formattedInterfaces));
- }
- matcher.appendTail(sb);
- return sb.toString();
- }
-
- private static String formatInterfaces(String prefixSpaces, String interfaces) {
- StringBuilder sb = new StringBuilder(interfaces);
- String newLine = String.format("\n%s ", prefixSpaces);
-
- // Add a line break after each interface so that there's only 1 interface per line.
- int i = 0;
- int bracketCount = 0;
- while (i >= 0 && i < sb.length()) {
- char c = sb.charAt(i++);
- if (c == '<') {
- bracketCount++;
- } else if (c == '>') {
- bracketCount--;
- } else if (c == ',' && bracketCount == 0) {
- sb.insert(i++, newLine);
- }
- }
- return sb.toString();
- }
-
- private RootFileFormatter() {}
-}
diff --git a/java/dagger/hilt/processor/internal/root/RootGenerator.java b/java/dagger/hilt/processor/internal/root/RootGenerator.java
deleted file mode 100644
index c2c55e6..0000000
--- a/java/dagger/hilt/processor/internal/root/RootGenerator.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-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 com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.graph.GraphBuilder;
-import com.google.common.graph.Graphs;
-import com.google.common.graph.MutableGraph;
-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 dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentDescriptor;
-import dagger.hilt.processor.internal.ComponentGenerator;
-import dagger.hilt.processor.internal.ComponentNames;
-import dagger.hilt.processor.internal.ComponentTree;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import java.util.Optional;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-
-/** Generates components and any other classes needed for a root. */
-final class RootGenerator {
-
- static void generate(RootMetadata metadata, ProcessingEnvironment env) throws IOException {
- new RootGenerator(
- RootMetadata.copyWithNewTree(
- metadata,
- filterDescriptors(metadata.componentTree())),
- env).generateComponents();
- }
-
- private final RootMetadata metadata;
- private final ProcessingEnvironment env;
- private final Root root;
-
- private RootGenerator(RootMetadata metadata, ProcessingEnvironment env) {
- this.metadata = metadata;
- this.env = env;
- this.root = metadata.root();
- }
-
- private void generateComponents() throws IOException {
-
- // TODO(bcorso): Consider moving all of this logic into ComponentGenerator?
- TypeSpec.Builder componentsWrapper =
- TypeSpec.classBuilder(getComponentsWrapperClassName())
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE).build());
-
- Processors.addGeneratedAnnotation(componentsWrapper, env, ClassNames.ROOT_PROCESSOR.toString());
-
- ImmutableMap<ComponentDescriptor, ClassName> subcomponentBuilderModules =
- subcomponentBuilderModules(componentsWrapper);
-
- ComponentTree componentTree = metadata.componentTree();
- for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) {
- ImmutableSet<ClassName> modules =
- ImmutableSet.<ClassName>builder()
- .addAll(toClassNames(metadata.modules(componentDescriptor.component())))
- .addAll(
- componentTree.childrenOf(componentDescriptor).stream()
- .map(subcomponentBuilderModules::get)
- .collect(toImmutableSet()))
- .build();
-
- componentsWrapper.addType(
- new ComponentGenerator(
- env,
- getComponentClassName(componentDescriptor),
- root.element(),
- Optional.empty(),
- modules,
- metadata.entryPoints(componentDescriptor.component()),
- metadata.scopes(componentDescriptor.component()),
- ImmutableList.of(),
- componentAnnotation(componentDescriptor),
- componentBuilder(componentDescriptor))
- .generate().toBuilder().addModifiers(Modifier.STATIC).build());
- }
-
- RootFileFormatter.write(
- JavaFile.builder(root.classname().packageName(), componentsWrapper.build()).build(),
- env.getFiler());
- }
-
- private static ComponentTree filterDescriptors(ComponentTree componentTree) {
- MutableGraph<ComponentDescriptor> graph =
- GraphBuilder.from(componentTree.graph()).build();
-
- componentTree.graph().nodes().forEach(graph::addNode);
- componentTree.graph().edges().forEach(graph::putEdge);
-
- // Remove components that do not have builders (besides the root component) since if
- // we didn't find any builder class, then we don't need to generate the component
- // since it would be inaccessible.
- componentTree.getComponentDescriptors().stream()
- .filter(descriptor -> !descriptor.isRoot() && !descriptor.creator().isPresent())
- .forEach(graph::removeNode);
-
- // The graph may still have nodes that are children of components that don't have builders,
- // so we need to find reachable nodes from the root and create a new graph to remove those.
- // We reuse the root from the original tree since it should not have been removed.
- return ComponentTree.from(Graphs.reachableNodes(graph, componentTree.root()));
- }
-
- private ImmutableMap<ComponentDescriptor, ClassName> subcomponentBuilderModules(
- TypeSpec.Builder componentsWrapper) throws IOException {
- ImmutableMap.Builder<ComponentDescriptor, ClassName> modules = ImmutableMap.builder();
- for (ComponentDescriptor descriptor : metadata.componentTree().getComponentDescriptors()) {
- // Root component builders don't have subcomponent builder modules
- if (!descriptor.isRoot() && descriptor.creator().isPresent()) {
- ClassName component = getComponentClassName(descriptor);
- ClassName builder = descriptor.creator().get();
- ClassName module = component.peerClass(component.simpleName() + "BuilderModule");
- componentsWrapper.addType(subcomponentBuilderModule(component, builder, module));
- modules.put(descriptor, module);
- }
- }
- return modules.build();
- }
-
- // Generates:
- // @Module(subcomponents = FooSubcomponent.class)
- // interface FooSubcomponentBuilderModule {
- // @Binds FooSubcomponentInterfaceBuilder bind(FooSubcomponent.Builder builder);
- // }
- private TypeSpec subcomponentBuilderModule(
- ClassName componentName, ClassName builderName, ClassName moduleName) throws IOException {
- TypeSpec.Builder subcomponentBuilderModule =
- TypeSpec.interfaceBuilder(moduleName)
- .addOriginatingElement(root.element())
- .addModifiers(ABSTRACT)
- .addAnnotation(
- AnnotationSpec.builder(ClassNames.MODULE)
- .addMember("subcomponents", "$T.class", componentName)
- .build())
- .addAnnotation(ClassNames.DISABLE_INSTALL_IN_CHECK)
- .addMethod(
- MethodSpec.methodBuilder("bind")
- .addModifiers(ABSTRACT, PUBLIC)
- .addAnnotation(ClassNames.BINDS)
- .returns(builderName)
- .addParameter(componentName.nestedClass("Builder"), "builder")
- .build());
-
- Processors.addGeneratedAnnotation(
- subcomponentBuilderModule, env, ClassNames.ROOT_PROCESSOR.toString());
-
- return subcomponentBuilderModule.build();
- }
-
- private Optional<TypeSpec> componentBuilder(ComponentDescriptor descriptor) {
- return descriptor
- .creator()
- .map(
- creator ->
- TypeSpec.interfaceBuilder("Builder")
- .addOriginatingElement(root.element())
- .addModifiers(STATIC, ABSTRACT)
- .addSuperinterface(creator)
- .addAnnotation(componentBuilderAnnotation(descriptor))
- .build());
- }
-
- private ClassName componentAnnotation(ComponentDescriptor componentDescriptor) {
- if (!componentDescriptor.isRoot()
- ) {
- return ClassNames.SUBCOMPONENT;
- } else {
- return ClassNames.COMPONENT;
- }
- }
-
- private ClassName componentBuilderAnnotation(ComponentDescriptor componentDescriptor) {
- if (componentDescriptor.isRoot()) {
- return ClassNames.COMPONENT_BUILDER;
- } else {
- return ClassNames.SUBCOMPONENT_BUILDER;
- }
- }
-
- private ClassName getPartialRootModuleClassName() {
- return getComponentsWrapperClassName().nestedClass("PartialRootModule");
- }
-
- private ClassName getComponentsWrapperClassName() {
- return ComponentNames.generatedComponentsWrapper(root.classname());
- }
-
- private ClassName getComponentClassName(ComponentDescriptor componentDescriptor) {
- return ComponentNames.generatedComponent(root.classname(), componentDescriptor.component());
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/RootMetadata.java b/java/dagger/hilt/processor/internal/root/RootMetadata.java
deleted file mode 100644
index 4c43f1d..0000000
--- a/java/dagger/hilt/processor/internal/root/RootMetadata.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-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 com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeName;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentDescriptor;
-import dagger.hilt.processor.internal.ComponentTree;
-import dagger.hilt.processor.internal.KotlinMetadataUtils;
-import dagger.hilt.processor.internal.Processors;
-import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
-import dagger.hilt.processor.internal.aliasof.AliasOfs;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-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. */
-public final class RootMetadata {
- private static final ClassName APPLICATION_CONTEXT_MODULE =
- ClassName.get("dagger.hilt.android.internal.modules", "ApplicationContextModule");
-
- static RootMetadata create(
- Root root,
- ComponentTree componentTree,
- ComponentDependencies deps,
- ProcessingEnvironment env) {
- RootMetadata metadata = new RootMetadata(root, componentTree, deps, env);
- metadata.validate();
- return metadata;
- }
-
- static RootMetadata copyWithNewTree(
- RootMetadata other,
- ComponentTree componentTree) {
- return create(other.root, componentTree, other.deps, other.env);
- }
-
- private final Root root;
- private final ProcessingEnvironment env;
- private final Elements elements;
- private final ComponentTree componentTree;
- private final ComponentDependencies deps;
- private final Supplier<ImmutableSetMultimap<ClassName, ClassName>> scopesByComponent =
- memoize(this::getScopesByComponentUncached);
- private final Supplier<TestRootMetadata> testRootMetadata =
- memoize(this::testRootMetadataUncached);
-
- private RootMetadata(
- Root root,
- ComponentTree componentTree,
- ComponentDependencies deps,
- ProcessingEnvironment env) {
- this.root = root;
- this.env = env;
- this.elements = env.getElementUtils();
- this.componentTree = componentTree;
- this.deps = deps;
- }
-
- public Root root() {
- return root;
- }
-
- public ComponentTree componentTree() {
- return componentTree;
- }
-
- public ComponentDependencies deps() {
- return deps;
- }
-
- public ImmutableSet<TypeElement> modules(ClassName componentName) {
- return deps.modules().get(componentName, root.classname(), root.isTestRoot());
- }
-
- public ImmutableSet<TypeName> entryPoints(ClassName componentName) {
- return ImmutableSet.<TypeName>builder()
- .addAll(getUserDefinedEntryPoints(componentName))
- .add(componentName)
- .build();
- }
-
- public ImmutableSet<ClassName> scopes(ClassName componentName) {
- return scopesByComponent.get().get(componentName);
- }
-
- /**
- * Returns all modules in the given component that do not have accessible default constructors.
- * Note that a non-static module nested in an outer class is considered to have no default
- * constructors, since an instance of the outer class is needed to construct the module. This also
- * 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) {
- return modules(componentName).stream()
- .filter(module -> !daggerCanConstruct(module))
- .filter(module -> !APPLICATION_CONTEXT_MODULE.equals(ClassName.get(module)))
- .collect(toImmutableSet());
- }
-
- public TestRootMetadata testRootMetadata() {
- return testRootMetadata.get();
- }
-
- public boolean waitForBindValue() {
- return false;
- }
-
- private TestRootMetadata testRootMetadataUncached() {
- return TestRootMetadata.of(env, root().element());
- }
-
- /**
- * Validates that the {@link RootType} annotation is compatible with its {@link TypeElement} and
- * {@link ComponentDependencies}.
- */
- private void validate() {
-
- // 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)) {
- if (root.type().isTestRoot() && !componentName.equals(ClassNames.SINGLETON_COMPONENT)) {
- env.getMessager()
- .printMessage(
- Diagnostic.Kind.ERROR,
- "[Hilt] All test modules (unless installed in ApplicationComponent) must use "
- + "static provision methods or have a visible, no-arg constructor. Found: "
- + extraModule.getQualifiedName(),
- root.element());
- } else if (!root.type().isTestRoot()) {
- env.getMessager()
- .printMessage(
- Diagnostic.Kind.ERROR,
- "[Hilt] All modules must be static and use static provision methods or have a "
- + "visible, no-arg constructor. Found: "
- + extraModule.getQualifiedName(),
- root.element());
- }
- }
- }
- }
-
- private ImmutableSet<TypeName> getUserDefinedEntryPoints(ClassName componentName) {
- ImmutableSet.Builder<TypeName> entryPointSet = ImmutableSet.builder();
- entryPointSet.add(ClassNames.GENERATED_COMPONENT);
- for (TypeElement element :
- deps.entryPoints().get(componentName, root.classname(), root.isTestRoot())) {
- entryPointSet.add(ClassName.get(element));
- }
- return entryPointSet.build();
- }
-
- private ImmutableSetMultimap<ClassName, ClassName> getScopesByComponentUncached() {
- ImmutableSetMultimap.Builder<ClassName, ClassName> builder = ImmutableSetMultimap.builder();
-
- ImmutableSet<ClassName> defineComponentScopes =
- componentTree.getComponentDescriptors().stream()
- .flatMap(descriptor -> descriptor.scopes().stream())
- .collect(toImmutableSet());
-
- AliasOfs aliasOfs = new AliasOfs(env, defineComponentScopes);
-
- for (ComponentDescriptor componentDescriptor : componentTree.getComponentDescriptors()) {
- for (ClassName scope : componentDescriptor.scopes()) {
- builder.put(componentDescriptor.component(), scope);
- builder.putAll(componentDescriptor.component(), aliasOfs.getAliasesFor(scope));
- }
- }
-
- return builder.build();
- }
-
- private static boolean daggerCanConstruct(TypeElement type) {
- KotlinMetadataUtil metadataUtil = KotlinMetadataUtils.getMetadataUtil();
- boolean isKotlinObject =
- metadataUtil.isObjectClass(type) || metadataUtil.isCompanionObjectClass(type);
- if (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;
- }
-
- return !isInnerClass(type)
- && !hasNonDaggerAbstractMethod(type)
- && (hasOnlyStaticProvides(type) || hasVisibleEmptyConstructor(type));
- }
-
- private static boolean isInnerClass(TypeElement type) {
- return type.getNestingKind().isNested() && !type.getModifiers().contains(STATIC);
- }
-
- private static boolean hasNonDaggerAbstractMethod(TypeElement type) {
- // TODO(erichang): Actually this isn't really supported b/28989613
- return ElementFilter.methodsIn(type.getEnclosedElements()).stream()
- .filter(method -> method.getModifiers().contains(ABSTRACT))
- .anyMatch(method -> !Processors.hasDaggerAbstractMethodAnnotation(method));
- }
-
- private static boolean hasOnlyStaticProvides(TypeElement 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));
- }
-
- private static boolean hasVisibleEmptyConstructor(TypeElement type) {
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
- return constructors.isEmpty()
- || constructors.stream()
- .filter(constructor -> constructor.getParameters().isEmpty())
- .anyMatch(constructor -> !constructor.getModifiers().contains(PRIVATE));
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/RootProcessor.java b/java/dagger/hilt/processor/internal/root/RootProcessor.java
deleted file mode 100644
index 8f8c948..0000000
--- a/java/dagger/hilt/processor/internal/root/RootProcessor.java
+++ /dev/null
@@ -1,181 +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.root;
-
-import static com.google.common.base.Preconditions.checkState;
-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.AGGREGATING;
-
-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.ComponentTree;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
-import dagger.hilt.processor.internal.definecomponent.DefineComponents;
-import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
-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(AGGREGATING)
-@AutoService(Processor.class)
-public final class RootProcessor extends BaseProcessor {
- private final List<ClassName> rootNames = new ArrayList<>();
- private final Set<ClassName> processed = new HashSet<>();
- private boolean isTestEnv;
- // TODO(bcorso): Consider using a Dagger component to create/scope these objects
- private final DefineComponents defineComponents = DefineComponents.create();
- private GeneratesRootInputs generatesRootInputs;
-
- @Override
- public synchronized void init(ProcessingEnvironment processingEnvironment) {
- super.init(processingEnvironment);
- generatesRootInputs = new GeneratesRootInputs(processingEnvironment);
- }
-
- @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);
- boolean isTestRoot = RootType.of(getProcessingEnv(), rootElement).isTestRoot();
- checkState(
- rootNames.isEmpty() || isTestEnv == isTestRoot,
- "Cannot mix test roots with non-test roots:"
- + "\n\tNon-Test Roots: %s"
- + "\n\tTest Roots: %s",
- isTestRoot ? rootNames : rootElement,
- isTestRoot ? rootElement : rootNames);
- isTestEnv = isTestRoot;
-
- rootNames.add(ClassName.get(rootElement));
- if (isTestEnv) {
- new TestInjectorGenerator(
- getProcessingEnv(),
- TestRootMetadata.of(getProcessingEnv(), rootElement)).generate();
- } else {
- ProcessorErrors.checkState(
- rootNames.size() <= 1, element, "More than one root found: %s", rootNames);
- }
- }
-
- @Override
- public void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
- Set<Element> newElements = generatesRootInputs.getElementsToWaitFor(roundEnv);
- if (!processed.isEmpty() ) {
- 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);
- }
-
- if (!newElements.isEmpty()) {
- // Skip further processing since there's new elements that generate root inputs in this round.
- return;
- }
-
- ImmutableList<Root> rootsToProcess =
- rootNames.stream()
- .filter(rootName -> !processed.contains(rootName))
- // We create a new root element each round to avoid the jdk8 bug where
- // TypeElement.equals does not work for elements across processing rounds.
- .map(rootName -> getElementUtils().getTypeElement(rootName.toString()))
- .map(rootElement -> Root.create(rootElement, getProcessingEnv()))
- .collect(toImmutableList());
-
- if (rootsToProcess.isEmpty()) {
- // Skip further processing since there's no roots that need processing.
- return;
- }
-
- // TODO(bcorso): Currently, if there's an exception in any of the roots we stop processing
- // all roots. We should consider if it's worth trying to continue processing for other
- // roots. At the moment, I think it's rare that if one root failed the others would not.
- try {
- ComponentTree tree = defineComponents.getComponentTree(getElementUtils());
- ComponentDependencies deps = ComponentDependencies.from(
- tree.getComponentDescriptors(), getElementUtils());
- ImmutableList<RootMetadata> rootMetadatas =
- rootsToProcess.stream()
- .map(root -> RootMetadata.create(root, tree, deps, getProcessingEnv()))
- .collect(toImmutableList());
-
- for (RootMetadata rootMetadata : rootMetadatas) {
- setProcessingState(rootMetadata.root());
- generateComponents(rootMetadata);
- }
-
- if (isTestEnv) {
- generateTestComponentData(rootMetadatas);
- }
- } catch (Exception e) {
- for (Root root : rootsToProcess) {
- processed.add(root.classname());
- }
- throw e;
- }
- }
-
- private void setProcessingState(Root root) {
- processed.add(root.classname());
- }
-
- private void generateComponents(RootMetadata rootMetadata) throws IOException {
- RootGenerator.generate(rootMetadata, getProcessingEnv());
- }
-
- private void generateTestComponentData(ImmutableList<RootMetadata> rootMetadatas)
- 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(), rootMetadata).generate();
- }
- new TestComponentDataSupplierGenerator(getProcessingEnv(), rootMetadatas).generate();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/RootType.java b/java/dagger/hilt/processor/internal/root/RootType.java
deleted file mode 100644
index 3545231..0000000
--- a/java/dagger/hilt/processor/internal/root/RootType.java
+++ /dev/null
@@ -1,60 +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.root;
-
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
-
-/** The valid root types for Hilt applications. */
-// TODO(erichang): Fix this class so we don't have to have placeholders
- enum RootType {
- ROOT(ClassNames.HILT_ANDROID_APP),
-
- // Placeholder to make sure @HiltAndroidTest usages get processed
- HILT_ANDROID_TEST_ROOT(ClassNames.HILT_ANDROID_TEST),
-
- TEST_ROOT(ClassNames.INTERNAL_TEST_ROOT);
-
- @SuppressWarnings("ImmutableEnumChecker")
- private final ClassName annotation;
-
- RootType(ClassName annotation) {
- this.annotation = annotation;
- }
-
- public boolean isTestRoot() {
- return this == TEST_ROOT;
- }
-
- public ClassName className() {
- return annotation;
- }
-
- public static RootType of(ProcessingEnvironment env, TypeElement element) {
- if (Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_APP)) {
- return ROOT;
- } else if (Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_TEST)) {
- return TEST_ROOT;
- } else if (Processors.hasAnnotation(element, 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
deleted file mode 100644
index 284f8cd..0000000
--- a/java/dagger/hilt/processor/internal/root/TestComponentDataGenerator.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.constructorsIn;
-
-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;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentNames;
-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 RootMetadata rootMetadata;
- private final ClassName name;
-
- public TestComponentDataGenerator(
- ProcessingEnvironment processingEnv,
- RootMetadata rootMetadata) {
- this.processingEnv = processingEnv;
- this.rootMetadata = rootMetadata;
- this.name =
- Processors.append(
- Processors.getEnclosedClassName(rootMetadata.testRootMetadata().testName()),
- "_ComponentDataHolder");
- }
-
- /**
- *
- *
- * <pre><code>{@code
- * public final class FooTest_ComponentDataHolder {
- * public static TestComponentData get() {
- * return new TestComponentData(
- * false, // waitForBindValue
- * testInstance -> injectInternal(($1T) testInstance),
- * Arrays.asList(FooTest.TestModule.class, ...),
- * modules ->
- * DaggerFooTest_ApplicationComponent.builder()
- * .applicationContextModule(
- * new ApplicationContextModule(ApplicationProvider.getApplicationContext()))
- * .testModule((FooTest.TestModule) modules.get(FooTest.TestModule.class))
- * .testModule(modules.containsKey(FooTest.TestModule.class)
- * ? (FooTest.TestModule) modules.get(FooTest.TestModule.class)
- * : ((TestInstace) testInstance).new TestModule())
- * .build());
- * }
- * }
- * }</code></pre>
- */
- public void generate() throws IOException {
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(name)
- .addModifiers(PUBLIC, FINAL)
- .addMethod(MethodSpec.constructorBuilder().addModifiers(PRIVATE).build())
- .addMethod(getMethod())
- .addMethod(getTestInjectInternalMethod());
-
- Processors.addGeneratedAnnotation(
- generator, processingEnv, ClassNames.ROOT_PROCESSOR.toString());
-
- JavaFile.builder(rootMetadata.testRootMetadata().testName().packageName(), generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-
- private MethodSpec getMethod() {
- TypeElement testElement = rootMetadata.testRootMetadata().testElement();
- ClassName component =
- ComponentNames.generatedComponent(
- ClassName.get(testElement), ClassNames.SINGLETON_COMPONENT);
- ImmutableSet<TypeElement> daggerRequiredModules =
- rootMetadata.modulesThatDaggerCannotConstruct(ClassNames.SINGLETON_COMPONENT);
- ImmutableSet<TypeElement> hiltRequiredModules =
- daggerRequiredModules.stream()
- .filter(module -> !canBeConstructedByHilt(module, testElement))
- .collect(toImmutableSet());
-
- return MethodSpec.methodBuilder("get")
- .addModifiers(PUBLIC, STATIC)
- .returns(ClassNames.TEST_COMPONENT_DATA)
- .addStatement(
- "return new $T($L, $L, $L, $L, $L)",
- ClassNames.TEST_COMPONENT_DATA,
- rootMetadata.waitForBindValue(),
- CodeBlock.of("testInstance -> injectInternal(($1T) testInstance)", testElement),
- getElementsListed(daggerRequiredModules),
- getElementsListed(hiltRequiredModules),
- CodeBlock.of(
- "(modules, testInstance, autoAddModuleEnabled) -> $T.builder()\n"
- + ".applicationContextModule(new $T($T.getApplicationContext()))\n"
- + "$L"
- + ".build()",
- Processors.prepend(Processors.getEnclosedClassName(component), "Dagger"),
- ClassNames.APPLICATION_CONTEXT_MODULE,
- ClassNames.APPLICATION_PROVIDER,
- daggerRequiredModules.stream()
- .map(module -> getAddModuleStatement(module, testElement))
- .collect(joining("\n"))))
- .build();
- }
-
- /**
- *
- *
- * <pre><code>
- * .testModule(modules.get(FooTest.TestModule.class))
- * </code></pre>
- *
- * <pre><code>
- * .testModule(autoAddModuleEnabled
- * ? ((FooTest) testInstance).new TestModule()
- * : (FooTest.TestModule) modules.get(FooTest.TestModule.class))
- * </code></pre>
- */
- private static String getAddModuleStatement(TypeElement module, TypeElement testElement) {
- ClassName className = ClassName.get(module);
- return canBeConstructedByHilt(module, testElement)
- ? CodeBlock.of(
- ".$1L(autoAddModuleEnabled\n"
- // testInstance can never be null if we reach here, because this flag can be
- // turned on only when testInstance is not null
- + " ? (($3T) testInstance).new $4L()\n"
- + " : ($2T) modules.get($2T.class))",
- Processors.upperToLowerCamel(className.simpleName()),
- className,
- className.enclosingClassName(),
- className.simpleName())
- .toString()
- : CodeBlock.of(
- ".$1L(($2T) modules.get($2T.class))",
- Processors.upperToLowerCamel(className.simpleName()),
- className)
- .toString();
- }
-
- private static boolean canBeConstructedByHilt(TypeElement module, TypeElement testElement) {
- return hasOnlyAccessibleNoArgConstructor(module)
- && module.getEnclosingElement().equals(testElement);
- }
-
- private static boolean hasOnlyAccessibleNoArgConstructor(TypeElement module) {
- List<ExecutableElement> declaredConstructors = constructorsIn(module.getEnclosedElements());
- return declaredConstructors.isEmpty()
- || (declaredConstructors.size() == 1
- && !declaredConstructors.get(0).getModifiers().contains(PRIVATE)
- && declaredConstructors.get(0).getParameters().isEmpty());
- }
-
- /* Arrays.asList(FooTest.TestModule.class, ...) */
- private static CodeBlock getElementsListed(ImmutableSet<TypeElement> modules) {
- return modules.isEmpty()
- ? CodeBlock.of("$T.emptySet()", ClassNames.COLLECTIONS)
- : CodeBlock.of(
- "new $T<>($T.asList($L))",
- ClassNames.HASH_SET,
- ClassNames.ARRAYS,
- modules.stream()
- .map(module -> CodeBlock.of("$T.class", module).toString())
- .collect(joining(",")));
- }
-
- private MethodSpec getTestInjectInternalMethod() {
- TypeElement testElement = rootMetadata.testRootMetadata().testElement();
- ClassName testName = ClassName.get(testElement);
- return MethodSpec.methodBuilder("injectInternal")
- .addModifiers(PRIVATE, STATIC)
- .addParameter(testName, "testInstance")
- .addAnnotation(
- AnnotationSpec.builder(SuppressWarnings.class)
- .addMember("value", "$S", "unchecked")
- .build())
- .addStatement("$L.injectTest(testInstance)", getInjector(testElement))
- .build();
- }
-
- private static CodeBlock getInjector(TypeElement testElement) {
- return CodeBlock.of(
- "(($T) (($T) $T.getApplicationContext()).generatedComponent())",
- ClassNames.TEST_INJECTOR,
- ClassNames.GENERATED_COMPONENT_MANAGER,
- ClassNames.APPLICATION_PROVIDER);
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/TestComponentDataSupplierGenerator.java b/java/dagger/hilt/processor/internal/root/TestComponentDataSupplierGenerator.java
deleted file mode 100644
index e5a83b6..0000000
--- a/java/dagger/hilt/processor/internal/root/TestComponentDataSupplierGenerator.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PROTECTED;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.WildcardTypeName;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-import java.io.IOException;
-import javax.annotation.processing.ProcessingEnvironment;
-
-/** Generates an implementation of {@link dagger.hilt.android.internal.TestComponentDataSupplier} */
-public final class TestComponentDataSupplierGenerator {
- private static final ClassName TEST_COMPONENT_DATA_SUPPLIER_IMPL =
- ClassName.get("dagger.hilt.android.internal.testing", "TestComponentDataSupplierImpl");
- private static final ParameterizedTypeName CLASS_TYPE =
- ParameterizedTypeName.get(ClassNames.CLASS, WildcardTypeName.subtypeOf(TypeName.OBJECT));
- private static final ParameterizedTypeName TEST_COMPONENT_DATA_MAP_TYPE =
- ParameterizedTypeName.get(ClassNames.MAP, CLASS_TYPE, ClassNames.TEST_COMPONENT_DATA);
-
- private final ProcessingEnvironment processingEnv;
- private final ImmutableList<RootMetadata> rootMetadatas;
-
- public TestComponentDataSupplierGenerator(
- ProcessingEnvironment processingEnv,
- ImmutableList<RootMetadata> rootMetadatas) {
- this.processingEnv = processingEnv;
- this.rootMetadatas = rootMetadatas;
- }
-
- /**
- * <pre><code>{@code
- * public final class TestComponentDataSupplierImpl extends TestComponentDataSupplier {
- * private final Map<Class<?>, TestComponentData> testComponentDataMap = new HashMap<>();
- *
- * protected TestComponentDataSupplierImpl() {
- * testComponentDataMap.put(FooTest.class, new FooTest_ComponentData());
- * testComponentDataMap.put(BarTest.class, new BarTest_ComponentData());
- * ...
- * }
- *
- * @Override
- * protected Map<Class<?>, TestComponentData> get() {
- * return testComponentDataMap;
- * }
- * }
- * }</code></pre>
- */
- public void generate() throws IOException {
- TypeSpec.Builder generator =
- TypeSpec.classBuilder(TEST_COMPONENT_DATA_SUPPLIER_IMPL)
- .addModifiers(PUBLIC, FINAL)
- .superclass(ClassNames.TEST_COMPONENT_DATA_SUPPLIER)
- .addField(
- FieldSpec.builder(
- TEST_COMPONENT_DATA_MAP_TYPE, "testComponentDataMap", PRIVATE, FINAL)
- .initializer("new $T<>($L)", ClassNames.HASH_MAP, rootMetadatas.size())
- .build())
- .addMethod(constructor())
- .addMethod(getMethod());
-
- Processors.addGeneratedAnnotation(
- generator, processingEnv, ClassNames.ROOT_PROCESSOR.toString());
-
- JavaFile.builder(TEST_COMPONENT_DATA_SUPPLIER_IMPL.packageName(), generator.build())
- .build()
- .writeTo(processingEnv.getFiler());
- }
-
-
- private MethodSpec constructor() {
- MethodSpec.Builder constructor = MethodSpec.constructorBuilder();
- for (RootMetadata rootMetadata : rootMetadatas) {
- ClassName testName = rootMetadata.testRootMetadata().testName();
- ClassName testComponentDataHolderName =
- Processors.append(Processors.getEnclosedClassName(testName), "_ComponentDataHolder");
- constructor.addStatement(
- "testComponentDataMap.put($T.class, $T.get())",
- testName,
- testComponentDataHolderName);
- }
- return constructor.build();
- }
-
- private MethodSpec getMethod() {
- return MethodSpec.methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(PROTECTED)
- .returns(TEST_COMPONENT_DATA_MAP_TYPE)
- .addStatement("return testComponentDataMap")
- .build();
- }
-}
diff --git a/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java b/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java
deleted file mode 100644
index fc97fed..0000000
--- a/java/dagger/hilt/processor/internal/root/TestInjectorGenerator.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.Processors;
-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 TestRootMetadata metadata;
-
- TestInjectorGenerator(ProcessingEnvironment env, TestRootMetadata metadata) {
- this.env = env;
- this.metadata = metadata;
- }
-
- // @GeneratedEntryPoint
- // @InstallIn(SingletonComponent.class)
- // public interface FooTest_GeneratedInjector extends TestInjector<FooTest> {}
- 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(
- AnnotationSpec.builder(ClassNames.INSTALL_IN)
- .addMember("value", "$T.class", installInComponent(metadata.testElement()))
- .build())
- .addModifiers(Modifier.PUBLIC)
- .addSuperinterface(
- ParameterizedTypeName.get(ClassNames.TEST_INJECTOR, metadata.testName()))
- .addMethod(
- MethodSpec.methodBuilder("injectTest")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
- .addParameter(
- metadata.testName(),
- Processors.upperToLowerCamel(metadata.testName().simpleName()))
- .build());
-
- Processors.addGeneratedAnnotation(builder, env, getClass());
-
- JavaFile.builder(metadata.testInjectorName().packageName(), builder.build())
- .build()
- .writeTo(env.getFiler());
- }
-
- private static ClassName installInComponent(TypeElement 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
deleted file mode 100644
index 561beb7..0000000
--- a/java/dagger/hilt/processor/internal/root/TestRootMetadata.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.root;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.value.AutoValue;
-import com.squareup.javapoet.ClassName;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ProcessorErrors;
-import dagger.hilt.processor.internal.Processors;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/** Metadata class for {@code InternalTestRoot} annotated classes. */
-@AutoValue
-abstract class TestRootMetadata {
-
- /** Returns the {@link TypeElement} for the test class. */
- abstract TypeElement testElement();
-
- /** Returns the {@link TypeElement} for the base application. */
- abstract TypeElement baseElement();
-
- /** Returns the {@link ClassName} for the test class. */
- ClassName testName() {
- return ClassName.get(testElement());
- }
-
- /** Returns the {@link ClassName} for the base application. */
- ClassName baseAppName() {
- return ClassName.get(baseElement());
- }
-
- /** The name of the generated Hilt test application class for the given test name. */
- ClassName appName() {
- return Processors.append(Processors.getEnclosedClassName(testName()), "_Application");
- }
-
- /** The name of the generated Hilt test application class for the given test name. */
- ClassName testInjectorName() {
- return Processors.append(Processors.getEnclosedClassName(testName()), "_GeneratedInjector");
- }
-
- static TestRootMetadata of(ProcessingEnvironment env, Element element) {
-
- TypeElement testElement = MoreElements.asType(element);
-
- TypeElement baseElement =
- env.getElementUtils().getTypeElement(ClassNames.MULTI_DEX_APPLICATION.toString());
- ProcessorErrors.checkState(
- !Processors.hasAnnotation(element, ClassNames.ANDROID_ENTRY_POINT),
- element,
- "Tests cannot be annotated with @AndroidEntryPoint. Please use @HiltAndroidTest");
-
- ProcessorErrors.checkState(
- Processors.hasAnnotation(element, ClassNames.HILT_ANDROID_TEST),
- element,
- "Tests must be annotated with @HiltAndroidTest");
-
- return new AutoValue_TestRootMetadata(testElement, baseElement);
- }
-}
diff --git a/java/dagger/hilt/testing/BUILD b/java/dagger/hilt/testing/BUILD
deleted file mode 100644
index 3ea1c5f..0000000
--- a/java/dagger/hilt/testing/BUILD
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Testing libraries for Hilt.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "package_info",
- srcs = ["package-info.java"],
- deps = [
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
-
-java_library(
- name = "test_install_in",
- testonly = 1,
- srcs = ["TestInstallIn.java"],
- exported_plugins = [
- "//java/dagger/hilt/processor/internal/aggregateddeps:plugin",
- ],
- exports = [
- "//java/dagger/hilt/processor/internal/aggregateddeps:annotation",
- ],
- deps = [
- ":package_info",
- "//java/dagger/hilt:generates_root_input",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/java/dagger/hilt/testing/TestInstallIn.java b/java/dagger/hilt/testing/TestInstallIn.java
deleted file mode 100644
index dfe1389..0000000
--- a/java/dagger/hilt/testing/TestInstallIn.java
+++ /dev/null
@@ -1,57 +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.testing;
-
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import dagger.hilt.GeneratesRootInput;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * An annotation that replaces one or more {@link dagger.hilt.InstallIn} modules with the annotated
- * module in tests.
- *
- * <p>The annotated class must also be annotated with {@link dagger.Module}.
- *
- * <p>Example:
- *
- * <pre><code>
- * // Replaces FooModule with FakeFooModule, and installs it into the same component as FooModule.
- * {@literal @}Module
- * {@literal @}TestInstallIn(components = SingletonComponent.class, replaces = FooModule.class)
- * public final class FakeFooModule {
- * {@literal @}Provides
- * static Foo provideFoo() {
- * return new FakeFoo();
- * }
- * }
- * </code></pre>
- *
- * @see <a href="https://dagger.dev/hilt/modules">Hilt Modules</a>
- */
-@Retention(CLASS)
-@Target({ElementType.TYPE})
-@GeneratesRootInput
-public @interface TestInstallIn {
- /** Returns the component(s) into which the annotated module will be installed. */
- Class<?>[] components();
-
- /** Returns the {@link InstallIn} module(s) that the annotated class will replace in tests. */
- Class<?>[] replaces();
-}
diff --git a/java/dagger/hilt/testing/package-info.java b/java/dagger/hilt/testing/package-info.java
deleted file mode 100644
index 5837343..0000000
--- a/java/dagger/hilt/testing/package-info.java
+++ /dev/null
@@ -1,25 +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.
- */
-
-/**
- * This package contains APIs for writing tests with Hilt.
- *
- * @see <a href="https://dagger.dev/hilt/testing">Hilt Testing</a>
- */
-@ParametersAreNonnullByDefault
-package dagger.hilt.testing;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/java/dagger/internal/ConfigureInitializationParameters.java b/java/dagger/internal/ConfigureInitializationParameters.java
new file mode 100644
index 0000000..1ca0fbb
--- /dev/null
+++ b/java/dagger/internal/ConfigureInitializationParameters.java
@@ -0,0 +1,36 @@
+/*
+ * 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.internal;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a {@code configureInitialization()} method with {@code ComponentRequirement}s that it
+ * accepts as parameters.
+ */
+@Target(METHOD)
+public @interface ConfigureInitializationParameters {
+ /**
+ * The list of parameters.
+ *
+ * Each value is a {@link dagger.internal.codegen.serialization.ComponentRequirementProto}
+ * serialized in Base64.
+ */
+ String[] value() default {};
+}
diff --git a/java/dagger/internal/GenerationOptions.java b/java/dagger/internal/GenerationOptions.java
new file mode 100644
index 0000000..996cd1d
--- /dev/null
+++ b/java/dagger/internal/GenerationOptions.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Metadata annotation for base subcomponent implementations in ahead-of-time compilations. This
+ * propagates any compiler options related to code generation so that later compilations can
+ * recreate the model of the generated code of superclass implementations.
+ */
+@Target(ElementType.TYPE)
+public @interface GenerationOptions {
+ boolean fastInit();
+}
diff --git a/java/dagger/internal/InjectedFieldSignature.java b/java/dagger/internal/InjectedFieldSignature.java
deleted file mode 100644
index 55d3285..0000000
--- a/java/dagger/internal/InjectedFieldSignature.java
+++ /dev/null
@@ -1,32 +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.internal;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marks a {@link dagger.MembersInjector} method for injecting a field with the signature of the
- * field intended to inject.
- */
-@Retention(RetentionPolicy.CLASS)
-@Target(ElementType.METHOD)
-public @interface InjectedFieldSignature {
- String value();
-}
diff --git a/java/dagger/internal/MapBuilder.java b/java/dagger/internal/MapBuilder.java
index 12824d1..25e2b5b 100644
--- a/java/dagger/internal/MapBuilder.java
+++ b/java/dagger/internal/MapBuilder.java
@@ -50,9 +50,11 @@
}
public Map<K, V> build() {
- if (contributions.isEmpty()) {
- return Collections.emptyMap();
+ switch (contributions.size()) {
+ case 0:
+ return Collections.emptyMap();
+ default:
+ return Collections.unmodifiableMap(contributions);
}
- return Collections.unmodifiableMap(contributions);
}
}
diff --git a/java/dagger/internal/MapFactory.java b/java/dagger/internal/MapFactory.java
index 39748c9..8eb0783 100644
--- a/java/dagger/internal/MapFactory.java
+++ b/java/dagger/internal/MapFactory.java
@@ -66,13 +66,11 @@
super(size);
}
- @Override
public Builder<K, V> put(K key, Provider<V> providerOfValue) {
super.put(key, providerOfValue);
return this;
}
- @Override
public Builder<K, V> putAll(Provider<Map<K, V>> mapFactory) {
super.putAll(mapFactory);
return this;
diff --git a/java/dagger/internal/MissingBindingFactory.java b/java/dagger/internal/MissingBindingFactory.java
new file mode 100644
index 0000000..993d150
--- /dev/null
+++ b/java/dagger/internal/MissingBindingFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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;
+
+/**
+ * A {@link Factory} that always throws on calls to {@link Factory#get()}. This is necessary in
+ * ahead-of-time subcomponents mode, where modifiable binding methods need to return a {@code
+ * Provider<T>} to a framework instance initialization that is pruned and no longer in the binding
+ * graph, but was present in a superclass implementation. This class fulfills that requirement but
+ * is still practically unusable.
+ */
+public final class MissingBindingFactory<T> implements Factory<T> {
+ private static final MissingBindingFactory<Object> INSTANCE = new MissingBindingFactory<>();
+
+ private MissingBindingFactory() {}
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
+ public static <T> Factory<T> create() {
+ return (Factory) INSTANCE;
+ }
+
+ @Override
+ public T get() {
+ throw new AssertionError(
+ "This binding is not part of the final binding graph. The key was requested by a binding "
+ + "that was believed to possibly be part of the graph, but is no longer requested. "
+ + "If this exception is thrown, it is the result of a Dagger bug.");
+ }
+}
diff --git a/java/dagger/internal/ModifiableBinding.java b/java/dagger/internal/ModifiableBinding.java
new file mode 100644
index 0000000..1e658e4
--- /dev/null
+++ b/java/dagger/internal/ModifiableBinding.java
@@ -0,0 +1,37 @@
+/*
+ * 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.internal;
+
+import static java.lang.annotation.ElementType.METHOD;
+
+import java.lang.annotation.Target;
+
+/** Annotates methods that implement bindings that may be modified by subclass implementations. */
+@Target(METHOD)
+public @interface ModifiableBinding {
+ /** {@code ModifiableBindingType} of the binding. */
+ // TODO(ronshapiro): should this be a shared enum with dagger.internal.codegen?
+ String modifiableBindingType();
+
+ /** A {@link dagger.internal.codegen.serialization.BindingRequestProto} serialized in Base64. */
+ String bindingRequest();
+
+ /**
+ * For a multibinding, the keys of all contributions it depends on in this implementation.
+ */
+ String[] multibindingContributions() default {};
+}
diff --git a/java/dagger/internal/ModifiableModule.java b/java/dagger/internal/ModifiableModule.java
new file mode 100644
index 0000000..983321e
--- /dev/null
+++ b/java/dagger/internal/ModifiableModule.java
@@ -0,0 +1,26 @@
+/*
+ * 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.internal;
+
+/**
+ * Annotates methods that return {@linkplain dagger.Module modules} that may be modified by subclass
+ * implementations.
+ */
+public @interface ModifiableModule {
+ /** The serialized {@code ComponentRequirement} of this method's module. */
+ String value();
+}
diff --git a/java/dagger/internal/Preconditions.java b/java/dagger/internal/Preconditions.java
index 5c2d740..714a353 100644
--- a/java/dagger/internal/Preconditions.java
+++ b/java/dagger/internal/Preconditions.java
@@ -51,34 +51,6 @@
}
/**
- * Ensures that an object reference returned from a provides method is not null.
- *
- * @param reference an object reference
- * @return the non-null reference that was validated
- * @throws NullPointerException if {@code reference} is null
- */
- public static <T> T checkNotNullFromProvides(T reference) {
- if (reference == null) {
- throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
- }
- return reference;
- }
-
- /**
- * Ensures that an object reference returned from a component method is not null.
- *
- * @param reference an object reference
- * @return the non-null reference that was validated
- * @throws NullPointerException if {@code reference} is null
- */
- public static <T> T checkNotNullFromComponent(T reference) {
- if (reference == null) {
- throw new NullPointerException("Cannot return null from a non-@Nullable component method");
- }
- return reference;
- }
-
- /**
* Ensures that an object reference passed as a parameter to the calling method is not null.
*
* @param reference an object reference
diff --git a/java/dagger/internal/SetBuilder.java b/java/dagger/internal/SetBuilder.java
index d65e7cb..41a2fc7 100644
--- a/java/dagger/internal/SetBuilder.java
+++ b/java/dagger/internal/SetBuilder.java
@@ -61,12 +61,13 @@
}
public Set<T> build() {
- if (contributions.isEmpty()) {
- return Collections.emptySet();
- } else if (contributions.size() == 1) {
- return Collections.singleton(contributions.get(0));
- } else {
- return Collections.unmodifiableSet(new HashSet<>(contributions));
+ switch (contributions.size()) {
+ case 0:
+ return Collections.emptySet();
+ case 1:
+ return Collections.singleton(contributions.get(0));
+ default:
+ return Collections.unmodifiableSet(new HashSet<>(contributions));
}
}
}
diff --git a/java/dagger/internal/codegen/AnnotationCreatorGenerator.java b/java/dagger/internal/codegen/AnnotationCreatorGenerator.java
new file mode 100644
index 0000000..273f552
--- /dev/null
+++ b/java/dagger/internal/codegen/AnnotationCreatorGenerator.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 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.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.AnnotationExpression.createMethodName;
+import static dagger.internal.codegen.AnnotationExpression.getAnnotationCreatorClassName;
+import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.LinkedHashSet;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+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.type.DeclaredType;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+/**
+ * Generates classes that create annotation instances for an annotation type. The generated class
+ * will have a private empty constructor, a static method that creates the annotation type itself,
+ * and a static method that creates each annotation type that is nested in the top-level annotation
+ * type.
+ *
+ * <p>So for an example annotation:
+ *
+ * <pre>
+ * {@literal @interface} Foo {
+ * String s();
+ * int i();
+ * Bar bar(); // an annotation defined elsewhere
+ * }
+ * </pre>
+ *
+ * the generated class will look like:
+ *
+ * <pre>
+ * public final class FooCreator {
+ * private FooCreator() {}
+ *
+ * public static Foo createFoo(String s, int i, Bar bar) { … }
+ * public static Bar createBar(…) { … }
+ * }
+ * </pre>
+ */
+class AnnotationCreatorGenerator extends SourceFileGenerator<TypeElement> {
+ private static final ClassName AUTO_ANNOTATION =
+ ClassName.get("com.google.auto.value", "AutoAnnotation");
+
+ @Inject
+ AnnotationCreatorGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ }
+
+ @Override
+ ClassName nameGeneratedType(TypeElement annotationType) {
+ return getAnnotationCreatorClassName(annotationType);
+ }
+
+ @Override
+ Element originatingElement(TypeElement annotationType) {
+ return annotationType;
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, TypeElement annotationType) {
+ TypeSpec.Builder annotationCreatorBuilder =
+ classBuilder(generatedTypeName)
+ .addModifiers(PUBLIC, FINAL)
+ .addMethod(constructorBuilder().addModifiers(PRIVATE).build());
+
+ for (TypeElement annotationElement : annotationsToCreate(annotationType)) {
+ annotationCreatorBuilder.addMethod(buildCreateMethod(generatedTypeName, annotationElement));
+ }
+
+ return Optional.of(annotationCreatorBuilder);
+ }
+
+ private MethodSpec buildCreateMethod(ClassName generatedTypeName, TypeElement annotationElement) {
+ String createMethodName = createMethodName(annotationElement);
+ MethodSpec.Builder createMethod =
+ methodBuilder(createMethodName)
+ .addAnnotation(AUTO_ANNOTATION)
+ .addModifiers(PUBLIC, STATIC)
+ .returns(TypeName.get(annotationElement.asType()));
+
+ ImmutableList.Builder<CodeBlock> parameters = ImmutableList.builder();
+ for (ExecutableElement annotationMember : methodsIn(annotationElement.getEnclosedElements())) {
+ String parameterName = annotationMember.getSimpleName().toString();
+ TypeName parameterType = TypeName.get(annotationMember.getReturnType());
+ createMethod.addParameter(parameterType, parameterName);
+ parameters.add(CodeBlock.of("$L", parameterName));
+ }
+
+ ClassName autoAnnotationClass =
+ generatedTypeName.peerClass(
+ "AutoAnnotation_" + generatedTypeName.simpleName() + "_" + createMethodName);
+ createMethod.addStatement(
+ "return new $T($L)", autoAnnotationClass, makeParametersCodeBlock(parameters.build()));
+ return createMethod.build();
+ }
+
+ /**
+ * Returns the annotation types for which {@code @AutoAnnotation static Foo createFoo(…)} methods
+ * should be written.
+ */
+ protected Set<TypeElement> annotationsToCreate(TypeElement annotationElement) {
+ return nestedAnnotationElements(annotationElement, new LinkedHashSet<>());
+ }
+
+ @CanIgnoreReturnValue
+ private static Set<TypeElement> nestedAnnotationElements(
+ TypeElement annotationElement, Set<TypeElement> annotationElements) {
+ if (annotationElements.add(annotationElement)) {
+ for (ExecutableElement method : methodsIn(annotationElement.getEnclosedElements())) {
+ TRAVERSE_NESTED_ANNOTATIONS.visit(method.getReturnType(), annotationElements);
+ }
+ }
+ return annotationElements;
+ }
+
+ private static final SimpleTypeVisitor6<Void, Set<TypeElement>> TRAVERSE_NESTED_ANNOTATIONS =
+ new SimpleTypeVisitor6<Void, Set<TypeElement>>() {
+ @Override
+ public Void visitDeclared(DeclaredType t, Set<TypeElement> p) {
+ TypeElement typeElement = MoreTypes.asTypeElement(t);
+ if (typeElement.getKind() == ElementKind.ANNOTATION_TYPE) {
+ nestedAnnotationElements(typeElement, p);
+ }
+ return null;
+ }
+ };
+}
diff --git a/java/dagger/internal/codegen/AnnotationExpression.java b/java/dagger/internal/codegen/AnnotationExpression.java
new file mode 100644
index 0000000..8d729e2
--- /dev/null
+++ b/java/dagger/internal/codegen/AnnotationExpression.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2016 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.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static dagger.internal.codegen.SourceFiles.classFileName;
+import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static java.util.stream.Collectors.toList;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import java.util.List;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+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.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+/**
+ * Returns an expression creating an instance of the visited annotation type. Its parameter must be
+ * a class as generated by {@link AnnotationCreatorGenerator}.
+ *
+ * <p>Note that {@link AnnotationValue#toString()} is the source-code representation of the value
+ * <em>when used in an annotation</em>, which is not always the same as the representation needed
+ * when creating the value in a method body.
+ *
+ * <p>For example, inside an annotation, a nested array of {@code int}s is simply {@code {1, 2, 3}},
+ * but in code it would have to be {@code new int[] {1, 2, 3}}.
+ */
+class AnnotationExpression extends SimpleAnnotationValueVisitor6<CodeBlock, AnnotationValue> {
+
+ private final AnnotationMirror annotation;
+ private final ClassName creatorClass;
+
+ AnnotationExpression(AnnotationMirror annotation) {
+ this.annotation = annotation;
+ this.creatorClass =
+ getAnnotationCreatorClassName(
+ MoreTypes.asTypeElement(annotation.getAnnotationType()));
+ }
+
+ /**
+ * Returns an expression that calls static methods on the annotation's creator class to create an
+ * annotation instance equivalent the annotation passed to the constructor.
+ */
+ CodeBlock getAnnotationInstanceExpression() {
+ return getAnnotationInstanceExpression(annotation);
+ }
+
+ private CodeBlock getAnnotationInstanceExpression(AnnotationMirror annotation) {
+ return CodeBlock.of(
+ "$T.$L($L)",
+ creatorClass,
+ createMethodName(
+ MoreElements.asType(annotation.getAnnotationType().asElement())),
+ makeParametersCodeBlock(
+ getAnnotationValuesWithDefaults(annotation)
+ .entrySet()
+ .stream()
+ .map(entry -> getValueExpression(entry.getKey().getReturnType(), entry.getValue()))
+ .collect(toList())));
+ }
+
+ /**
+ * Returns the name of the generated class that contains the static {@code create} methods for an
+ * annotation type.
+ */
+ static ClassName getAnnotationCreatorClassName(TypeElement annotationType) {
+ ClassName annotationTypeName = ClassName.get(annotationType);
+ return annotationTypeName
+ .topLevelClassName()
+ .peerClass(classFileName(annotationTypeName) + "Creator");
+ }
+
+ static String createMethodName(TypeElement annotationType) {
+ return "create" + annotationType.getSimpleName();
+ }
+
+ /**
+ * Returns an expression that evaluates to a {@code value} of a given type on an {@code
+ * annotation}.
+ */
+ CodeBlock getValueExpression(TypeMirror valueType, AnnotationValue value) {
+ return ARRAY_LITERAL_PREFIX.visit(valueType, this.visit(value, value));
+ }
+
+ @Override
+ public CodeBlock visitEnumConstant(VariableElement c, AnnotationValue p) {
+ return CodeBlock.of("$T.$L", c.getEnclosingElement(), c.getSimpleName());
+ }
+
+ @Override
+ public CodeBlock visitAnnotation(AnnotationMirror a, AnnotationValue p) {
+ return getAnnotationInstanceExpression(a);
+ }
+
+ @Override
+ public CodeBlock visitType(TypeMirror t, AnnotationValue p) {
+ return CodeBlock.of("$T.class", t);
+ }
+
+ @Override
+ public CodeBlock visitString(String s, AnnotationValue p) {
+ return CodeBlock.of("$S", s);
+ }
+
+ @Override
+ public CodeBlock visitByte(byte b, AnnotationValue p) {
+ return CodeBlock.of("(byte) $L", b);
+ }
+
+ @Override
+ public CodeBlock visitChar(char c, AnnotationValue p) {
+ return CodeBlock.of("$L", p);
+ }
+
+ @Override
+ public CodeBlock visitDouble(double d, AnnotationValue p) {
+ return CodeBlock.of("$LD", d);
+ }
+
+ @Override
+ public CodeBlock visitFloat(float f, AnnotationValue p) {
+ return CodeBlock.of("$LF", f);
+ }
+
+ @Override
+ public CodeBlock visitLong(long i, AnnotationValue p) {
+ return CodeBlock.of("$LL", i);
+ }
+
+ @Override
+ public CodeBlock visitShort(short s, AnnotationValue p) {
+ return CodeBlock.of("(short) $L", s);
+ }
+
+ @Override
+ protected CodeBlock defaultAction(Object o, AnnotationValue p) {
+ return CodeBlock.of("$L", o);
+ }
+
+ @Override
+ public CodeBlock visitArray(List<? extends AnnotationValue> values, AnnotationValue p) {
+ ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
+ for (AnnotationValue value : values) {
+ codeBlocks.add(this.visit(value, p));
+ }
+ return CodeBlock.of("{$L}", makeParametersCodeBlock(codeBlocks.build()));
+ }
+
+ /**
+ * If the visited type is an array, prefixes the parameter code block with {@code new T[]}, where
+ * {@code T} is the raw array component type.
+ */
+ private static final SimpleTypeVisitor6<CodeBlock, CodeBlock> ARRAY_LITERAL_PREFIX =
+ new SimpleTypeVisitor6<CodeBlock, CodeBlock>() {
+
+ @Override
+ public CodeBlock visitArray(ArrayType t, CodeBlock p) {
+ return CodeBlock.of("new $T[] $L", RAW_TYPE_NAME.visit(t.getComponentType()), p);
+ }
+
+ @Override
+ protected CodeBlock defaultAction(TypeMirror e, CodeBlock p) {
+ return p;
+ }
+ };
+
+ /**
+ * If the visited type is an array, returns the name of its raw component type; otherwise returns
+ * the name of the type itself.
+ */
+ private static final SimpleTypeVisitor6<TypeName, Void> RAW_TYPE_NAME =
+ new SimpleTypeVisitor6<TypeName, Void>() {
+ @Override
+ public TypeName visitDeclared(DeclaredType t, Void p) {
+ return ClassName.get(MoreTypes.asTypeElement(t));
+ }
+
+ @Override
+ protected TypeName defaultAction(TypeMirror e, Void p) {
+ return TypeName.get(e);
+ }
+ };
+}
diff --git a/java/dagger/internal/codegen/AnnotationProtoConverter.java b/java/dagger/internal/codegen/AnnotationProtoConverter.java
new file mode 100644
index 0000000..282d8ca
--- /dev/null
+++ b/java/dagger/internal/codegen/AnnotationProtoConverter.java
@@ -0,0 +1,275 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Maps.transformValues;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static javax.lang.model.util.ElementFilter.fieldsIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import dagger.internal.codegen.serialization.AnnotationProto;
+import dagger.internal.codegen.serialization.AnnotationValueProto;
+import java.util.Collections;
+import java.util.List;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+
+/** Converts {@link AnnotationMirror}s to {@link AnnotationProto}s and vice-versa. */
+final class AnnotationProtoConverter {
+ private final TypeProtoConverter typeProtoConverter;
+
+ @Inject
+ AnnotationProtoConverter(TypeProtoConverter typeProtoConverter) {
+ this.typeProtoConverter = typeProtoConverter;
+ }
+
+ /** Translates an {@link AnnotationMirror} to a proto representation. */
+ static AnnotationProto toProto(AnnotationMirror annotationMirror) {
+ AnnotationProto.Builder builder = AnnotationProto.newBuilder();
+ builder.setAnnotationType(TypeProtoConverter.toProto(annotationMirror.getAnnotationType()));
+ getAnnotationValuesWithDefaults(annotationMirror)
+ .forEach(
+ (attribute, value) ->
+ builder.putAllValues(
+ Collections.singletonMap(
+ attribute.getSimpleName().toString(), annotationValueProto(value))));
+ return builder.build();
+ }
+
+ /** Creates an {@link AnnotationMirror} from its proto representation. */
+ AnnotationMirror fromProto(AnnotationProto annotation) {
+ return SimpleAnnotationMirror.of(
+ MoreTypes.asTypeElement(typeProtoConverter.fromProto(annotation.getAnnotationType())),
+ transformValues(annotation.getValues(), AnnotationValueFromProto::new));
+ }
+
+ private static final AnnotationValueVisitor<
+ AnnotationValueProto.Builder, AnnotationValueProto.Builder>
+ ANNOTATION_VALUE_TO_PROTO =
+ new SimpleAnnotationValueVisitor8<
+ AnnotationValueProto.Builder, AnnotationValueProto.Builder>() {
+ @Override
+ public AnnotationValueProto.Builder visitAnnotation(
+ AnnotationMirror nestedAnnotation, AnnotationValueProto.Builder builder) {
+ return builder
+ .setNestedAnnotation(toProto(nestedAnnotation))
+ .setKind(AnnotationValueProto.Kind.ANNOTATION);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitBoolean(
+ boolean b, AnnotationValueProto.Builder builder) {
+ return builder.setBooleanValue(b).setKind(AnnotationValueProto.Kind.BOOLEAN);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitChar(
+ char c, AnnotationValueProto.Builder builder) {
+ return builder
+ .setStringValue(String.valueOf(c))
+ .setKind(AnnotationValueProto.Kind.CHAR);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitByte(
+ byte b, AnnotationValueProto.Builder builder) {
+ return builder.setIntValue(b).setKind(AnnotationValueProto.Kind.BYTE);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitShort(
+ short s, AnnotationValueProto.Builder builder) {
+ return builder.setIntValue(s).setKind(AnnotationValueProto.Kind.SHORT);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitInt(
+ int i, AnnotationValueProto.Builder builder) {
+ return builder.setIntValue(i).setKind(AnnotationValueProto.Kind.INT);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitFloat(
+ float f, AnnotationValueProto.Builder builder) {
+ return builder.setFloatValue(f).setKind(AnnotationValueProto.Kind.FLOAT);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitLong(
+ long l, AnnotationValueProto.Builder builder) {
+ return builder.setLongValue(l).setKind(AnnotationValueProto.Kind.LONG);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitDouble(
+ double d, AnnotationValueProto.Builder builder) {
+ return builder.setDoubleValue(d).setKind(AnnotationValueProto.Kind.DOUBLE);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitString(
+ String s, AnnotationValueProto.Builder builder) {
+ return builder.setStringValue(s).setKind(AnnotationValueProto.Kind.STRING);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitType(
+ TypeMirror t, AnnotationValueProto.Builder builder) {
+ return builder
+ .setClassLiteral(TypeProtoConverter.toProto(t))
+ .setKind(AnnotationValueProto.Kind.CLASS_LITERAL);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitEnumConstant(
+ VariableElement c, AnnotationValueProto.Builder builder) {
+ return builder
+ .setEnumType(TypeProtoConverter.toProto(c.asType()))
+ .setEnumName(c.getSimpleName().toString())
+ .setKind(AnnotationValueProto.Kind.ENUM);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitArray(
+ List<? extends AnnotationValue> values, AnnotationValueProto.Builder builder) {
+ values.forEach(value -> builder.addArrayValues(annotationValueProto(value)));
+ return builder.setKind(AnnotationValueProto.Kind.ARRAY);
+ }
+
+ @Override
+ public AnnotationValueProto.Builder visitUnknown(
+ AnnotationValue av, AnnotationValueProto.Builder builder) {
+ throw new UnsupportedOperationException(av.toString());
+ }
+ };
+
+ /** Translates an {@link AnnotationValue} to a proto representation. */
+ private static AnnotationValueProto annotationValueProto(AnnotationValue annotationValue) {
+ return annotationValue
+ .accept(ANNOTATION_VALUE_TO_PROTO, AnnotationValueProto.newBuilder())
+ .build();
+ }
+
+ private class AnnotationValueFromProto implements AnnotationValue {
+ private final AnnotationValueProto proto;
+
+ AnnotationValueFromProto(AnnotationValueProto proto) {
+ this.proto = proto;
+ }
+
+ @Override
+ public Object getValue() {
+ switch (proto.getKind()) {
+ case BOOLEAN:
+ return proto.getBooleanValue();
+ case BYTE:
+ return (byte) proto.getIntValue();
+ case SHORT:
+ return (short) proto.getIntValue();
+ case CHAR:
+ return getCharValue();
+ case INT:
+ return proto.getIntValue();
+ case FLOAT:
+ return proto.getFloatValue();
+ case LONG:
+ return proto.getLongValue();
+ case DOUBLE:
+ return proto.getDoubleValue();
+ case STRING:
+ return proto.getStringValue();
+ case CLASS_LITERAL:
+ return typeProtoConverter.fromProto(proto.getClassLiteral());
+ case ENUM:
+ return getEnumConstant();
+ case ANNOTATION:
+ return fromProto(proto.getNestedAnnotation());
+ case ARRAY:
+ return getArrayValues();
+ case UNKNOWN:
+ case UNRECOGNIZED:
+ // fall through
+ }
+ throw new AssertionError(proto);
+ }
+
+ @Override
+ public <R, P> R accept(AnnotationValueVisitor<R, P> visitor, P passedValue) {
+ switch (proto.getKind()) {
+ case BOOLEAN:
+ return visitor.visitBoolean(proto.getBooleanValue(), passedValue);
+ case BYTE:
+ return visitor.visitByte((byte) proto.getIntValue(), passedValue);
+ case SHORT:
+ return visitor.visitShort((short) proto.getIntValue(), passedValue);
+ case CHAR:
+ return visitor.visitChar(getCharValue(), passedValue);
+ case INT:
+ return visitor.visitInt(proto.getIntValue(), passedValue);
+ case FLOAT:
+ return visitor.visitFloat(proto.getFloatValue(), passedValue);
+ case LONG:
+ return visitor.visitLong(proto.getLongValue(), passedValue);
+ case DOUBLE:
+ return visitor.visitDouble(proto.getDoubleValue(), passedValue);
+ case STRING:
+ return visitor.visitString((String) getValue(), passedValue);
+ case CLASS_LITERAL:
+ return visitor.visitType((TypeMirror) getValue(), passedValue);
+ case ENUM:
+ return visitor.visitEnumConstant((VariableElement) getValue(), passedValue);
+ case ANNOTATION:
+ return visitor.visitAnnotation((AnnotationMirror) getValue(), passedValue);
+ case ARRAY:
+ return visitor.visitArray(getArrayValues(), passedValue);
+ case UNKNOWN:
+ case UNRECOGNIZED:
+ // fall through
+ }
+ throw new AssertionError(proto);
+ }
+
+ private char getCharValue() {
+ checkState(proto.getKind().equals(AnnotationValueProto.Kind.CHAR));
+ return proto.getStringValue().charAt(0);
+ }
+
+ private VariableElement getEnumConstant() {
+ checkState(proto.getKind().equals(AnnotationValueProto.Kind.ENUM));
+ TypeMirror enumType = typeProtoConverter.fromProto(proto.getEnumType());
+ return fieldsIn(MoreTypes.asTypeElement(enumType).getEnclosedElements()).stream()
+ .filter(value -> value.getSimpleName().contentEquals(proto.getEnumName()))
+ .findFirst()
+ .get();
+ }
+
+ private ImmutableList<AnnotationValue> getArrayValues() {
+ checkState(proto.getKind().equals(AnnotationValueProto.Kind.ARRAY));
+ return proto.getArrayValuesList().stream()
+ .map(AnnotationValueFromProto::new)
+ .collect(toImmutableList());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/AnonymousProviderCreationExpression.java b/java/dagger/internal/codegen/AnonymousProviderCreationExpression.java
new file mode 100644
index 0000000..fc30eaa
--- /dev/null
+++ b/java/dagger/internal/codegen/AnonymousProviderCreationExpression.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.javapoet.CodeBlocks.anonymousProvider;
+import static dagger.model.RequestKind.INSTANCE;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.javapoet.Expression;
+
+/**
+ * A {@link javax.inject.Provider} creation expression for an anonymous inner class whose
+ * {@code get()} method returns the expression for an instance binding request for its key.
+ */
+final class AnonymousProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final ContributionBinding binding;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ClassName requestingClass;
+
+ AnonymousProviderCreationExpression(
+ ContributionBinding binding,
+ ComponentBindingExpressions componentBindingExpressions,
+ ClassName requestingClass) {
+ this.binding = binding;
+ this.componentBindingExpressions = componentBindingExpressions;
+ this.requestingClass = requestingClass;
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ BindingRequest instanceExpressionRequest = bindingRequest(binding.key(), INSTANCE);
+ Expression instanceExpression =
+ componentBindingExpressions.getDependencyExpression(
+ instanceExpressionRequest,
+ // Not a real class name, but the actual requestingClass is an inner class within the
+ // given class, not that class itself.
+ requestingClass.nestedClass("Anonymous"));
+ return anonymousProvider(instanceExpression);
+ }
+}
diff --git a/java/dagger/internal/codegen/AnyBindingMethodValidator.java b/java/dagger/internal/codegen/AnyBindingMethodValidator.java
new file mode 100644
index 0000000..bad9636
--- /dev/null
+++ b/java/dagger/internal/codegen/AnyBindingMethodValidator.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+
+/** Validates any binding method. */
+final class AnyBindingMethodValidator {
+
+ private final ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> validators;
+ private final Map<ExecutableElement, ValidationReport<ExecutableElement>> reports =
+ new HashMap<>();
+
+ @Inject
+ AnyBindingMethodValidator(
+ ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> validators) {
+ this.validators = validators;
+ }
+
+ /** Returns the binding method annotations considered by this validator. */
+ ImmutableSet<Class<? extends Annotation>> methodAnnotations() {
+ return validators.keySet();
+ }
+
+ /**
+ * Returns {@code true} if {@code method} is annotated with at least one of {@link
+ * #methodAnnotations()}.
+ */
+ boolean isBindingMethod(ExecutableElement method) {
+ return isAnyAnnotationPresent(method, methodAnnotations());
+ }
+
+ /**
+ * Returns a validation report for a method.
+ *
+ * <ul>
+ * <li>Reports an error if {@code method} is annotated with more than one {@linkplain
+ * #methodAnnotations() binding method annotation}.
+ * <li>Validates {@code method} with the {@link BindingMethodValidator} for the single
+ * {@linkplain #methodAnnotations() binding method annotation}.
+ * </ul>
+ *
+ * @throws IllegalArgumentException if {@code method} is not annotated by any {@linkplain
+ * #methodAnnotations() binding method annotation}
+ */
+ ValidationReport<ExecutableElement> validate(ExecutableElement method) {
+ return reentrantComputeIfAbsent(reports, method, this::validateUncached);
+ }
+
+ /**
+ * Returns {@code true} if {@code method} was already {@linkplain #validate(ExecutableElement)
+ * validated}.
+ */
+ boolean wasAlreadyValidated(ExecutableElement method) {
+ return reports.containsKey(method);
+ }
+
+ private ValidationReport<ExecutableElement> validateUncached(ExecutableElement method) {
+ ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(method);
+ ImmutableSet<? extends Class<? extends Annotation>> bindingMethodAnnotations =
+ methodAnnotations()
+ .stream()
+ .filter(annotation -> isAnnotationPresent(method, annotation))
+ .collect(toImmutableSet());
+ switch (bindingMethodAnnotations.size()) {
+ case 0:
+ throw new IllegalArgumentException(
+ String.format("%s has no binding method annotation", method));
+
+ case 1:
+ report.addSubreport(
+ validators.get(getOnlyElement(bindingMethodAnnotations)).validate(method));
+ break;
+
+ default:
+ report.addError(
+ String.format(
+ "%s is annotated with more than one of (%s)",
+ method.getSimpleName(),
+ methodAnnotations().stream().map(Class::getCanonicalName).collect(joining(", "))),
+ method);
+ break;
+ }
+ return report.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java b/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java
deleted file mode 100644
index abc0436..0000000
--- a/java/dagger/internal/codegen/AssistedFactoryProcessingStep.java
+++ /dev/null
@@ -1,360 +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.internal.codegen;
-
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.INSTANCE_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-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 com.squareup.javapoet.TypeVariableName;
-import dagger.assisted.AssistedFactory;
-import dagger.internal.codegen.base.SourceFileGenerationException;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedFactoryMetadata;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedParameter;
-import dagger.internal.codegen.binding.BindingFactory;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
-import java.util.HashSet;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-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.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/** An annotation processor for {@link dagger.assisted.AssistedFactory}-annotated types. */
-final class AssistedFactoryProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final Filer filer;
- private final SourceVersion sourceVersion;
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final BindingFactory bindingFactory;
-
- @Inject
- AssistedFactoryProcessingStep(
- Messager messager,
- Filer filer,
- SourceVersion sourceVersion,
- DaggerElements elements,
- DaggerTypes types,
- BindingFactory bindingFactory) {
- super(MoreElements::asType);
- this.messager = messager;
- this.filer = filer;
- this.sourceVersion = sourceVersion;
- this.elements = elements;
- this.types = types;
- this.bindingFactory = bindingFactory;
- }
-
- @Override
- public ImmutableSet<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(AssistedFactory.class);
- }
-
- @Override
- protected void process(
- TypeElement factory, ImmutableSet<Class<? extends Annotation>> annotations) {
- ValidationReport<TypeElement> report = new AssistedFactoryValidator().validate(factory);
- report.printMessagesTo(messager);
- if (report.isClean()) {
- try {
- ProvisionBinding binding = bindingFactory.assistedFactoryBinding(factory, Optional.empty());
- new AssistedFactoryImplGenerator().generate(binding);
- } catch (SourceFileGenerationException e) {
- e.printMessageTo(messager);
- }
- }
- }
-
- private final class AssistedFactoryValidator {
- ValidationReport<TypeElement> validate(TypeElement factory) {
- ValidationReport.Builder<TypeElement> report = ValidationReport.about(factory);
-
- if (!factory.getModifiers().contains(ABSTRACT)) {
- return report
- .addError(
- "The @AssistedFactory-annotated type must be either an abstract class or "
- + "interface.",
- factory)
- .build();
- }
-
- if (factory.getNestingKind().isNested() && !factory.getModifiers().contains(STATIC)) {
- report.addError("Nested @AssistedFactory-annotated types must be static. ", factory);
- }
-
- ImmutableSet<ExecutableElement> abstractFactoryMethods =
- AssistedInjectionAnnotations.assistedFactoryMethods(factory, elements, types);
-
- if (abstractFactoryMethods.isEmpty()) {
- report.addError(
- "The @AssistedFactory-annotated type is missing an abstract, non-default method "
- + "whose return type matches the assisted injection type.",
- factory);
- }
-
- for (ExecutableElement method : abstractFactoryMethods) {
- ExecutableType methodType = types.resolveExecutableType(method, factory.asType());
- if (!isAssistedInjectionType(methodType.getReturnType())) {
- report.addError(
- String.format(
- "Invalid return type: %s. An assisted factory's abstract method must return a "
- + "type with an @AssistedInject-annotated constructor.",
- methodType.getReturnType()),
- method);
- }
- if (!method.getTypeParameters().isEmpty()) {
- report.addError(
- "@AssistedFactory does not currently support type parameters in the creator "
- + "method. See https://github.com/google/dagger/issues/2279",
- method);
- }
- }
-
- if (abstractFactoryMethods.size() > 1) {
- report.addError(
- "The @AssistedFactory-annotated type should contain a single abstract, non-default"
- + " method but found multiple: "
- + abstractFactoryMethods,
- factory);
- }
-
- if (!report.build().isClean()) {
- return report.build();
- }
-
- AssistedFactoryMetadata metadata =
- AssistedFactoryMetadata.create(factory.asType(), elements, types);
-
- // Note: We check uniqueness of the @AssistedInject constructor parameters in
- // AssistedInjectProcessingStep. We need to check uniqueness for here too because we may
- // have resolved some type parameters that were not resolved in the @AssistedInject type.
- Set<AssistedParameter> uniqueAssistedParameters = new HashSet<>();
- for (AssistedParameter assistedParameter : metadata.assistedFactoryAssistedParameters()) {
- if (!uniqueAssistedParameters.add(assistedParameter)) {
- report.addError(
- "@AssistedFactory method has duplicate @Assisted types: " + assistedParameter,
- assistedParameter.variableElement());
- }
- }
-
- if (!ImmutableSet.copyOf(metadata.assistedInjectAssistedParameters())
- .equals(ImmutableSet.copyOf(metadata.assistedFactoryAssistedParameters()))) {
- report.addError(
- String.format(
- "The parameters in the factory method must match the @Assisted parameters in %s."
- + "\n Actual: %s#%s"
- + "\n Expected: %s#%s(%s)",
- metadata.assistedInjectType(),
- metadata.factory().getQualifiedName(),
- metadata.factoryMethod(),
- metadata.factory().getQualifiedName(),
- metadata.factoryMethod().getSimpleName(),
- metadata.assistedInjectAssistedParameters().stream()
- .map(AssistedParameter::type)
- .map(Object::toString)
- .collect(joining(", "))),
- metadata.factoryMethod());
- }
-
- return report.build();
- }
-
- private boolean isAssistedInjectionType(TypeMirror type) {
- return type.getKind() == TypeKind.DECLARED
- && AssistedInjectionAnnotations.isAssistedInjectionType(asTypeElement(type));
- }
- }
-
- /** Generates an implementation of the {@link dagger.assisted.AssistedFactory}-annotated class. */
- private final class AssistedFactoryImplGenerator extends SourceFileGenerator<ProvisionBinding> {
- AssistedFactoryImplGenerator() {
- super(filer, elements, sourceVersion);
- }
-
- @Override
- public ClassName nameGeneratedType(ProvisionBinding binding) {
- return generatedClassNameForBinding(binding);
- }
-
- @Override
- public Element originatingElement(ProvisionBinding binding) {
- return binding.bindingElement().get();
- }
-
- // For each @AssistedFactory-annotated type, we generates a class named "*_Impl" that implements
- // that type.
- //
- // Note that this class internally delegates to the @AssistedInject generated class, which
- // contains the actual implementation logic for creating the @AssistedInject type. The reason we
- // need both of these generated classes is because while the @AssistedInject generated class
- // knows how to create the @AssistedInject type, it doesn't know about all of the
- // @AssistedFactory interfaces that it needs to extend when it's generated. Thus, the role of
- // the @AssistedFactory generated class is purely to implement the @AssistedFactory type.
- // Furthermore, while we could have put all of the logic into the @AssistedFactory generated
- // class and not generate the @AssistedInject generated class, having the @AssistedInject
- // generated class ensures we have proper accessibility to the @AssistedInject type, and reduces
- // duplicate logic if there are multiple @AssistedFactory types for the same @AssistedInject
- // type.
- //
- // Example:
- // public class FooFactory_Impl implements FooFactory {
- // private final Foo_Factory delegateFactory;
- //
- // FooFactory_Impl(Foo_Factory delegateFactory) {
- // this.delegateFactory = delegateFactory;
- // }
- //
- // @Override
- // public Foo createFoo(AssistedDep assistedDep) {
- // return delegateFactory.get(assistedDep);
- // }
- //
- // public static Provider<FooFactory> create(Foo_Factory delegateFactory) {
- // return InstanceFactory.create(new FooFactory_Impl(delegateFactory));
- // }
- // }
- @Override
- public Optional<TypeSpec.Builder> write(ProvisionBinding binding) {
- TypeElement factory = asType(binding.bindingElement().get());
-
- ClassName name = nameGeneratedType(binding);
- TypeSpec.Builder builder =
- TypeSpec.classBuilder(name)
- .addModifiers(PUBLIC, FINAL)
- .addTypeVariables(
- factory.getTypeParameters().stream()
- .map(TypeVariableName::get)
- .collect(toImmutableList()));
-
- if (factory.getKind() == ElementKind.INTERFACE) {
- builder.addSuperinterface(factory.asType());
- } else {
- builder.superclass(factory.asType());
- }
-
- AssistedFactoryMetadata metadata =
- AssistedFactoryMetadata.create(asDeclared(factory.asType()), elements, types);
- ParameterSpec delegateFactoryParam =
- ParameterSpec.builder(
- delegateFactoryTypeName(metadata.assistedInjectType()), "delegateFactory")
- .build();
- builder
- .addField(
- FieldSpec.builder(delegateFactoryParam.type, delegateFactoryParam.name)
- .addModifiers(PRIVATE, FINAL)
- .build())
- .addMethod(
- MethodSpec.constructorBuilder()
- .addParameter(delegateFactoryParam)
- .addStatement("this.$1N = $1N", delegateFactoryParam)
- .build())
- .addMethod(
- MethodSpec.overriding(metadata.factoryMethod(), metadata.factoryType(), types)
- .addStatement(
- "return $N.get($L)",
- delegateFactoryParam,
- // Use the order of the parameters from the @AssistedInject constructor but
- // use the parameter names of the @AssistedFactory method.
- metadata.assistedInjectAssistedParameters().stream()
- .map(metadata.assistedFactoryAssistedParametersMap()::get)
- .map(param -> CodeBlock.of("$L", param.getSimpleName()))
- .collect(toParametersCodeBlock()))
- .build())
- .addMethod(
- MethodSpec.methodBuilder("create")
- .addModifiers(PUBLIC, STATIC)
- .addParameter(delegateFactoryParam)
- .addTypeVariables(
- metadata.assistedInjectElement().getTypeParameters().stream()
- .map(TypeVariableName::get)
- .collect(toImmutableList()))
- .returns(providerOf(TypeName.get(factory.asType())))
- .addStatement(
- "return $T.$Lcreate(new $T($N))",
- INSTANCE_FACTORY,
- // Java 7 type inference requires the method call provide the exact type here.
- sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0
- ? CodeBlock.of("<$T>", types.accessibleType(metadata.factoryType(), name))
- : CodeBlock.of(""),
- name,
- delegateFactoryParam)
- .build());
- return Optional.of(builder);
- }
-
- /** Returns the generated factory {@link TypeName type} for an @AssistedInject constructor. */
- private TypeName delegateFactoryTypeName(DeclaredType assistedInjectType) {
- // The name of the generated factory for the assisted inject type,
- // e.g. an @AssistedInject Foo(...) {...} constructor will generate a Foo_Factory class.
- ClassName generatedFactoryClassName =
- generatedClassNameForBinding(
- bindingFactory.injectionBinding(
- getOnlyElement(assistedInjectedConstructors(asTypeElement(assistedInjectType))),
- Optional.empty()));
-
- // Return the factory type resolved with the same type parameters as the assisted inject type.
- return assistedInjectType.getTypeArguments().isEmpty()
- ? generatedFactoryClassName
- : ParameterizedTypeName.get(
- generatedFactoryClassName,
- assistedInjectType.getTypeArguments().stream()
- .map(TypeName::get)
- .collect(toImmutableList())
- .toArray(new TypeName[0]));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/AssistedInjectProcessingStep.java b/java/dagger/internal/codegen/AssistedInjectProcessingStep.java
deleted file mode 100644
index 4f2f5b7..0000000
--- a/java/dagger/internal/codegen/AssistedInjectProcessingStep.java
+++ /dev/null
@@ -1,87 +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;
-
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkState;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations.AssistedParameter;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
-import java.util.HashSet;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-
-/** An annotation processor for {@link dagger.assisted.AssistedInject}-annotated elements. */
-final class AssistedInjectProcessingStep extends TypeCheckingProcessingStep<ExecutableElement> {
- private final DaggerTypes types;
- private final Messager messager;
-
- @Inject
- AssistedInjectProcessingStep(DaggerTypes types, Messager messager) {
- super(MoreElements::asExecutable);
- this.types = types;
- this.messager = messager;
- }
-
- @Override
- public ImmutableSet<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(AssistedInject.class);
- }
-
- @Override
- protected void process(
- ExecutableElement assistedInjectElement,
- ImmutableSet<Class<? extends Annotation>> annotations) {
- new AssistedInjectValidator().validate(assistedInjectElement).printMessagesTo(messager);
- }
-
- private final class AssistedInjectValidator {
- ValidationReport<ExecutableElement> validate(ExecutableElement constructor) {
- checkState(constructor.getKind() == ElementKind.CONSTRUCTOR);
- ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(constructor);
-
- DeclaredType assistedInjectType =
- asDeclared(closestEnclosingTypeElement(constructor).asType());
- ImmutableList<AssistedParameter> assistedParameters =
- AssistedInjectionAnnotations.assistedInjectAssistedParameters(assistedInjectType, types);
-
- Set<AssistedParameter> uniqueAssistedParameters = new HashSet<>();
- for (AssistedParameter assistedParameter : assistedParameters) {
- if (!uniqueAssistedParameters.add(assistedParameter)) {
- report.addError(
- "@AssistedInject constructor has duplicate @Assisted type: " + assistedParameter,
- assistedParameter.variableElement());
- }
- }
-
- return report.build();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/AssistedProcessingStep.java b/java/dagger/internal/codegen/AssistedProcessingStep.java
deleted file mode 100644
index 3173987..0000000
--- a/java/dagger/internal/codegen/AssistedProcessingStep.java
+++ /dev/null
@@ -1,132 +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.internal.codegen;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
-import java.lang.annotation.Annotation;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-
-/**
- * An annotation processor for {@link dagger.assisted.Assisted}-annotated types.
- *
- * <p>This processing step should run after {@link AssistedFactoryProcessingStep}.
- */
-final class AssistedProcessingStep extends TypeCheckingProcessingStep<VariableElement> {
- private final KotlinMetadataUtil kotlinMetadataUtil;
- private final InjectionAnnotations injectionAnnotations;
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final Messager messager;
-
- @Inject
- AssistedProcessingStep(
- KotlinMetadataUtil kotlinMetadataUtil,
- InjectionAnnotations injectionAnnotations,
- DaggerElements elements,
- DaggerTypes types,
- Messager messager) {
- super(MoreElements::asVariable);
- this.kotlinMetadataUtil = kotlinMetadataUtil;
- this.injectionAnnotations = injectionAnnotations;
- this.elements = elements;
- this.types = types;
- this.messager = messager;
- }
-
- @Override
- public ImmutableSet<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Assisted.class);
- }
-
- @Override
- protected void process(
- VariableElement assisted, ImmutableSet<Class<? extends Annotation>> annotations) {
- new AssistedValidator().validate(assisted).printMessagesTo(messager);
- }
-
- private final class AssistedValidator {
- ValidationReport<VariableElement> validate(VariableElement assisted) {
- ValidationReport.Builder<VariableElement> report = ValidationReport.about(assisted);
-
- Element enclosingElement = assisted.getEnclosingElement();
- if (!isAssistedInjectConstructor(enclosingElement)
- && !isAssistedFactoryCreateMethod(enclosingElement)
- // The generated java stubs for kotlin data classes contain a "copy" method that has
- // the same parameters (and annotations) as the constructor, so just ignore it.
- && !isKotlinDataClassCopyMethod(enclosingElement)) {
- report.addError(
- "@Assisted parameters can only be used within an @AssistedInject-annotated "
- + "constructor.",
- assisted);
- }
-
- injectionAnnotations
- .getQualifiers(assisted)
- .forEach(
- qualifier ->
- report.addError(
- "Qualifiers cannot be used with @Assisted parameters.", assisted, qualifier));
-
- return report.build();
- }
- }
-
- private boolean isAssistedInjectConstructor(Element element) {
- return element.getKind() == ElementKind.CONSTRUCTOR
- && isAnnotationPresent(element, AssistedInject.class);
- }
-
- private boolean isAssistedFactoryCreateMethod(Element element) {
- if (element.getKind() == ElementKind.METHOD) {
- TypeElement enclosingElement = closestEnclosingTypeElement(element);
- return AssistedInjectionAnnotations.isAssistedFactoryType(enclosingElement)
- // This assumes we've already validated AssistedFactory and that a valid method exists.
- && AssistedInjectionAnnotations.assistedFactoryMethod(enclosingElement, elements, types)
- .equals(element);
- }
- return false;
- }
-
- private boolean isKotlinDataClassCopyMethod(Element element) {
- // Note: This is a best effort. Technically, we could check the return type and parameters of
- // the copy method to verify it's the one associated with the constructor, but I'd rather keep
- // this simple to avoid encoding too many details of kapt's stubs. At worst, we'll be allowing
- // an @Assisted annotation that has no affect, which is already true for many of Dagger's other
- // annotations.
- return element.getKind() == ElementKind.METHOD
- && element.getSimpleName().contentEquals("copy")
- && kotlinMetadataUtil.isDataClass(closestEnclosingTypeElement(element));
- }
-}
diff --git a/java/dagger/internal/codegen/BUILD b/java/dagger/internal/codegen/BUILD
index be970be..824a72e 100644
--- a/java/dagger/internal/codegen/BUILD
+++ b/java/dagger/internal/codegen/BUILD
@@ -15,106 +15,485 @@
# Description:
# A JSR-330 compliant dependency injection system for android and java
-load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
-load(
- "//:build_defs.bzl",
- "POM_VERSION",
-)
-load("//tools:maven.bzl", "gen_maven_artifact")
-
package(default_visibility = ["//:src"])
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "DOCLINT_REFERENCES")
+load("//tools:maven.bzl", "POM_VERSION", "pom_file")
+
+EXPERIMENTAL_VISUALIZER_SRCS = ["BindingNetworkVisualizer.java"]
+
+JAVAC_PLUGIN_MODULE_SRCS = ["JavacPluginModule.java"]
+
+KYTHE_SRCS = ["DaggerKythePlugin.java"]
+
+STATISTICS_COLLECTOR_SRCS = ["BindingGraphStatisticsCollector.java"]
+
+CODEGEN_SRCS = glob(
+ ["*.java"],
+ exclude = EXPERIMENTAL_VISUALIZER_SRCS + KYTHE_SRCS + STATISTICS_COLLECTOR_SRCS +
+ JAVAC_PLUGIN_MODULE_SRCS,
+)
+
+CODEGEN_PLUGINS = [":bootstrap_compiler_plugin"]
+
+CODEGEN_SHARED_DEPS = [
+ "@google_bazel_common//third_party/java/auto:service",
+ "@google_bazel_common//third_party/java/auto:value",
+ "@google_bazel_common//third_party/java/auto:common",
+ "@google_bazel_common//third_party/java/checker_framework_annotations",
+ "@google_bazel_common//third_party/java/error_prone:annotations",
+ "@google_bazel_common//third_party/java/google_java_format",
+ "@google_bazel_common//third_party/java/javapoet",
+ "@bazel_tools//tools/jdk:langtools-neverlink",
+ "@google_bazel_common//third_party/java/jsr250_annotations",
+ "@google_bazel_common//third_party/java/jsr330_inject",
+ "//java/dagger:core",
+ "//java/dagger/internal/codegen/serialization",
+ "//java/dagger/producers",
+ "//java/dagger/model",
+ "//java/dagger/spi",
+ "//java/dagger/model:internal-proxies",
+]
+
+CODEGEN_DEPS = CODEGEN_SHARED_DEPS + [
+ ":jdk-and-guava-extras",
+ "@google_bazel_common//third_party/java/guava",
+]
+
+# Extra features for the JDK and Guava. This code is merged into both
+# the dagger-compiler and dagger-spi artifacts that are sent to Maven
+java_library(
+ name = "jdk-and-guava-extras",
+ srcs = [
+ "DaggerGraphs.java",
+ "DaggerStreams.java",
+ "Optionals.java",
+ ],
+ plugins = CODEGEN_PLUGINS,
+ tags = ["maven:merged"],
+ deps = [
+ "@google_bazel_common//third_party/java/guava",
+ ],
+)
+
+# Common types needed across all of the codegen package
+java_library(
+ name = "base",
+ srcs = [
+ "AnnotationProtoConverter.java",
+ "ClearableCache.java",
+ "CompilerOptions.java",
+ "ComponentAnnotation.java",
+ "ContributionType.java",
+ "DaggerStatistics.java",
+ "DaggerStatisticsCollectingProcessingStep.java",
+ "DaggerStatisticsCollector.java",
+ "DaggerStatisticsRecorder.java",
+ "DiagnosticFormatting.java",
+ "ElementFormatter.java",
+ "FeatureStatus.java",
+ "Formatter.java",
+ "ForwardingCompilerOptions.java",
+ "FrameworkTypes.java",
+ "InjectionAnnotations.java",
+ "Keys.java",
+ "MapKeyAccessibility.java",
+ "MapType.java",
+ "ModuleAnnotation.java",
+ "MoreAnnotationMirrors.java",
+ "MoreAnnotationValues.java",
+ "MultibindingAnnotations.java",
+ "OptionalType.java",
+ "ProcessingEnvironmentCompilerOptions.java",
+ "ProcessingOptions.java",
+ "RequestKinds.java",
+ "Scopes.java",
+ "SetType.java",
+ "SimpleAnnotationMirror.java",
+ "SimpleTypeAnnotationValue.java",
+ "SourceFileGenerationException.java", # Used in :writing and :processor
+ "SourceFileGenerator.java", # Needed by InjectBindingRegistry in :binding and also :writing
+ "TypeCheckingProcessingStep.java",
+ "TypeProtoConverter.java",
+ "UniqueNameSet.java",
+ "Util.java",
+ "ValidationType.java",
+ "package-info.java",
+ ],
+ plugins = CODEGEN_PLUGINS,
+ tags = ["maven:merged"],
+ deps = CODEGEN_DEPS + [
+ "//java/dagger/internal/codegen/javapoet",
+ "//java/dagger/internal/codegen/langmodel",
+ ],
+)
+
+# Classes that help to build a model of the binding graph
+java_library(
+ name = "binding",
+ srcs = [
+ "AnnotationExpression.java",
+ "Binding.java",
+ "BindingDeclaration.java",
+ "BindingDeclarationFormatter.java",
+ "BindingFactory.java",
+ "BindingGraph.java",
+ "BindingGraphConverter.java",
+ "BindingGraphFactory.java",
+ "BindingNode.java",
+ "BindingRequest.java",
+ "BindingType.java",
+ "BindsTypeChecker.java",
+ "ChildFactoryMethodEdgeImpl.java",
+ "ComponentCreatorAnnotation.java",
+ "ComponentCreatorDescriptor.java",
+ "ComponentCreatorKind.java",
+ "ComponentDescriptor.java",
+ "ComponentDescriptorFactory.java",
+ "ComponentKind.java",
+ "ComponentNodeImpl.java",
+ "ComponentRequirement.java",
+ "ComponentTreeTraverser.java",
+ "ConfigurationAnnotations.java", # Uses ModuleDescriptors
+ "ContributionBinding.java",
+ "DelegateDeclaration.java",
+ "DependencyEdgeImpl.java",
+ "DependencyRequestFactory.java",
+ "DependencyRequestFormatter.java",
+ "DependencyVariableNamer.java", # Used by SourceFiles
+ "ErrorMessages.java", # Consider splitting this up as it pulls in too much
+ "FrameworkDependency.java",
+ "FrameworkField.java", # Used by SourceFiles
+ "FrameworkType.java",
+ "FrameworkTypeMapper.java",
+ "InjectBindingRegistry.java",
+ "InjectionSiteFactory.java",
+ "KeyFactory.java",
+ "KeyVariableNamer.java", # needs ConfigurationAnnotations, SourceFiles
+ "MapKeys.java",
+ "MembersInjectionBinding.java",
+ "MethodSignature.java",
+ "MethodSignatureFormatter.java",
+ "ModuleDescriptor.java",
+ "ModuleKind.java",
+ "MultibindingDeclaration.java",
+ "OptionalBindingDeclaration.java",
+ "ProductionBinding.java",
+ "ProvisionBinding.java",
+ "ResolvedBindings.java",
+ "SourceFiles.java", # Consider splitting this up?
+ "SubcomponentCreatorBindingEdgeImpl.java",
+ "SubcomponentDeclaration.java",
+ ],
+ plugins = CODEGEN_PLUGINS,
+ tags = ["maven:merged"],
+ deps = CODEGEN_DEPS + [
+ ":base",
+ "//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/javapoet",
+ ],
+)
+
+# Code related to validating the user-written Dagger code
+java_library(
+ name = "validation",
+ srcs = [
+ "AnyBindingMethodValidator.java",
+ "BindingElementValidator.java",
+ "BindingGraphPlugins.java",
+ "BindingGraphValidator.java",
+ "BindingMethodProcessingStep.java",
+ "BindingMethodValidator.java",
+ "BindsInstanceElementValidator.java",
+ "BindsInstanceMethodValidator.java",
+ "BindsInstanceParameterValidator.java",
+ "BindsInstanceProcessingStep.java",
+ "BindsMethodValidator.java",
+ "BindsOptionalOfMethodValidator.java",
+ "ComponentCreatorValidator.java",
+ "ComponentDescriptorValidator.java",
+ "ComponentHierarchyValidator.java",
+ "ComponentValidator.java",
+ "DependencyRequestValidator.java",
+ "DiagnosticReporterFactory.java",
+ "InjectValidator.java",
+ "MapKeyValidator.java",
+ "MembersInjectionValidator.java",
+ "ModuleValidator.java",
+ "MultibindingAnnotationsProcessingStep.java",
+ "MultibindsMethodValidator.java",
+ "ProducesMethodValidator.java",
+ "ProvidesMethodValidator.java",
+ "Validation.java",
+ "ValidationReport.java",
+ ],
+ plugins = CODEGEN_PLUGINS,
+ tags = ["maven:merged"],
+ deps = CODEGEN_DEPS + [
+ ":base",
+ ":binding",
+ "//java/dagger/internal/codegen/langmodel",
+ ],
+)
+
+java_library(
+ name = "binding_graph_validation",
+ srcs = [
+ "DependencyCycleValidator.java",
+ "DependsOnProductionExecutorValidator.java",
+ "DuplicateBindingsValidator.java",
+ "IncompatiblyScopedBindingsValidator.java",
+ "InjectBindingValidator.java",
+ "MapMultibindingValidator.java",
+ "MissingBindingValidator.java",
+ "NullableBindingValidator.java",
+ "ProvisionDependencyOnProducerBindingValidator.java",
+ "SubcomponentFactoryMethodValidator.java",
+ ],
+ plugins = CODEGEN_PLUGINS,
+ tags = ["maven:merged"],
+ deps = CODEGEN_DEPS + [
+ ":base",
+ ":binding",
+ ":validation",
+ "//java/dagger/internal/codegen/langmodel",
+ ],
+)
+
+# Classes that assemble the model of the generated code and write to the Filer
+java_library(
+ name = "writing",
+ srcs = [
+ "AnnotationCreatorGenerator.java",
+ "AnonymousProviderCreationExpression.java",
+ "BindingExpression.java",
+ "ComponentBindingExpressions.java",
+ "ComponentCreatorImplementation.java",
+ "ComponentImplementation.java",
+ "ComponentInstanceBindingExpression.java",
+ "ComponentMethodBindingExpression.java",
+ "ComponentProvisionBindingExpression.java",
+ "ComponentRequirementBindingExpression.java",
+ "ComponentRequirementExpression.java",
+ "ComponentRequirementExpressions.java",
+ "DeferredModifiableBindingExpression.java",
+ "DelegateBindingExpression.java",
+ "DelegatingFrameworkInstanceCreationExpression.java",
+ "DependencyMethodProducerCreationExpression.java",
+ "DependencyMethodProviderCreationExpression.java",
+ "DerivedFromFrameworkInstanceBindingExpression.java",
+ "FactoryGenerator.java",
+ "FrameworkFieldInitializer.java",
+ "FrameworkInstanceBindingExpression.java",
+ "FrameworkInstanceSupplier.java",
+ "GenerationCompilerOptions.java",
+ "GwtCompatibility.java",
+ "HjarSourceFileGenerator.java",
+ "ImmediateFutureBindingExpression.java",
+ "InaccessibleMapKeyProxyGenerator.java",
+ "InjectionMethod.java",
+ "InjectionMethods.java",
+ "InjectionOrProvisionProviderCreationExpression.java",
+ "InnerSwitchingProviders.java",
+ "InstanceFactoryCreationExpression.java",
+ "MapBindingExpression.java",
+ "MapFactoryCreationExpression.java",
+ "MemberSelect.java",
+ "MembersInjectionBindingExpression.java",
+ "MembersInjectionMethods.java",
+ "MembersInjectorGenerator.java",
+ "MembersInjectorProviderCreationExpression.java",
+ "MethodBindingExpression.java",
+ "MissingBindingExpression.java",
+ "ModifiableAbstractMethodBindingExpression.java",
+ "ModifiableBindingExpressions.java",
+ "ModifiableBindingMethods.java",
+ "ModifiableBindingType.java",
+ "ModifiableConcreteMethodBindingExpression.java",
+ "ModuleConstructorProxyGenerator.java",
+ "ModuleGenerator.java",
+ "ModuleProxies.java",
+ "MonitoringModuleGenerator.java",
+ "MonitoringModuleProcessingStep.java",
+ "MultibindingExpression.java",
+ "MultibindingFactoryCreationExpression.java",
+ "OptionalBindingExpression.java",
+ "OptionalFactories.java",
+ "OptionalFactoryInstanceCreationExpression.java",
+ "ParentComponent.java",
+ "PerComponentImplementation.java",
+ "PerGeneratedFile.java",
+ "PrivateMethodBindingExpression.java",
+ "ProducerCreationExpression.java",
+ "ProducerEntryPointView.java",
+ "ProducerFactoryGenerator.java",
+ "ProducerFromProviderCreationExpression.java",
+ "ProducerNodeInstanceBindingExpression.java",
+ "ProviderInstanceBindingExpression.java",
+ "PrunedConcreteMethodBindingExpression.java",
+ "SetBindingExpression.java",
+ "SetFactoryCreationExpression.java",
+ "SimpleInvocationBindingExpression.java",
+ "SimpleMethodBindingExpression.java",
+ "SubcomponentCreatorBindingExpression.java",
+ "SubcomponentNames.java",
+ "SwitchingProviders.java",
+ "TopLevel.java",
+ "UnwrappedMapKeyGenerator.java",
+ ],
+ plugins = CODEGEN_PLUGINS,
+ tags = ["maven:merged"],
+ deps = CODEGEN_DEPS + [
+ ":base",
+ ":binding",
+ "//java/dagger/internal/codegen/javapoet",
+ "//java/dagger/internal/codegen/langmodel",
+ ],
+)
+
+# The processor's "main", if you will
java_library(
name = "processor",
- srcs = glob(
- ["*.java"],
- exclude = ["package-info.java"],
- ),
- plugins = [
- "//java/dagger/internal/codegen/bootstrap",
+ srcs = [
+ "BindingGraphValidationModule.java",
+ "BindingMethodValidatorsModule.java",
+ "ComponentCreatorImplementationFactory.java",
+ "ComponentGenerator.java",
+ "ComponentHjarProcessingStep.java",
+ "ComponentImplementationBuilder.java",
+ "ComponentImplementationFactory.java",
+ "ComponentProcessingStep.java",
+ "ComponentProcessor.java",
+ "CurrentImplementationSubcomponent.java",
+ "DeserializedComponentImplementationBuilder.java",
+ "GenerationOptionsModule.java",
+ "InjectBindingRegistryImpl.java",
+ "InjectBindingRegistryModule.java",
+ "InjectProcessingStep.java",
+ "MapKeyProcessingStep.java",
+ "ModuleProcessingStep.java",
+ "ProcessingEnvironmentModule.java",
+ "ProcessingRoundCacheModule.java",
+ "SourceFileGeneratorsModule.java",
+ "SpiModule.java",
+ "SystemComponentsModule.java",
+ "TopLevelImplementationComponent.java",
],
+ plugins = CODEGEN_PLUGINS,
tags = ["maven_coordinates=com.google.dagger:dagger-compiler:" + POM_VERSION],
- exports = [
- "@google_bazel_common//third_party/java/jsr250_annotations", # Export for @Generated
- ],
- deps = [
- ":package_info",
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/bindinggraphvalidation",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/componentgenerator",
- "//java/dagger/internal/codegen/extension",
+ deps = CODEGEN_DEPS + [
+ ":base",
+ ":binding",
+ ":binding_graph_validation",
+ ":writing",
+ ":validation",
"//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/codegen/writing",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/google_java_format",
"@google_bazel_common//third_party/java/incap",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
+ ],
+)
+
+pom_file(
+ name = "pom",
+ artifact_id = "dagger-compiler",
+ artifact_name = "Dagger Compiler",
+ targets = [
+ ":processor",
+ ":base",
+ ":binding",
+ ":binding_graph_validation",
+ ":writing",
+ ":validation",
+ "//java/dagger/internal/codegen/serialization",
+ "//java/dagger/internal/codegen/javapoet",
],
)
java_library(
- name = "package_info",
- srcs = ["package-info.java"],
- tags = ["maven:merged"],
- deps = ["@google_bazel_common//third_party/java/error_prone:annotations"],
+ name = "javac-plugin-module",
+ srcs = JAVAC_PLUGIN_MODULE_SRCS,
+ plugins = [":component-codegen"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":base",
+ ":binding",
+ ":javac",
+ ":processor",
+ "//java/dagger:core",
+ "//java/dagger/internal/codegen/langmodel",
+ ],
)
-gen_maven_artifact(
- name = "artifact",
- artifact_coordinates = "com.google.dagger:dagger-compiler:" + POM_VERSION,
- artifact_name = "Dagger Compiler",
- artifact_target = ":processor",
- artifact_target_libs = [
- ":package_info",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/base:shared",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/bindinggraphvalidation",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/componentgenerator",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
+java_library(
+ name = "kythe",
+ srcs = KYTHE_SRCS,
+ plugins = [":component-codegen"],
+ deps = [
+ ":base",
+ ":binding",
+ ":javac",
+ ":javac-plugin-module",
+ ":kythe_plugin",
+ ":processor",
+ "//java/dagger:core",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/codegen/writing",
- "//java/dagger/model:internal-proxies",
+ "//java/dagger/model",
+ "//java/dagger/producers",
+ "@google_bazel_common//third_party/java/auto:common",
+ "@google_bazel_common//third_party/java/auto:service",
+ "@google_bazel_common//third_party/java/guava",
],
- artifact_target_maven_deps = [
- "com.google.auto:auto-common",
- "com.google.code.findbugs:jsr305",
- "com.google.dagger:dagger-producers",
- "com.google.dagger:dagger-spi",
- "com.google.dagger:dagger",
- "com.google.googlejavaformat:google-java-format",
- "com.google.guava:failureaccess",
- "com.google.guava:guava",
- "com.squareup:javapoet",
- "javax.annotation:jsr250-api",
- "javax.inject:javax.inject",
- "net.ltgt.gradle.incap:incap",
- "org.checkerframework:checker-compat-qual",
- "org.jetbrains.kotlin:kotlin-stdlib",
- "org.jetbrains.kotlinx:kotlinx-metadata-jvm",
+)
+
+# Replacement for @bazel_tools//third_party/java/jdk/langtools:javac, which seems to have gone away?
+java_import(
+ name = "javac",
+ jars = ["@bazel_tools//third_party/java/jdk/langtools:javac_jar"],
+)
+
+# A _deploy.jar consisting of the java_librarys in https://github.com/kythe/kythe needed to build a
+# Kythe plugin
+# TODO(ronshapiro): replace this with a http_archive of the next release in
+# https://github.com/kythe/kythe/releases
+java_import(
+ name = "kythe_plugin",
+ jars = ["kythe_plugin_deploy.jar"],
+ neverlink = 1,
+)
+
+java_import(
+ name = "bootstrap_compiler",
+ jars = ["bootstrap_compiler_deploy.jar"],
+ visibility = ["//visibility:private"],
+)
+
+java_plugin(
+ name = "bootstrap_compiler_plugin",
+ generates_api = 1,
+ processor_class = "dagger.internal.codegen.ComponentProcessor",
+ deps = [":bootstrap_compiler"],
+)
+
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
+javadoc_library(
+ name = "codegen-javadoc",
+ srcs = CODEGEN_SRCS,
+ root_packages = ["dagger.internal.codegen"],
+ deps = [":processor"],
+)
+
+java_library(
+ name = "check-package-javadoc",
+ testonly = 1,
+ srcs = CODEGEN_SRCS,
+ javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
+ plugins = CODEGEN_PLUGINS,
+ deps = CODEGEN_DEPS + [
+ "//java/dagger/internal/codegen/langmodel",
+ "//java/dagger/internal/codegen/javapoet",
+ "@google_bazel_common//third_party/java/incap",
],
- javadoc_root_packages = ["dagger.internal.codegen"],
- # The javadocs should only include ComponentProcessor.java, since that is the only class used
- # externally. Specifically, ComponentProcessor.forTesting() is required for testing SPI plugins.
- javadoc_srcs = ["ComponentProcessor.java"],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.shaded.auto.common.@1"],
)
java_plugin(
@@ -130,3 +509,19 @@
],
deps = [":processor"],
)
+
+java_library(
+ name = "statistics",
+ srcs = STATISTICS_COLLECTOR_SRCS,
+ plugins = [":component-codegen"],
+ deps = [
+ ":base",
+ ":binding",
+ ":javac",
+ ":javac-plugin-module",
+ ":processor",
+ "//java/dagger:core",
+ "//java/dagger/model",
+ "@google_bazel_common//third_party/java/error_prone:check_api",
+ ],
+)
diff --git a/java/dagger/internal/codegen/Binding.java b/java/dagger/internal/codegen/Binding.java
new file mode 100644
index 0000000..c0f6b71
--- /dev/null
+++ b/java/dagger/internal/codegen/Binding.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Suppliers.memoize;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static java.util.stream.Collectors.toSet;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.Scope;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+/**
+ * An abstract type for classes representing a Dagger binding. Particularly, contains the {@link
+ * Element} that generated the binding and the {@link DependencyRequest} instances that are required
+ * to satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding to the
+ * subtypes.
+ */
+abstract class Binding extends BindingDeclaration {
+
+ /**
+ * Returns {@code true} if using this binding requires an instance of the {@link
+ * #contributingModule()}.
+ */
+ boolean requiresModuleInstance() {
+ if (!bindingElement().isPresent() || !contributingModule().isPresent()) {
+ return false;
+ }
+ Set<Modifier> modifiers = bindingElement().get().getModifiers();
+ return !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC);
+ }
+
+ /**
+ * 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}.
+ */
+ abstract boolean isNullable();
+
+ /** The kind of binding this instance represents. */
+ abstract BindingKind kind();
+
+ /** The {@link BindingType} of this binding. */
+ abstract BindingType bindingType();
+
+ /** The {@link FrameworkType} of this binding. */
+ final FrameworkType frameworkType() {
+ return FrameworkType.forBindingType(bindingType());
+ }
+
+ /**
+ * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding as
+ * defined by the user-defined injection sites.
+ */
+ abstract ImmutableSet<DependencyRequest> explicitDependencies();
+
+ /**
+ * The set of {@link DependencyRequest dependencies} that are added by the framework rather than a
+ * user-defined injection site. This returns an unmodifiable set.
+ */
+ // TODO(gak): this will eventually get changed to return a set of FrameworkDependency
+ ImmutableSet<DependencyRequest> implicitDependencies() {
+ return ImmutableSet.of();
+ }
+
+ private final Supplier<ImmutableSet<DependencyRequest>> dependencies =
+ memoize(
+ () -> {
+ ImmutableSet<DependencyRequest> implicitDependencies = implicitDependencies();
+ return ImmutableSet.copyOf(
+ implicitDependencies.isEmpty()
+ ? explicitDependencies()
+ : Sets.union(implicitDependencies, explicitDependencies()));
+ });
+
+ /**
+ * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is the
+ * union of {@link #explicitDependencies()} and {@link #implicitDependencies()}. This returns an
+ * unmodifiable set.
+ */
+ final ImmutableSet<DependencyRequest> dependencies() {
+ return dependencies.get();
+ }
+
+ private final Supplier<ImmutableList<FrameworkDependency>> frameworkDependencies =
+ memoize(
+ () ->
+ dependencyAssociations()
+ .stream()
+ .map(DependencyAssociation::frameworkDependency)
+ .collect(toImmutableList()));
+
+ /**
+ * The framework dependencies of {@code binding}. There will be one element for each different
+ * binding key in the <em>{@linkplain Binding#unresolved() unresolved}</em> version of {@code
+ * binding}.
+ *
+ * <p>For example, given the following modules:
+ *
+ * <pre><code>
+ * {@literal @Module} abstract class {@literal BaseModule<T>} {
+ * {@literal @Provides} Foo provideFoo(T t, String string) {
+ * return …;
+ * }
+ * }
+ *
+ * {@literal @Module} class StringModule extends {@literal BaseModule<String>} {}
+ * </code></pre>
+ *
+ * Both dependencies of {@code StringModule.provideFoo} have the same binding key: {@code String}.
+ * But there are still two dependencies, because in the unresolved binding they have different
+ * binding keys:
+ *
+ * <dl>
+ * <dt>{@code T}
+ * <dd>{@code String t}
+ * <dt>{@code String}
+ * <dd>{@code String string}
+ * </dl>
+ *
+ * <p>Note that the sets returned by this method when called on the same binding will be equal,
+ * and their elements will be in the same order.
+ */
+ /* TODO(dpb): The stable-order postcondition is actually hard to verify in code for two equal
+ * instances of Binding, because it really depends on the order of the binding's dependencies,
+ * and two equal instances of Binding may have the same dependencies in a different order. */
+ final ImmutableList<FrameworkDependency> frameworkDependencies() {
+ return frameworkDependencies.get();
+ }
+
+ /**
+ * Associates a {@link FrameworkDependency} with the set of {@link DependencyRequest} instances
+ * that correlate for a binding.
+ */
+ @AutoValue
+ abstract static class DependencyAssociation {
+ abstract FrameworkDependency frameworkDependency();
+
+ abstract ImmutableSet<DependencyRequest> dependencyRequests();
+
+ static DependencyAssociation create(
+ FrameworkDependency frameworkDependency, Iterable<DependencyRequest> dependencyRequests) {
+ return new AutoValue_Binding_DependencyAssociation(
+ frameworkDependency, ImmutableSet.copyOf(dependencyRequests));
+ }
+ }
+
+ private final Supplier<ImmutableList<DependencyAssociation>> dependencyAssociations =
+ memoize(
+ () -> {
+ FrameworkTypeMapper frameworkTypeMapper =
+ FrameworkTypeMapper.forBindingType(bindingType());
+ ImmutableList.Builder<DependencyAssociation> list = ImmutableList.builder();
+ for (Set<DependencyRequest> requests : groupByUnresolvedKey()) {
+ list.add(
+ DependencyAssociation.create(
+ FrameworkDependency.create(
+ getOnlyElement(
+ requests.stream().map(DependencyRequest::key).collect(toSet())),
+ frameworkTypeMapper.getFrameworkType(requests)),
+ requests));
+ }
+ return list.build();
+ });
+
+ /**
+ * Returns the same {@link FrameworkDependency} instances from {@link #frameworkDependencies}, but
+ * with the set of {@link DependencyRequest} instances with which each is associated.
+ *
+ * <p>Ths method returns a list of {@link Map.Entry entries} rather than a {@link Map} or {@link
+ * com.google.common.collect.Multimap} because any given {@link FrameworkDependency} may appear
+ * multiple times if the {@linkplain Binding#unresolved() unresolved} binding requires it. If that
+ * distinction is not important, the entries can be merged into a single mapping.
+ */
+ final ImmutableList<DependencyAssociation> dependencyAssociations() {
+ return dependencyAssociations.get();
+ }
+
+ private final Supplier<ImmutableMap<DependencyRequest, FrameworkDependency>>
+ frameworkDependenciesMap =
+ memoize(
+ () -> {
+ ImmutableMap.Builder<DependencyRequest, FrameworkDependency> frameworkDependencies =
+ ImmutableMap.builder();
+ for (DependencyAssociation dependencyAssociation : dependencyAssociations()) {
+ for (DependencyRequest dependencyRequest :
+ dependencyAssociation.dependencyRequests()) {
+ frameworkDependencies.put(
+ dependencyRequest, dependencyAssociation.frameworkDependency());
+ }
+ }
+ return frameworkDependencies.build();
+ });
+
+ /**
+ * Returns the mapping from each {@linkplain #dependencies dependency} to its associated {@link
+ * FrameworkDependency}.
+ */
+ final ImmutableMap<DependencyRequest, FrameworkDependency>
+ dependenciesToFrameworkDependenciesMap() {
+ return frameworkDependenciesMap.get();
+ }
+
+ /**
+ * Groups {@code binding}'s implicit dependencies by their binding key, using the dependency keys
+ * from the {@link Binding#unresolved()} binding if it exists.
+ */
+ private ImmutableList<Set<DependencyRequest>> groupByUnresolvedKey() {
+ ImmutableSetMultimap.Builder<Key, DependencyRequest> dependenciesByKeyBuilder =
+ ImmutableSetMultimap.builder();
+ Iterator<DependencyRequest> dependencies = dependencies().iterator();
+ Binding unresolved = unresolved().isPresent() ? unresolved().get() : this;
+ Iterator<DependencyRequest> unresolvedDependencies = unresolved.dependencies().iterator();
+ while (dependencies.hasNext()) {
+ dependenciesByKeyBuilder.put(unresolvedDependencies.next().key(), dependencies.next());
+ }
+ return ImmutableList.copyOf(
+ Multimaps.asMap(
+ dependenciesByKeyBuilder.orderValuesBy(SourceFiles.DEPENDENCY_ORDERING).build())
+ .values());
+ }
+
+ /**
+ * If this binding's key's type parameters are different from those of the
+ * {@link #bindingTypeElement()}, this is the binding for the {@link #bindingTypeElement()}'s
+ * unresolved type.
+ */
+ abstract Optional<? extends Binding> unresolved();
+
+ Optional<Scope> scope() {
+ return Optional.empty();
+ }
+
+ // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
+ static boolean hasNonDefaultTypeParameters(
+ TypeElement element, TypeMirror type, DaggerTypes types) {
+ // If the element has no type parameters, nothing can be wrong.
+ if (element.getTypeParameters().isEmpty()) {
+ return false;
+ }
+
+ List<TypeMirror> defaultTypes = Lists.newArrayList();
+ for (TypeParameterElement parameter : element.getTypeParameters()) {
+ defaultTypes.add(parameter.asType());
+ }
+
+ List<TypeMirror> actualTypes =
+ type.accept(
+ new SimpleTypeVisitor6<List<TypeMirror>, Void>() {
+ @Override
+ protected List<TypeMirror> defaultAction(TypeMirror e, Void p) {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public List<TypeMirror> visitDeclared(DeclaredType t, Void p) {
+ return ImmutableList.<TypeMirror>copyOf(t.getTypeArguments());
+ }
+ },
+ null);
+
+ // The actual type parameter size can be different if the user is using a raw type.
+ if (defaultTypes.size() != actualTypes.size()) {
+ return true;
+ }
+
+ for (int i = 0; i < defaultTypes.size(); i++) {
+ if (!types.isSameType(defaultTypes.get(i), actualTypes.get(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingDeclaration.java b/java/dagger/internal/codegen/BindingDeclaration.java
new file mode 100644
index 0000000..c9520cd
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingDeclaration.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.model.BindingKind;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/** An object that declares or specifies a binding. */
+abstract class BindingDeclaration {
+
+ /** The {@link Key} of this declaration. */
+ abstract Key key();
+
+ /**
+ * The {@link Element} 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.
+ */
+ // TODO(ronshapiro): examine whether this wildcard+bound have any benefit.
+ // We never actually refer to the overridden bindingElement methods directly in a way which needs
+ // anything more than an Element. Removing the wildcard would allow for simpler user-written code
+ // when the binding element is passed to a method.
+ abstract Optional<Element> bindingElement();
+
+ /**
+ * The type enclosing the {@link #bindingElement()}, or {@link Optional#empty()} if {@link
+ * #bindingElement()} is empty.
+ */
+ final Optional<TypeElement> bindingTypeElement() {
+ return bindingElement().map(DaggerElements::closestEnclosingTypeElement);
+ }
+
+ /**
+ * The installed module class that contributed the {@link #bindingElement()}. May be a subclass of
+ * the class that contains {@link #bindingElement()}. Absent if {@link #bindingElement()} is
+ * empty.
+ */
+ abstract Optional<TypeElement> contributingModule();
+}
diff --git a/java/dagger/internal/codegen/BindingDeclarationFormatter.java b/java/dagger/internal/codegen/BindingDeclarationFormatter.java
new file mode 100644
index 0000000..d850165
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingDeclarationFormatter.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.collect.Sets.immutableEnumSet;
+import static dagger.internal.codegen.DiagnosticFormatting.stripCommonTypePrefixes;
+import static dagger.internal.codegen.ElementFormatter.elementToString;
+import static javax.lang.model.element.ElementKind.PARAMETER;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.EXECUTABLE;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+
+/**
+ * Formats a {@link BindingDeclaration} into a {@link String} suitable for use in error messages.
+ */
+final class BindingDeclarationFormatter extends Formatter<BindingDeclaration> {
+ private static final ImmutableSet<TypeKind> FORMATTABLE_ELEMENT_TYPE_KINDS =
+ immutableEnumSet(EXECUTABLE, DECLARED);
+
+ private final MethodSignatureFormatter methodSignatureFormatter;
+
+ @Inject
+ BindingDeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter) {
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ }
+
+ /**
+ * Returns {@code true} for declarations that this formatter can format. Specifically bindings
+ * from subcomponent declarations or those with {@linkplain BindingDeclaration#bindingElement()
+ * binding elements} that are methods, constructors, or types.
+ */
+ boolean canFormat(BindingDeclaration bindingDeclaration) {
+ if (bindingDeclaration instanceof SubcomponentDeclaration) {
+ return true;
+ }
+ if (bindingDeclaration.bindingElement().isPresent()) {
+ Element bindingElement = bindingDeclaration.bindingElement().get();
+ return bindingElement.getKind().equals(PARAMETER)
+ || FORMATTABLE_ELEMENT_TYPE_KINDS.contains(bindingElement.asType().getKind());
+ }
+ // TODO(dpb): validate whether what this is doing is correct
+ return false;
+ }
+
+ @Override
+ public String format(BindingDeclaration bindingDeclaration) {
+ if (bindingDeclaration instanceof SubcomponentDeclaration) {
+ return formatSubcomponentDeclaration((SubcomponentDeclaration) bindingDeclaration);
+ }
+
+ if (bindingDeclaration.bindingElement().isPresent()) {
+ Element bindingElement = bindingDeclaration.bindingElement().get();
+ if (bindingElement.getKind().equals(PARAMETER)) {
+ return elementToString(bindingElement);
+ }
+
+ switch (bindingElement.asType().getKind()) {
+ case EXECUTABLE:
+ return methodSignatureFormatter.format(
+ MoreElements.asExecutable(bindingElement),
+ bindingDeclaration
+ .contributingModule()
+ .map(module -> MoreTypes.asDeclared(module.asType())));
+
+ case DECLARED:
+ return stripCommonTypePrefixes(bindingElement.asType().toString());
+
+ default:
+ throw new IllegalArgumentException(
+ "Formatting unsupported for element: " + bindingElement);
+ }
+ }
+
+ return String.format(
+ "Dagger-generated binding for %s",
+ stripCommonTypePrefixes(bindingDeclaration.key().toString()));
+ }
+
+ private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
+ ImmutableList<TypeElement> moduleSubcomponents =
+ subcomponentDeclaration.moduleAnnotation().subcomponents();
+ int index = moduleSubcomponents.indexOf(subcomponentDeclaration.subcomponentType());
+ StringBuilder annotationValue = new StringBuilder();
+ if (moduleSubcomponents.size() != 1) {
+ annotationValue.append("{");
+ }
+ annotationValue.append(
+ formatArgumentInList(
+ index,
+ moduleSubcomponents.size(),
+ subcomponentDeclaration.subcomponentType().getQualifiedName() + ".class"));
+ if (moduleSubcomponents.size() != 1) {
+ annotationValue.append("}");
+ }
+
+ return String.format(
+ "@%s(subcomponents = %s) for %s",
+ subcomponentDeclaration.moduleAnnotation().annotationClass().getSimpleName(),
+ annotationValue,
+ subcomponentDeclaration.contributingModule().get());
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingElementValidator.java b/java/dagger/internal/codegen/BindingElementValidator.java
new file mode 100644
index 0000000..0051912
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingElementValidator.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Verify.verifyNotNull;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.MapKeys.getMapKeys;
+import static dagger.internal.codegen.Scopes.scopesOf;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
+import static javax.lang.model.type.TypeKind.ARRAY;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.TYPEVAR;
+import static javax.lang.model.type.TypeKind.VOID;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.MapKey;
+import dagger.Provides;
+import dagger.model.Key;
+import dagger.model.Scope;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.multibindings.IntoMap;
+import dagger.producers.Produces;
+import java.lang.annotation.Annotation;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Qualifier;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+/** A validator for elements that represent binding declarations. */
+abstract class BindingElementValidator<E extends Element> {
+ private final Class<? extends Annotation> bindingAnnotation;
+ private final AllowsMultibindings allowsMultibindings;
+ private final AllowsScoping allowsScoping;
+ private final Map<E, ValidationReport<E>> cache = new HashMap<>();
+
+ /**
+ * Creates a validator object.
+ *
+ * @param bindingAnnotation the annotation on an element that identifies it as a binding element
+ */
+ protected BindingElementValidator(
+ Class<? extends Annotation> bindingAnnotation,
+ AllowsMultibindings allowsMultibindings,
+ AllowsScoping allowsScoping) {
+ this.bindingAnnotation = bindingAnnotation;
+ this.allowsMultibindings = allowsMultibindings;
+ this.allowsScoping = allowsScoping;
+ }
+
+ /** Returns a {@link ValidationReport} for {@code element}. */
+ final ValidationReport<E> validate(E element) {
+ return reentrantComputeIfAbsent(cache, element, this::validateUncached);
+ }
+
+ private ValidationReport<E> validateUncached(E element) {
+ return elementValidator(element).validate();
+ }
+
+ /**
+ * Returns an error message of the form "<{@link #bindingElements()}> <i>rule</i>", where
+ * <i>rule</i> comes from calling {@link String#format(String, Object...)} on {@code ruleFormat}
+ * and the other arguments.
+ */
+ @FormatMethod
+ protected final String bindingElements(String ruleFormat, Object... args) {
+ return new Formatter().format("%s ", bindingElements()).format(ruleFormat, args).toString();
+ }
+
+ /**
+ * The kind of elements that this validator validates. Should be plural. Used for error reporting.
+ */
+ protected abstract String bindingElements();
+
+ /** The verb describing the {@link ElementValidator#bindingElementType()} in error messages. */
+ // TODO(ronshapiro,dpb): improve the name of this method and it's documentation.
+ protected abstract String bindingElementTypeVerb();
+
+ /** The error message when a binding element has a bad type. */
+ protected String badTypeMessage() {
+ return bindingElements(
+ "must %s a primitive, an array, a type variable, or a declared type",
+ bindingElementTypeVerb());
+ }
+
+ /**
+ * The error message when a the type for a binding element with {@link
+ * ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a not set type.
+ */
+ protected String elementsIntoSetNotASetMessage() {
+ return bindingElements(
+ "annotated with @ElementsIntoSet must %s a Set", bindingElementTypeVerb());
+ }
+
+ /**
+ * The error message when a the type for a binding element with {@link
+ * ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a raw set.
+ */
+ protected String elementsIntoSetRawSetMessage() {
+ return bindingElements(
+ "annotated with @ElementsIntoSet cannot %s a raw Set", bindingElementTypeVerb());
+ }
+
+ /*** Returns an {@link ElementValidator} for validating the given {@code element}. */
+ protected abstract ElementValidator elementValidator(E element);
+
+ /** Validator for a single binding element. */
+ protected abstract class ElementValidator {
+ protected final E element;
+ protected final ValidationReport.Builder<E> report;
+
+ protected ElementValidator(E element) {
+ this.element = element;
+ this.report = ValidationReport.about(element);
+ }
+
+ /** Checks the element for validity. */
+ private ValidationReport<E> validate() {
+ checkType();
+ checkQualifiers();
+ checkMapKeys();
+ checkMultibindings();
+ checkScopes();
+ checkAdditionalProperties();
+ return report.build();
+ }
+
+ /** Check any additional properties of the element. Does nothing by default. */
+ protected void checkAdditionalProperties() {}
+
+ /**
+ * The type declared by this binding element. This may differ from a binding's {@link
+ * Key#type()}, for example in multibindings. An {@link Optional#empty()} return value indicates
+ * that the contributed type is ambiguous or missing, i.e. a {@code @BindsInstance} method with
+ * zero or many parameters.
+ */
+ // TODO(dpb): should this be an ImmutableList<TypeMirror>, with this class checking the size?
+ protected abstract Optional<TypeMirror> bindingElementType();
+
+ /**
+ * Adds an error if the {@link #bindingElementType() binding element type} is not appropriate.
+ *
+ * <p>Adds an error if the type is not a primitive, array, declared type, or type variable.
+ *
+ * <p>If the binding is not a multibinding contribution, adds an error if the type is a
+ * framework type.
+ *
+ * <p>If the element has {@link ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES}, adds an
+ * error if the type is not a {@code Set<T>} for some {@code T}
+ */
+ protected void checkType() {
+ switch (ContributionType.fromBindingElement(element)) {
+ case UNIQUE:
+ /* Validate that a unique binding is not attempting to bind a framework type. This
+ * validation is only appropriate for unique bindings because multibindings may collect
+ * framework types. E.g. Set<Provider<Foo>> is perfectly reasonable. */
+ checkFrameworkType();
+ // fall through
+
+ case SET:
+ case MAP:
+ bindingElementType().ifPresent(type -> checkKeyType(type));
+ break;
+
+ case SET_VALUES:
+ checkSetValuesType();
+ }
+ }
+
+ /**
+ * Adds an error if {@code keyType} is not a primitive, declared type, array, or type variable.
+ */
+ protected void checkKeyType(TypeMirror keyType) {
+ TypeKind kind = keyType.getKind();
+ if (kind.equals(VOID)) {
+ report.addError(bindingElements("must %s a value (not void)", bindingElementTypeVerb()));
+ } else if (!(kind.isPrimitive()
+ || kind.equals(DECLARED)
+ || kind.equals(ARRAY)
+ || kind.equals(TYPEVAR))) {
+ report.addError(badTypeMessage());
+ }
+ }
+
+ /**
+ * Adds an error if the type for an element with {@link ElementsIntoSet @ElementsIntoSet} or
+ * {@code SET_VALUES} is not a a {@code Set<T>} for a reasonable {@code T}.
+ */
+ // TODO(gak): should we allow "covariant return" for set values?
+ protected void checkSetValuesType() {
+ bindingElementType().ifPresent(keyType -> checkSetValuesType(keyType));
+ }
+
+ /** Adds an error if {@code type} is not a {@code Set<T>} for a reasonable {@code T}. */
+ protected final void checkSetValuesType(TypeMirror type) {
+ if (!SetType.isSet(type)) {
+ report.addError(elementsIntoSetNotASetMessage());
+ } else {
+ SetType setType = SetType.from(type);
+ if (setType.isRawType()) {
+ report.addError(elementsIntoSetRawSetMessage());
+ } else {
+ checkKeyType(setType.elementType());
+ }
+ }
+ }
+
+ /**
+ * Adds an error if the element has more than one {@linkplain Qualifier qualifier} annotation.
+ */
+ private void checkQualifiers() {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(element);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ report.addError(
+ bindingElements("may not use more than one @Qualifier"),
+ element,
+ qualifier);
+ }
+ }
+ }
+
+ /**
+ * Adds an error if an {@link IntoMap @IntoMap} element doesn't have exactly one {@link
+ * MapKey @MapKey} annotation, or if an element that is {@link IntoMap @IntoMap} has any.
+ */
+ private void checkMapKeys() {
+ if (!allowsMultibindings.allowsMultibindings()) {
+ return;
+ }
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(element);
+ if (ContributionType.fromBindingElement(element).equals(ContributionType.MAP)) {
+ switch (mapKeys.size()) {
+ case 0:
+ report.addError(bindingElements("of type map must declare a map key"));
+ break;
+ case 1:
+ break;
+ default:
+ report.addError(bindingElements("may not have more than one map key"));
+ break;
+ }
+ } else if (!mapKeys.isEmpty()) {
+ report.addError(bindingElements("of non map type cannot declare a map key"));
+ }
+ }
+
+ /**
+ * Adds errors if:
+ *
+ * <ul>
+ * <li>the element doesn't allow {@linkplain MultibindingAnnotations multibinding annotations}
+ * and has any
+ * <li>the element does allow them but has more than one
+ * <li>the element has a multibinding annotation and its {@link Provides} or {@link Produces}
+ * annotation has a {@code type} parameter.
+ * </ul>
+ */
+ private void checkMultibindings() {
+ ImmutableSet<AnnotationMirror> multibindingAnnotations =
+ MultibindingAnnotations.forElement(element);
+
+ switch (allowsMultibindings) {
+ case NO_MULTIBINDINGS:
+ for (AnnotationMirror annotation : multibindingAnnotations) {
+ report.addError(
+ bindingElements("cannot have multibinding annotations"),
+ element,
+ annotation);
+ }
+ break;
+
+ case ALLOWS_MULTIBINDINGS:
+ if (multibindingAnnotations.size() > 1) {
+ for (AnnotationMirror annotation : multibindingAnnotations) {
+ report.addError(
+ bindingElements("cannot have more than one multibinding annotation"),
+ element,
+ annotation);
+ }
+ }
+ break;
+ }
+
+ // TODO(ronshapiro): move this into ProvidesMethodValidator
+ if (bindingAnnotation.equals(Provides.class)) {
+ AnnotationMirror bindingAnnotationMirror =
+ getAnnotationMirror(element, bindingAnnotation).get();
+ boolean usesProvidesType = false;
+ for (ExecutableElement member : bindingAnnotationMirror.getElementValues().keySet()) {
+ usesProvidesType |= member.getSimpleName().contentEquals("type");
+ }
+ if (usesProvidesType && !multibindingAnnotations.isEmpty()) {
+ report.addError(
+ "@Provides.type cannot be used with multibinding annotations", element);
+ }
+ }
+ }
+
+ /**
+ * Adds an error if the element has a scope but doesn't allow scoping, or if it has more than
+ * one {@linkplain Scope scope} annotation.
+ */
+ private void checkScopes() {
+ ImmutableSet<Scope> scopes = scopesOf(element);
+ String error = null;
+ switch (allowsScoping) {
+ case ALLOWS_SCOPING:
+ if (scopes.size() <= 1) {
+ return;
+ }
+ error = bindingElements("cannot use more than one @Scope");
+ break;
+ case NO_SCOPING:
+ error = bindingElements("cannot be scoped");
+ break;
+ }
+ verifyNotNull(error);
+ for (Scope scope : scopes) {
+ report.addError(error, element, scope.scopeAnnotation());
+ }
+ }
+
+ /**
+ * Adds an error if the {@link #bindingElementType() type} is a {@linkplain FrameworkTypes
+ * framework type}.
+ */
+ private void checkFrameworkType() {
+ if (bindingElementType().filter(FrameworkTypes::isFrameworkType).isPresent()) {
+ report.addError(bindingElements("must not %s framework types", bindingElementTypeVerb()));
+ }
+ }
+ }
+
+ /** Whether to check multibinding annotations. */
+ enum AllowsMultibindings {
+ /**
+ * This element disallows multibinding annotations, so don't bother checking for their validity.
+ * {@link MultibindingAnnotationsProcessingStep} will add errors if the element has any
+ * multibinding annotations.
+ */
+ NO_MULTIBINDINGS,
+
+ /** This element allows multibinding annotations, so validate them. */
+ ALLOWS_MULTIBINDINGS,
+ ;
+
+ private boolean allowsMultibindings() {
+ return this == ALLOWS_MULTIBINDINGS;
+ }
+ }
+
+ /** How to check scoping annotations. */
+ enum AllowsScoping {
+ /** This element disallows scoping, so check that no scope annotations are present. */
+ NO_SCOPING,
+
+ /** This element allows scoping, so validate that there's at most one scope annotation. */
+ ALLOWS_SCOPING,
+ ;
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingExpression.java b/java/dagger/internal/codegen/BindingExpression.java
new file mode 100644
index 0000000..65200f7
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingExpression.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2017 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 dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import javax.lang.model.type.TypeMirror;
+
+/** A factory of code expressions used to access a single request for a binding in a component. */
+// TODO(user): Rename this to RequestExpression?
+abstract class BindingExpression {
+
+ /**
+ * Returns an expression that evaluates to the value of a request based on the given requesting
+ * class.
+ *
+ * @param requestingClass the class that will contain the expression
+ */
+ abstract Expression getDependencyExpression(ClassName requestingClass);
+
+ /**
+ * Equivalent to {@link #getDependencyExpression} that is used only when the request is for an
+ * implementation of a component method. By default, just delegates to {@link
+ * #getDependencyExpression}.
+ */
+ Expression getDependencyExpressionForComponentMethod(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ return getDependencyExpression(component.name());
+ }
+
+ /** Returns {@code true} if this binding expression should be encapsulated in a method. */
+ boolean requiresMethodEncapsulation() {
+ return false;
+ }
+
+ /**
+ * Returns an expression for the implementation of a component method with the given request.
+ *
+ * @param component the component that will contain the implemented method
+ */
+ CodeBlock getComponentMethodImplementation(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ // By default, just delegate to #getDependencyExpression().
+ return CodeBlock.of(
+ "return $L;",
+ getDependencyExpressionForComponentMethod(componentMethod, component).codeBlock());
+ }
+
+ /**
+ * Returns an expression for the implementation of a modifiable binding method for the given
+ * component.
+ */
+ CodeBlock getModifiableBindingMethodImplementation(
+ ModifiableBindingMethod modifiableBindingMethod,
+ ComponentImplementation component,
+ DaggerTypes types) {
+ Expression dependencyExpression = getDependencyExpression(component.name());
+
+ // It's possible to have a case where a modifiable component method delegates to another
+ // binding method from an enclosing class that is not itself a component method. In that case,
+ // the enclosing class's method may return a publicly accessible type, but the nested class will
+ // have a return type that is defined by the component method. In that case, a downcast is
+ // necessary so that the return statement is valid.
+ //
+ // E.g.:
+ //
+ // public class DaggerAncestor implements Ancestor {
+ // protected Object packagePrivateModifiable() { ... }
+ //
+ // protected class LeafImpl extends DaggerLeaf {
+ // @Override
+ // public final PackagePrivateModifiable componentMethod() {
+ // return (PackagePrivateModifiable) DaggerAncestor.this.packagePrivateModifiable();
+ // }
+ // }
+ // }
+ //
+ // DaggerAncestor.packagePrivateModifiable returns Object even though the actual instance's type
+ // is PackagePrivateModifiable. So a cast is necessary.
+ //
+ // This isn't necessary for getComponentMethodImplementation() because that's only used for
+ // non-modifiable bindings
+ TypeMirror returnType = modifiableBindingMethod.returnType();
+ if (!types.isAssignable(dependencyExpression.type(), returnType)
+ && isTypeAccessibleFrom(returnType, component.name().packageName())) {
+ dependencyExpression = dependencyExpression.castTo(returnType);
+ }
+
+ return CodeBlock.of("return $L;", dependencyExpression.codeBlock());
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingFactory.java b/java/dagger/internal/codegen/BindingFactory.java
new file mode 100644
index 0000000..564b412
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingFactory.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2017 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkArgument;
+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.Binding.hasNonDefaultTypeParameters;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
+import static dagger.internal.codegen.ConfigurationAnnotations.getNullableType;
+import static dagger.internal.codegen.ContributionBinding.bindingKindForMultibindingKey;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MoreAnnotationMirrors.wrapOptionalInEquivalence;
+import static dagger.internal.codegen.Scopes.uniqueScopeOf;
+import static dagger.model.BindingKind.BOUND_INSTANCE;
+import static dagger.model.BindingKind.COMPONENT;
+import static dagger.model.BindingKind.COMPONENT_DEPENDENCY;
+import static dagger.model.BindingKind.COMPONENT_PRODUCTION;
+import static dagger.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.model.BindingKind.DELEGATE;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MEMBERS_INJECTOR;
+import static dagger.model.BindingKind.OPTIONAL;
+import static dagger.model.BindingKind.PRODUCTION;
+import static dagger.model.BindingKind.PROVISION;
+import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Iterables;
+import dagger.Module;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.ProductionBinding.ProductionKind;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import javax.inject.Inject;
+import javax.inject.Provider;
+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.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+/** A factory for {@link Binding} objects. */
+final class BindingFactory {
+ private final DaggerTypes types;
+ private final KeyFactory keyFactory;
+ private final DependencyRequestFactory dependencyRequestFactory;
+ private final InjectionSiteFactory injectionSiteFactory;
+ private final DaggerElements elements;
+
+ @Inject
+ BindingFactory(
+ DaggerTypes types,
+ DaggerElements elements,
+ KeyFactory keyFactory,
+ DependencyRequestFactory dependencyRequestFactory,
+ InjectionSiteFactory injectionSiteFactory) {
+ this.types = types;
+ this.elements = elements;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ this.injectionSiteFactory = injectionSiteFactory;
+ }
+
+ /**
+ * Returns an {@link dagger.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
+ * binding should be for the parameterized type
+ */
+ // TODO(dpb): See if we can just pass the parameterized type and not also the constructor.
+ ProvisionBinding injectionBinding(
+ ExecutableElement constructorElement, Optional<TypeMirror> resolvedType) {
+ checkArgument(constructorElement.getKind().equals(CONSTRUCTOR));
+ checkArgument(isAnnotationPresent(constructorElement, Inject.class));
+ checkArgument(!getQualifier(constructorElement).isPresent());
+
+ ExecutableType constructorType = MoreTypes.asExecutable(constructorElement.asType());
+ DeclaredType constructedType =
+ MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
+ // If the class this is constructing has some type arguments, resolve everything.
+ if (!constructedType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
+ DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get());
+ // Validate that we're resolving from the correct type.
+ checkState(
+ types.isSameType(types.erasure(resolved), types.erasure(constructedType)),
+ "erased expected type: %s, erased actual type: %s",
+ types.erasure(resolved),
+ types.erasure(constructedType));
+ constructorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement));
+ constructedType = resolved;
+ }
+
+ Key key = keyFactory.forInjectConstructorWithResolvedType(constructedType);
+ ImmutableSet<DependencyRequest> provisionDependencies =
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ constructorElement.getParameters(), constructorType.getParameterTypes());
+
+ ProvisionBinding.Builder builder =
+ ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .bindingElement(constructorElement)
+ .key(key)
+ .provisionDependencies(provisionDependencies)
+ .injectionSites(injectionSiteFactory.getInjectionSites(constructedType))
+ .kind(INJECTION)
+ .scope(uniqueScopeOf(constructorElement.getEnclosingElement()));
+
+ TypeElement bindingTypeElement = MoreElements.asType(constructorElement.getEnclosingElement());
+ if (hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types)) {
+ builder.unresolved(injectionBinding(constructorElement, Optional.empty()));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#PROVISION} binding for a {@code @Provides}-annotated
+ * method.
+ *
+ * @param contributedBy the installed module that declares or inherits the method
+ */
+ ProvisionBinding providesMethodBinding(
+ ExecutableElement providesMethod, TypeElement contributedBy) {
+ return setMethodBindingProperties(
+ ProvisionBinding.builder(),
+ providesMethod,
+ contributedBy,
+ keyFactory.forProvidesMethod(providesMethod, contributedBy),
+ this::providesMethodBinding)
+ .kind(PROVISION)
+ .scope(uniqueScopeOf(providesMethod))
+ .nullableType(getNullableType(providesMethod))
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#PRODUCTION} binding for a {@code @Produces}-annotated
+ * method.
+ *
+ * @param contributedBy the installed module that declares or inherits the method
+ */
+ ProductionBinding producesMethodBinding(
+ ExecutableElement producesMethod, TypeElement contributedBy) {
+ // TODO(beder): Add nullability checking with Java 8.
+ ProductionBinding.Builder builder =
+ setMethodBindingProperties(
+ ProductionBinding.builder(),
+ producesMethod,
+ contributedBy,
+ keyFactory.forProducesMethod(producesMethod, contributedBy),
+ this::producesMethodBinding)
+ .kind(PRODUCTION)
+ .productionKind(ProductionKind.fromProducesMethod(producesMethod))
+ .thrownTypes(producesMethod.getThrownTypes())
+ .executorRequest(dependencyRequestFactory.forProductionImplementationExecutor())
+ .monitorRequest(dependencyRequestFactory.forProductionComponentMonitor());
+ return builder.build();
+ }
+
+ private <C extends ContributionBinding, B extends ContributionBinding.Builder<C, B>>
+ B setMethodBindingProperties(
+ B builder,
+ ExecutableElement method,
+ TypeElement contributedBy,
+ Key key,
+ BiFunction<ExecutableElement, TypeElement, C> create) {
+ checkArgument(method.getKind().equals(METHOD));
+ ExecutableType methodType =
+ MoreTypes.asExecutable(
+ types.asMemberOf(MoreTypes.asDeclared(contributedBy.asType()), method));
+ if (!types.isSameType(methodType, method.asType())) {
+ builder.unresolved(create.apply(method, MoreElements.asType(method.getEnclosingElement())));
+ }
+ return builder
+ .contributionType(ContributionType.fromBindingElement(method))
+ .bindingElement(method)
+ .contributingModule(contributedBy)
+ .key(key)
+ .dependencies(
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ method.getParameters(), methodType.getParameterTypes()))
+ .wrappedMapKeyAnnotation(wrapOptionalInEquivalence(getMapKey(method)));
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#MULTIBOUND_MAP} or {@link
+ * dagger.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding contribution
+ * bindings.
+ *
+ * @param key a key that may be satisfied by a multibinding
+ */
+ ContributionBinding syntheticMultibinding(
+ Key key, Iterable<ContributionBinding> multibindingContributions) {
+ ContributionBinding.Builder<?, ?> builder =
+ multibindingRequiresProduction(key, multibindingContributions)
+ ? ProductionBinding.builder()
+ : ProvisionBinding.builder();
+ return builder
+ .contributionType(ContributionType.UNIQUE)
+ .key(key)
+ .dependencies(
+ dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
+ .kind(bindingKindForMultibindingKey(key))
+ .build();
+ }
+
+ private boolean multibindingRequiresProduction(
+ Key key, Iterable<ContributionBinding> multibindingContributions) {
+ if (MapType.isMap(key)) {
+ MapType mapType = MapType.from(key);
+ if (mapType.valuesAreTypeOf(Producer.class) || mapType.valuesAreTypeOf(Produced.class)) {
+ return true;
+ }
+ } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(Produced.class)) {
+ return true;
+ }
+ return Iterables.any(
+ multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION));
+ }
+
+ /** Returns a {@link dagger.model.BindingKind#COMPONENT} binding for the component. */
+ ProvisionBinding componentBinding(TypeElement componentDefinitionType) {
+ checkNotNull(componentDefinitionType);
+ return ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .bindingElement(componentDefinitionType)
+ .key(keyFactory.forType(componentDefinitionType.asType()))
+ .kind(COMPONENT)
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#COMPONENT_DEPENDENCY} binding for a component's
+ * dependency.
+ */
+ ProvisionBinding componentDependencyBinding(ComponentRequirement dependency) {
+ checkNotNull(dependency);
+ return ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .bindingElement(dependency.typeElement())
+ .key(keyFactory.forType(dependency.type()))
+ .kind(COMPONENT_DEPENDENCY)
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#COMPONENT_PROVISION} or {@link
+ * dagger.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
+ */
+ ContributionBinding componentDependencyMethodBinding(
+ ComponentDescriptor componentDescriptor, ExecutableElement dependencyMethod) {
+ checkArgument(dependencyMethod.getKind().equals(METHOD));
+ checkArgument(dependencyMethod.getParameters().isEmpty());
+ ContributionBinding.Builder<?, ?> builder;
+ if (componentDescriptor.isProduction()
+ && isComponentProductionMethod(elements, dependencyMethod)) {
+ builder =
+ ProductionBinding.builder()
+ .key(keyFactory.forProductionComponentMethod(dependencyMethod))
+ .kind(COMPONENT_PRODUCTION)
+ .thrownTypes(dependencyMethod.getThrownTypes());
+ } else {
+ builder =
+ ProvisionBinding.builder()
+ .key(keyFactory.forComponentMethod(dependencyMethod))
+ .nullableType(getNullableType(dependencyMethod))
+ .kind(COMPONENT_PROVISION)
+ .scope(uniqueScopeOf(dependencyMethod));
+ }
+ return builder
+ .contributionType(ContributionType.UNIQUE)
+ .bindingElement(dependencyMethod)
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#BOUND_INSTANCE} binding for a
+ * {@code @BindsInstance}-annotated builder setter method or factory method parameter.
+ */
+ ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, Element element) {
+ checkArgument(element instanceof VariableElement || element instanceof ExecutableElement);
+ VariableElement parameterElement =
+ element instanceof VariableElement
+ ? MoreElements.asVariable(element)
+ : getOnlyElement(MoreElements.asExecutable(element).getParameters());
+ return ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .bindingElement(element)
+ .key(requirement.key().get())
+ .nullableType(getNullableType(parameterElement))
+ .kind(BOUND_INSTANCE)
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.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()}.
+ *
+ * @param component the component that declares or inherits the method
+ */
+ ProvisionBinding subcomponentCreatorBinding(
+ ExecutableElement subcomponentCreatorMethod, TypeElement component) {
+ checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD));
+ checkArgument(subcomponentCreatorMethod.getParameters().isEmpty());
+ Key key =
+ keyFactory.forSubcomponentCreatorMethod(
+ subcomponentCreatorMethod, asDeclared(component.asType()));
+ return ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .bindingElement(subcomponentCreatorMethod)
+ .key(key)
+ .kind(SUBCOMPONENT_CREATOR)
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared using {@link
+ * Module#subcomponents()}.
+ */
+ ProvisionBinding subcomponentCreatorBinding(
+ ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
+ SubcomponentDeclaration subcomponentDeclaration = subcomponentDeclarations.iterator().next();
+ return ProvisionBinding.builder()
+ .contributionType(ContributionType.UNIQUE)
+ .key(subcomponentDeclaration.key())
+ .kind(SUBCOMPONENT_CREATOR)
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#DELEGATE} binding.
+ *
+ * @param delegateDeclaration the {@code @Binds}-annotated declaration
+ * @param actualBinding the binding that satisfies the {@code @Binds} declaration
+ */
+ ContributionBinding delegateBinding(
+ DelegateDeclaration delegateDeclaration, ContributionBinding actualBinding) {
+ switch (actualBinding.bindingType()) {
+ case PRODUCTION:
+ return buildDelegateBinding(
+ ProductionBinding.builder().nullableType(actualBinding.nullableType()),
+ delegateDeclaration,
+ Producer.class);
+
+ case PROVISION:
+ return buildDelegateBinding(
+ ProvisionBinding.builder()
+ .scope(uniqueScopeOf(delegateDeclaration.bindingElement().get()))
+ .nullableType(actualBinding.nullableType()),
+ delegateDeclaration,
+ Provider.class);
+
+ case MEMBERS_INJECTION: // fall-through to throw
+ }
+ throw new AssertionError("bindingType: " + actualBinding);
+ }
+
+ /**
+ * Returns a {@link dagger.model.BindingKind#DELEGATE} binding used when there is no binding that
+ * satisfies the {@code @Binds} declaration.
+ */
+ ContributionBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) {
+ return buildDelegateBinding(
+ ProvisionBinding.builder().scope(uniqueScopeOf(delegateDeclaration.bindingElement().get())),
+ delegateDeclaration,
+ Provider.class);
+ }
+
+ private ContributionBinding buildDelegateBinding(
+ ContributionBinding.Builder<?, ?> builder,
+ DelegateDeclaration delegateDeclaration,
+ Class<?> frameworkType) {
+ return builder
+ .contributionType(delegateDeclaration.contributionType())
+ .bindingElement(delegateDeclaration.bindingElement().get())
+ .contributingModule(delegateDeclaration.contributingModule().get())
+ .key(keyFactory.forDelegateBinding(delegateDeclaration, frameworkType))
+ .dependencies(delegateDeclaration.delegateRequest())
+ .wrappedMapKeyAnnotation(delegateDeclaration.wrappedMapKey())
+ .kind(DELEGATE)
+ .build();
+ }
+
+ /**
+ * Returns an {@link dagger.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
+ * the underlying (non-optional) key
+ */
+ ContributionBinding syntheticOptionalBinding(
+ Key key, RequestKind requestKind, ResolvedBindings underlyingKeyBindings) {
+ ContributionBinding.Builder<?, ?> builder =
+ syntheticOptionalBindingBuilder(requestKind, underlyingKeyBindings)
+ .contributionType(ContributionType.UNIQUE)
+ .key(key)
+ .kind(OPTIONAL);
+ if (!underlyingKeyBindings.isEmpty()) {
+ builder.dependencies(
+ dependencyRequestFactory.forSyntheticPresentOptionalBinding(key, requestKind));
+ }
+ return builder.build();
+ }
+
+ private ContributionBinding.Builder<?, ?> syntheticOptionalBindingBuilder(
+ RequestKind requestKind, ResolvedBindings underlyingKeyBindings) {
+ return !underlyingKeyBindings.isEmpty()
+ && (underlyingKeyBindings.bindingTypes().contains(BindingType.PRODUCTION)
+ || requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases
+ || requestKind.equals(RequestKind.PRODUCED)) // handles producerFromProvider cases
+ ? ProductionBinding.builder()
+ : ProvisionBinding.builder();
+ }
+
+ /** Returns a {@link dagger.model.BindingKind#MEMBERS_INJECTOR} binding. */
+ ProvisionBinding membersInjectorBinding(
+ Key key, MembersInjectionBinding membersInjectionBinding) {
+ return ProvisionBinding.builder()
+ .key(key)
+ .contributionType(ContributionType.UNIQUE)
+ .kind(MEMBERS_INJECTOR)
+ .bindingElement(MoreTypes.asTypeElement(membersInjectionBinding.key().type()))
+ .provisionDependencies(membersInjectionBinding.dependencies())
+ .injectionSites(membersInjectionBinding.injectionSites())
+ .build();
+ }
+
+ /**
+ * Returns a {@link dagger.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
+ */
+ // TODO(dpb): See if we can just pass one nongeneric/parameterized type.
+ MembersInjectionBinding membersInjectionBinding(
+ DeclaredType declaredType, Optional<TypeMirror> resolvedType) {
+ // If the class this is injecting has some type arguments, resolve everything.
+ if (!declaredType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
+ DeclaredType resolved = asDeclared(resolvedType.get());
+ // Validate that we're resolving from the correct type.
+ checkState(
+ types.isSameType(types.erasure(resolved), types.erasure(declaredType)),
+ "erased expected type: %s, erased actual type: %s",
+ types.erasure(resolved),
+ types.erasure(declaredType));
+ declaredType = resolved;
+ }
+ ImmutableSortedSet<InjectionSite> injectionSites =
+ injectionSiteFactory.getInjectionSites(declaredType);
+ ImmutableSet<DependencyRequest> dependencies =
+ injectionSites
+ .stream()
+ .flatMap(injectionSite -> injectionSite.dependencies().stream())
+ .collect(toImmutableSet());
+
+ Key key = keyFactory.forMembersInjectedType(declaredType);
+ TypeElement typeElement = MoreElements.asType(declaredType.asElement());
+ return new AutoValue_MembersInjectionBinding(
+ key,
+ dependencies,
+ typeElement,
+ hasNonDefaultTypeParameters(typeElement, key.type(), types)
+ ? Optional.of(
+ membersInjectionBinding(asDeclared(typeElement.asType()), Optional.empty()))
+ : Optional.empty(),
+ injectionSites);
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingGraph.java b/java/dagger/internal/codegen/BindingGraph.java
new file mode 100644
index 0000000..2f548b2
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraph.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.DaggerStreams.presentValues;
+import static dagger.internal.codegen.DaggerStreams.stream;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+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.Maps;
+import com.google.common.collect.Multimaps;
+import com.google.common.graph.Traverser;
+import dagger.Subcomponent;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+
+/** The canonical representation of a full-resolved graph. */
+@AutoValue
+abstract class BindingGraph {
+ abstract ComponentDescriptor componentDescriptor();
+
+ /**
+ * The resolved bindings for all {@link ContributionBinding}s in this graph, keyed by {@link Key}.
+ */
+ // TODO(ronshapiro): when MembersInjectionBinding no longer extends Binding, rename this to
+ // bindings()
+ abstract ImmutableMap<Key, ResolvedBindings> contributionBindings();
+
+ /**
+ * The resolved bindings for all {@link MembersInjectionBinding}s in this graph, keyed by {@link
+ * Key}.
+ */
+ abstract ImmutableMap<Key, ResolvedBindings> membersInjectionBindings();
+
+ /**
+ * Returns the {@link ResolvedBindings resolved bindings} instance for {@code
+ * bindingExpressionKey}. If the bindings will be used for members injection, a {@link
+ * ResolvedBindings} with {@linkplain #membersInjectionBindings() members injection bindings} will
+ * be returned, otherwise a {@link ResolvedBindings} with {@link #contributionBindings()} will be
+ * returned.
+ */
+ final ResolvedBindings resolvedBindings(BindingRequest request) {
+ return request.isRequestKind(RequestKind.MEMBERS_INJECTION)
+ ? membersInjectionBindings().get(request.key())
+ : contributionBindings().get(request.key());
+ }
+
+ final Iterable<ResolvedBindings> resolvedBindings() {
+ // Don't return an immutable collection - this is only ever used for looping over all bindings
+ // in the graph. Copying is wasteful, especially if is a hashing collection, since the values
+ // should all, by definition, be distinct.
+ // TODO(dpb): consider inlining this to callers and removing this.
+ return Iterables.concat(membersInjectionBindings().values(), contributionBindings().values());
+ }
+
+ abstract ImmutableList<BindingGraph> subgraphs();
+
+ /**
+ * The type that defines the component for this graph.
+ *
+ * @see ComponentDescriptor#typeElement()
+ */
+ TypeElement componentTypeElement() {
+ return componentDescriptor().typeElement();
+ }
+
+ /**
+ * Returns the set of modules that are owned by this graph regardless of whether or not any of
+ * their bindings are used in this graph. For graphs representing top-level {@link
+ * dagger.Component components}, this set will be the same as {@linkplain
+ * ComponentDescriptor#modules() the component's transitive modules}. For {@linkplain Subcomponent
+ * subcomponents}, this set will be the transitive modules that are not owned by any of their
+ * ancestors.
+ */
+ abstract ImmutableSet<ModuleDescriptor> ownedModules();
+
+ @Memoized
+ ImmutableSet<TypeElement> ownedModuleTypes() {
+ return FluentIterable.from(ownedModules()).transform(ModuleDescriptor::moduleElement).toSet();
+ }
+
+ /**
+ * Returns the factory method for this subcomponent, if it exists.
+ *
+ * <p>This factory method is the one defined in the parent component's interface.
+ *
+ * <p>In the example below, the {@link BindingGraph#factoryMethod} for {@code ChildComponent}
+ * would return the {@link ExecutableElement}: {@code childComponent(ChildModule1)} .
+ *
+ * <pre><code>
+ * {@literal @Component}
+ * interface ParentComponent {
+ * ChildComponent childComponent(ChildModule1 childModule);
+ * }
+ * </code></pre>
+ */
+ // TODO(b/73294201): Consider returning the resolved ExecutableType for the factory method.
+ abstract Optional<ExecutableElement> factoryMethod();
+
+ /**
+ * Returns a map between the {@linkplain ComponentRequirement component requirement} and the
+ * corresponding {@link VariableElement} for each module parameter in the {@linkplain
+ * BindingGraph#factoryMethod factory method}.
+ */
+ // TODO(dpb): Consider disallowing modules if none of their bindings are used.
+ ImmutableMap<ComponentRequirement, VariableElement> factoryMethodParameters() {
+ checkState(factoryMethod().isPresent());
+ ImmutableMap.Builder<ComponentRequirement, VariableElement> builder = ImmutableMap.builder();
+ for (VariableElement parameter : factoryMethod().get().getParameters()) {
+ builder.put(ComponentRequirement.forModule(parameter.asType()), parameter);
+ }
+ return builder.build();
+ }
+
+ private static final Traverser<BindingGraph> SUBGRAPH_TRAVERSER =
+ Traverser.forTree(BindingGraph::subgraphs);
+
+ /**
+ * The types for which the component needs instances.
+ *
+ * <ul>
+ * <li>component dependencies
+ * <li>{@linkplain #ownedModules() owned modules} with concrete instance bindings that are used
+ * in the graph
+ * <li>bound instances
+ * </ul>
+ */
+ @Memoized
+ ImmutableSet<ComponentRequirement> componentRequirements() {
+ ImmutableSet<TypeElement> requiredModules = requiredModuleElements();
+ ImmutableSet.Builder<ComponentRequirement> requirements = ImmutableSet.builder();
+ componentDescriptor().requirements().stream()
+ .filter(
+ requirement ->
+ !requirement.kind().isModule()
+ || requiredModules.contains(requirement.typeElement()))
+ .forEach(requirements::add);
+ if (factoryMethod().isPresent()) {
+ requirements.addAll(factoryMethodParameters().keySet());
+ }
+ return requirements.build();
+ }
+
+ private ImmutableSet<TypeElement> requiredModuleElements() {
+ return stream(SUBGRAPH_TRAVERSER.depthFirstPostOrder(this))
+ .flatMap(graph -> graph.contributionBindings().values().stream())
+ .flatMap(bindings -> bindings.contributionBindings().stream())
+ .map(ContributionBinding::contributingModule)
+ .distinct()
+ .flatMap(presentValues())
+ .filter(ownedModuleTypes()::contains)
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the {@link ComponentDescriptor}s for this component and its subcomponents. */
+ ImmutableSet<ComponentDescriptor> componentDescriptors() {
+ return FluentIterable.from(SUBGRAPH_TRAVERSER.depthFirstPreOrder(this))
+ .transform(BindingGraph::componentDescriptor)
+ .toSet();
+ }
+
+ /**
+ * {@code true} if this graph contains all bindings installed in the component; {@code false} if
+ * it contains only those bindings that are reachable from at least one entry point.
+ */
+ abstract boolean isFullBindingGraph();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override // Suppresses ErrorProne warning that hashCode was overridden w/o equals
+ public abstract boolean equals(Object other);
+
+ static BindingGraph create(
+ ComponentDescriptor componentDescriptor,
+ Map<Key, ResolvedBindings> resolvedContributionBindingsMap,
+ Map<Key, ResolvedBindings> resolvedMembersInjectionBindings,
+ List<BindingGraph> subgraphs,
+ Set<ModuleDescriptor> ownedModules,
+ Optional<ExecutableElement> factoryMethod,
+ boolean isFullBindingGraph) {
+ checkForDuplicates(subgraphs);
+ return new AutoValue_BindingGraph(
+ componentDescriptor,
+ ImmutableMap.copyOf(resolvedContributionBindingsMap),
+ ImmutableMap.copyOf(resolvedMembersInjectionBindings),
+ ImmutableList.copyOf(subgraphs),
+ ImmutableSet.copyOf(ownedModules),
+ factoryMethod,
+ isFullBindingGraph);
+ }
+
+ private static final void checkForDuplicates(Iterable<BindingGraph> graphs) {
+ Map<TypeElement, Collection<BindingGraph>> duplicateGraphs =
+ Maps.filterValues(
+ Multimaps.index(graphs, graph -> graph.componentDescriptor().typeElement()).asMap(),
+ overlapping -> overlapping.size() > 1);
+ if (!duplicateGraphs.isEmpty()) {
+ throw new IllegalArgumentException("Expected no duplicates: " + duplicateGraphs);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingGraphConverter.java b/java/dagger/internal/codegen/BindingGraphConverter.java
new file mode 100644
index 0000000..a2cc799
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraphConverter.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 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.auto.common.MoreTypes.asTypeElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.DaggerGraphs.unreachableNodes;
+import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.Network;
+import com.google.common.graph.NetworkBuilder;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.BindingGraph.Edge;
+import dagger.model.BindingGraph.MissingBinding;
+import dagger.model.BindingGraph.Node;
+import dagger.model.BindingGraphProxies;
+import dagger.model.ComponentPath;
+import dagger.model.DependencyRequest;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/** Converts {@link dagger.internal.codegen.BindingGraph}s to {@link dagger.model.BindingGraph}s. */
+final class BindingGraphConverter {
+ private final BindingDeclarationFormatter bindingDeclarationFormatter;
+
+ @Inject
+ BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) {
+ this.bindingDeclarationFormatter = bindingDeclarationFormatter;
+ }
+
+ /**
+ * Creates the external {@link dagger.model.BindingGraph} representing the given internal {@link
+ * dagger.internal.codegen.BindingGraph}.
+ */
+ dagger.model.BindingGraph convert(BindingGraph bindingGraph) {
+ Traverser traverser = new Traverser(bindingGraph);
+ traverser.traverseComponents();
+
+ // When bindings are copied down into child graphs because they transitively depend on local
+ // multibindings or optional bindings, the parent-owned binding is still there. If that
+ // parent-owned binding is not reachable from its component, it doesn't need to be in the graph
+ // because it will never be used. So remove all nodes that are not reachable from the root
+ // component—unless we're converting a full binding graph.
+ if (!bindingGraph.isFullBindingGraph()) {
+ unreachableNodes(traverser.network.asGraph(), rootComponentNode(traverser.network))
+ .forEach(traverser.network::removeNode);
+ }
+
+ return BindingGraphProxies.bindingGraph(traverser.network, bindingGraph.isFullBindingGraph());
+ }
+
+ // TODO(dpb): Example of BindingGraph logic applied to derived networks.
+ private ComponentNode rootComponentNode(Network<Node, Edge> network) {
+ return (ComponentNode)
+ Iterables.find(
+ network.nodes(),
+ node -> node instanceof ComponentNode && node.componentPath().atRoot());
+ }
+
+ private final class Traverser extends ComponentTreeTraverser {
+ private final MutableNetwork<Node, Edge> network =
+ NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
+ private final boolean isRootSubcomponent;
+ private final boolean isFullBindingGraph;
+
+ private final ComponentPath rootComponentPath;
+ private ComponentNode parentComponent;
+ private ComponentNode currentComponent;
+
+ Traverser(BindingGraph graph) {
+ super(graph);
+ rootComponentPath = ComponentPath.create(ImmutableList.of(graph.componentTypeElement()));
+ isRootSubcomponent = graph.componentDescriptor().isSubcomponent();
+ isFullBindingGraph = graph.isFullBindingGraph();
+ }
+
+ @Override
+ protected void visitComponent(BindingGraph graph) {
+ ComponentNode grandparentComponent = parentComponent;
+ parentComponent = currentComponent;
+ currentComponent = ComponentNodeImpl.create(componentPath(), graph.componentDescriptor());
+
+ network.addNode(currentComponent);
+
+ for (ResolvedBindings resolvedBindings : graph.resolvedBindings()) {
+ for (BindingNode binding : bindingNodes(resolvedBindings)) {
+ addBinding(binding);
+ if (binding.kind().equals(SUBCOMPONENT_CREATOR)
+ && binding.componentPath().equals(currentComponent.componentPath())) {
+ network.addEdge(
+ binding,
+ subcomponentNode(binding.key().type(), graph),
+ new SubcomponentCreatorBindingEdgeImpl(
+ resolvedBindings.subcomponentDeclarations()));
+ }
+ }
+ }
+
+ super.visitComponent(graph);
+
+ currentComponent = parentComponent;
+ parentComponent = grandparentComponent;
+ }
+
+ @Override
+ protected void visitEntryPoint(DependencyRequest entryPoint, BindingGraph graph) {
+ addDependencyEdges(currentComponent, entryPoint);
+ super.visitEntryPoint(entryPoint, graph);
+ }
+
+ @Override
+ protected void visitSubcomponentFactoryMethod(
+ BindingGraph graph, BindingGraph parent, ExecutableElement factoryMethod) {
+ network.addEdge(
+ parentComponent, currentComponent, new ChildFactoryMethodEdgeImpl(factoryMethod));
+ super.visitSubcomponentFactoryMethod(graph, parent, factoryMethod);
+ }
+
+ /**
+ * Adds a {@link dagger.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);
+ if (dependencies.isEmpty()) {
+ addDependencyEdge(source, dependencyRequest, missingBindingNode(dependencies));
+ } else {
+ for (BindingNode dependency : bindingNodes(dependencies)) {
+ addDependencyEdge(source, dependencyRequest, dependency);
+ }
+ }
+ }
+
+ private void addDependencyEdge(
+ Node source, DependencyRequest dependencyRequest, Node dependency) {
+ network.addNode(dependency);
+ if (!hasDependencyEdge(source, dependency, dependencyRequest)) {
+ network.addEdge(
+ source,
+ dependency,
+ new DependencyEdgeImpl(dependencyRequest, source instanceof ComponentNode));
+ }
+ }
+
+ private boolean hasDependencyEdge(
+ Node source, Node dependency, DependencyRequest dependencyRequest) {
+ // An iterative approach is used instead of a Stream because this method is called in a hot
+ // loop, and the Stream calculates the size of network.edgesConnecting(), which is slow. This
+ // seems to be because caculating the edges connecting two nodes in a Network that supports
+ // parallel edges is must check the equality of many nodes, and BindingNode's equality
+ // semantics drag in the equality of many other expensive objects
+ for (Edge edge : network.edgesConnecting(source, dependency)) {
+ if (edge instanceof DependencyEdge) {
+ if (((DependencyEdge) edge).dependencyRequest().equals(dependencyRequest)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private ResolvedBindings resolvedDependencies(
+ Node source, DependencyRequest dependencyRequest) {
+ return graphForAncestor(source.componentPath().currentComponent())
+ .resolvedBindings(bindingRequest(dependencyRequest));
+ }
+
+ /** Adds a binding and all its dependencies. */
+ private void addBinding(BindingNode binding) {
+ network.addNode(binding);
+ for (DependencyRequest dependencyRequest : binding.dependencies()) {
+ addDependencyEdges(binding, dependencyRequest);
+ }
+ }
+
+ private ImmutableSet<BindingNode> bindingNodes(ResolvedBindings resolvedBindings) {
+ ImmutableSet.Builder<BindingNode> bindingNodes = ImmutableSet.builder();
+ resolvedBindings
+ .allBindings()
+ .asMap()
+ .forEach(
+ (component, bindings) -> {
+ for (Binding binding : bindings) {
+ bindingNodes.add(bindingNode(resolvedBindings, binding, component));
+ }
+ });
+ return bindingNodes.build();
+ }
+
+ private BindingNode bindingNode(
+ ResolvedBindings resolvedBindings, Binding binding, TypeElement owningComponent) {
+ return BindingNode.create(
+ pathFromRootToAncestor(owningComponent),
+ binding,
+ resolvedBindings.multibindingDeclarations(),
+ resolvedBindings.optionalBindingDeclarations(),
+ resolvedBindings.subcomponentDeclarations(),
+ bindingDeclarationFormatter);
+ }
+
+ private MissingBinding missingBindingNode(ResolvedBindings dependencies) {
+ // TODO(b/117833324): Revisit whether limiting missing binding nodes to the root component is
+ // necessary to limit the amount of missing binding nodes in the network, or if perhaps *all*
+ // missing binding nodes should be structured this way.
+ return BindingGraphProxies.missingBindingNode(
+ isRootSubcomponent && !isFullBindingGraph ? rootComponentPath : componentPath(),
+ dependencies.key());
+ }
+
+ private ComponentNode subcomponentNode(TypeMirror subcomponentBuilderType, BindingGraph graph) {
+ TypeElement subcomponentBuilderElement = asTypeElement(subcomponentBuilderType);
+ ComponentDescriptor subcomponent =
+ graph.componentDescriptor().getChildComponentWithBuilderType(subcomponentBuilderElement);
+ return ComponentNodeImpl.create(
+ componentPath().childPath(subcomponent.typeElement()), subcomponent);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingGraphFactory.java b/java/dagger/internal/codegen/BindingGraphFactory.java
new file mode 100644
index 0000000..d96da8a
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraphFactory.java
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreTypes.isType;
+import static com.google.auto.common.MoreTypes.isTypeOf;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.isEmpty;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.RequestKinds.getRequestKind;
+import static dagger.internal.codegen.SourceFiles.generatedMonitoringModuleName;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.model.BindingKind.DELEGATE;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.OPTIONAL;
+import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
+import static dagger.model.RequestKind.MEMBERS_INJECTION;
+import static java.util.function.Predicate.isEqual;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import dagger.MembersInjector;
+import dagger.Reusable;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.Scope;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.internal.ProductionExecutorModule;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Queue;
+import java.util.Set;
+import java.util.function.Function;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/** A factory for {@link BindingGraph} objects. */
+@Singleton
+final class BindingGraphFactory implements ClearableCache {
+ private final DaggerElements elements;
+ private final InjectBindingRegistry injectBindingRegistry;
+ private final KeyFactory keyFactory;
+ private final BindingFactory bindingFactory;
+ private final ModuleDescriptor.Factory moduleDescriptorFactory;
+ private final Map<Key, ImmutableSet<Key>> keysMatchingRequestCache = new HashMap<>();
+
+ @Inject
+ BindingGraphFactory(
+ DaggerElements elements,
+ InjectBindingRegistry injectBindingRegistry,
+ KeyFactory keyFactory,
+ BindingFactory bindingFactory,
+ ModuleDescriptor.Factory moduleDescriptorFactory) {
+ this.elements = elements;
+ this.injectBindingRegistry = injectBindingRegistry;
+ this.keyFactory = keyFactory;
+ this.bindingFactory = bindingFactory;
+ this.moduleDescriptorFactory = moduleDescriptorFactory;
+ }
+
+ /**
+ * Creates a binding graph for a component.
+ *
+ * @param createFullBindingGraph if {@code true}, the binding graph will include all bindings;
+ * otherwise it will include only bindings reachable from at least one entry point
+ */
+ BindingGraph create(ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) {
+ return create(Optional.empty(), componentDescriptor, createFullBindingGraph);
+ }
+
+ private BindingGraph create(
+ Optional<Resolver> parentResolver,
+ ComponentDescriptor componentDescriptor,
+ boolean createFullBindingGraph) {
+ ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder();
+ ImmutableSet.Builder<DelegateDeclaration> delegatesBuilder = ImmutableSet.builder();
+ ImmutableSet.Builder<OptionalBindingDeclaration> optionalsBuilder = ImmutableSet.builder();
+
+ if (componentDescriptor.isRealComponent()) {
+ // binding for the component itself
+ explicitBindingsBuilder.add(
+ bindingFactory.componentBinding(componentDescriptor.typeElement()));
+ }
+
+ // Collect Component dependencies.
+ for (ComponentRequirement dependency : componentDescriptor.dependencies()) {
+ explicitBindingsBuilder.add(bindingFactory.componentDependencyBinding(dependency));
+ List<ExecutableElement> dependencyMethods =
+ methodsIn(elements.getAllMembers(dependency.typeElement()));
+ for (ExecutableElement method : dependencyMethods) {
+ // MembersInjection methods aren't "provided" explicitly, so ignore them.
+ if (isComponentContributionMethod(elements, method)) {
+ explicitBindingsBuilder.add(
+ bindingFactory.componentDependencyMethodBinding(componentDescriptor, method));
+ }
+ }
+ }
+
+ // Collect bindings on the creator.
+ componentDescriptor
+ .creatorDescriptor()
+ .ifPresent(
+ creatorDescriptor ->
+ creatorDescriptor.boundInstanceRequirements().stream()
+ .map(
+ requirement ->
+ bindingFactory.boundInstanceBinding(
+ requirement, creatorDescriptor.elementForRequirement(requirement)))
+ .forEach(explicitBindingsBuilder::add));
+
+ componentDescriptor
+ .childComponentsDeclaredByBuilderEntryPoints()
+ .forEach(
+ (builderEntryPoint, childComponent) -> {
+ if (!componentDescriptor
+ .childComponentsDeclaredByModules()
+ .contains(childComponent)) {
+ explicitBindingsBuilder.add(
+ bindingFactory.subcomponentCreatorBinding(
+ builderEntryPoint.methodElement(), componentDescriptor.typeElement()));
+ }
+ });
+
+ ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations = ImmutableSet.builder();
+ ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations = ImmutableSet.builder();
+
+ // Collect transitive module bindings and multibinding declarations.
+ for (ModuleDescriptor moduleDescriptor : modules(componentDescriptor, parentResolver)) {
+ explicitBindingsBuilder.addAll(moduleDescriptor.bindings());
+ multibindingDeclarations.addAll(moduleDescriptor.multibindingDeclarations());
+ subcomponentDeclarations.addAll(moduleDescriptor.subcomponentDeclarations());
+ delegatesBuilder.addAll(moduleDescriptor.delegateDeclarations());
+ optionalsBuilder.addAll(moduleDescriptor.optionalDeclarations());
+ }
+
+ final Resolver requestResolver =
+ new Resolver(
+ parentResolver,
+ componentDescriptor,
+ indexBindingDeclarationsByKey(explicitBindingsBuilder.build()),
+ indexBindingDeclarationsByKey(multibindingDeclarations.build()),
+ indexBindingDeclarationsByKey(subcomponentDeclarations.build()),
+ indexBindingDeclarationsByKey(delegatesBuilder.build()),
+ indexBindingDeclarationsByKey(optionalsBuilder.build()));
+
+ componentDescriptor.entryPointMethods().stream()
+ .map(method -> method.dependencyRequest().get())
+ .forEach(
+ entryPoint -> {
+ if (entryPoint.kind().equals(MEMBERS_INJECTION)) {
+ requestResolver.resolveMembersInjection(entryPoint.key());
+ } else {
+ requestResolver.resolve(entryPoint.key());
+ }
+ });
+
+ if (createFullBindingGraph) {
+ // Resolve the keys for all bindings in all modules, stripping any multibinding contribution
+ // identifier so that the multibinding itself is resolved.
+ modules(componentDescriptor, parentResolver).stream()
+ .flatMap(module -> module.allBindingKeys().stream())
+ .map(key -> key.toBuilder().multibindingContributionIdentifier(Optional.empty()).build())
+ .forEach(requestResolver::resolve);
+ }
+
+ // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have
+ // been detected during binding resolution. If a binding for a subcomponent is never resolved,
+ // no BindingGraph will be created for it and no implementation will be generated. This is
+ // done in a queue since resolving one subcomponent might resolve a key for a subcomponent
+ // from a parent graph. This is done until no more new subcomponents are resolved.
+ Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>();
+ ImmutableList.Builder<BindingGraph> subgraphs = ImmutableList.builder();
+ for (ComponentDescriptor subcomponent :
+ Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) {
+ if (resolvedSubcomponents.add(subcomponent)) {
+ subgraphs.add(create(Optional.of(requestResolver), subcomponent, createFullBindingGraph));
+ }
+ }
+
+ return BindingGraph.create(
+ componentDescriptor,
+ requestResolver.getResolvedContributionBindings(),
+ requestResolver.getResolvedMembersInjectionBindings(),
+ subgraphs.build(),
+ requestResolver.getOwnedModules(),
+ requestResolver.getFactoryMethod(),
+ createFullBindingGraph);
+ }
+
+ /**
+ * Returns all the modules that should be installed in the component. For production components
+ * and production subcomponents that have a parent that is not a production component or
+ * subcomponent, also includes the production monitoring module for the component and the
+ * production executor module.
+ */
+ private ImmutableSet<ModuleDescriptor> modules(
+ ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver) {
+ return shouldIncludeImplicitProductionModules(componentDescriptor, parentResolver)
+ ? new ImmutableSet.Builder<ModuleDescriptor>()
+ .addAll(componentDescriptor.modules())
+ .add(descriptorForMonitoringModule(componentDescriptor.typeElement()))
+ .add(descriptorForProductionExecutorModule())
+ .build()
+ : componentDescriptor.modules();
+ }
+
+ private boolean shouldIncludeImplicitProductionModules(
+ ComponentDescriptor component, Optional<Resolver> parentResolver) {
+ return component.isProduction()
+ && ((!component.isSubcomponent() && component.isRealComponent())
+ || (parentResolver.isPresent()
+ && !parentResolver.get().componentDescriptor.isProduction()));
+ }
+
+ /**
+ * Returns a descriptor for a generated module that handles monitoring for production components.
+ * This module is generated in the {@link MonitoringModuleProcessingStep}.
+ *
+ * @throws TypeNotPresentException if the module has not been generated yet. This will cause the
+ * processor to retry in a later processing round.
+ */
+ private ModuleDescriptor descriptorForMonitoringModule(TypeElement componentDefinitionType) {
+ return moduleDescriptorFactory.create(
+ elements.checkTypePresent(
+ generatedMonitoringModuleName(componentDefinitionType).toString()));
+ }
+
+ /** Returns a descriptor {@link ProductionExecutorModule}. */
+ private ModuleDescriptor descriptorForProductionExecutorModule() {
+ return moduleDescriptorFactory.create(elements.getTypeElement(ProductionExecutorModule.class));
+ }
+
+ /** Indexes {@code bindingDeclarations} by {@link BindingDeclaration#key()}. */
+ private static <T extends BindingDeclaration>
+ ImmutableSetMultimap<Key, T> indexBindingDeclarationsByKey(Iterable<T> declarations) {
+ return ImmutableSetMultimap.copyOf(Multimaps.index(declarations, BindingDeclaration::key));
+ }
+
+ @Override
+ public void clearCache() {
+ keysMatchingRequestCache.clear();
+ }
+
+ private final class Resolver {
+ final Optional<Resolver> parentResolver;
+ final ComponentDescriptor componentDescriptor;
+ final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings;
+ final ImmutableSet<ContributionBinding> explicitBindingsSet;
+ final ImmutableSetMultimap<Key, ContributionBinding> explicitMultibindings;
+ final ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations;
+ final ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations;
+ final ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations;
+ final ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations;
+ final ImmutableSetMultimap<Key, DelegateDeclaration> delegateMultibindingDeclarations;
+ final Map<Key, ResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>();
+ final Map<Key, ResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>();
+ final Deque<Key> cycleStack = new ArrayDeque<>();
+ final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>();
+ final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>();
+ final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>();
+
+ Resolver(
+ Optional<Resolver> parentResolver,
+ ComponentDescriptor componentDescriptor,
+ ImmutableSetMultimap<Key, ContributionBinding> explicitBindings,
+ ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations,
+ ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations,
+ ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations,
+ ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations) {
+ this.parentResolver = parentResolver;
+ this.componentDescriptor = checkNotNull(componentDescriptor);
+ this.explicitBindings = checkNotNull(explicitBindings);
+ this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values());
+ this.multibindingDeclarations = checkNotNull(multibindingDeclarations);
+ this.subcomponentDeclarations = checkNotNull(subcomponentDeclarations);
+ this.delegateDeclarations = checkNotNull(delegateDeclarations);
+ this.optionalBindingDeclarations = checkNotNull(optionalBindingDeclarations);
+ this.explicitMultibindings = multibindingContributionsByMultibindingKey(explicitBindingsSet);
+ this.delegateMultibindingDeclarations =
+ multibindingContributionsByMultibindingKey(delegateDeclarations.values());
+ subcomponentsToResolve.addAll(
+ componentDescriptor.childComponentsDeclaredByFactoryMethods().values());
+ subcomponentsToResolve.addAll(
+ componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values());
+ }
+
+ /** Returns the optional factory method for this component. */
+ Optional<ExecutableElement> getFactoryMethod() {
+ return parentResolver
+ .flatMap(
+ parent ->
+ parent.componentDescriptor.getFactoryMethodForChildComponent(componentDescriptor))
+ .map(method -> method.methodElement());
+ }
+
+ /**
+ * Returns the resolved contribution bindings for the given {@link Key}:
+ *
+ * <ul>
+ * <li>All explicit bindings for:
+ * <ul>
+ * <li>the requested key
+ * <li>{@code Set<T>} if the requested key's type is {@code Set<Produced<T>>}
+ * <li>{@code Map<K, Provider<V>>} if the requested key's type is {@code Map<K,
+ * Producer<V>>}.
+ * </ul>
+ * <li>A synthetic binding that depends on {@code Map<K, Producer<V>>} if the requested key's
+ * type is {@code Map<K, V>} and there are some explicit bindings for {@code Map<K,
+ * Producer<V>>}.
+ * <li>A synthetic binding that depends on {@code Map<K, Provider<V>>} if the requested key's
+ * type is {@code Map<K, V>} and there are some explicit bindings for {@code Map<K,
+ * Provider<V>>} but no explicit bindings for {@code Map<K, Producer<V>>}.
+ * <li>An implicit {@link Inject @Inject}-annotated constructor binding if there is one and
+ * there are no explicit bindings or synthetic bindings.
+ * </ul>
+ */
+ ResolvedBindings lookUpBindings(Key requestKey) {
+ Set<ContributionBinding> bindings = new LinkedHashSet<>();
+ bindings.addAll(getExplicitBindings(requestKey));
+
+ ImmutableSet<ContributionBinding> multibindingContributions =
+ getAllMatchingBindingDeclarations(requestKey, this::getExplicitMultibindings);
+ ImmutableSet<MultibindingDeclaration> multibindingDeclarations =
+ getAllMatchingBindingDeclarations(requestKey, this::getMultibindingDeclarations);
+
+ syntheticMultibinding(requestKey, multibindingContributions, multibindingDeclarations)
+ .ifPresent(bindings::add);
+
+ ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations =
+ getAllMatchingBindingDeclarations(requestKey, this::getOptionalBindingDeclarations);
+ syntheticOptionalBinding(requestKey, optionalBindingDeclarations).ifPresent(bindings::add);
+
+ ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations =
+ getSubcomponentDeclarations(requestKey);
+ syntheticSubcomponentBuilderBinding(subcomponentDeclarations)
+ .ifPresent(
+ binding -> {
+ bindings.add(binding);
+ addSubcomponentToOwningResolver(binding);
+ });
+
+ if (isType(requestKey.type()) && isTypeOf(MembersInjector.class, requestKey.type())) {
+ injectBindingRegistry
+ .getOrFindMembersInjectorProvisionBinding(requestKey)
+ .ifPresent(bindings::add);
+ }
+
+ // If there are no bindings, add the implicit @Inject-constructed binding if there is one.
+ if (bindings.isEmpty()) {
+ injectBindingRegistry.getOrFindProvisionBinding(requestKey)
+ .filter(binding -> !isIncorrectlyScopedInPartialGraph(binding))
+ .ifPresent(bindings::add);
+ }
+
+ return ResolvedBindings.forContributionBindings(
+ requestKey,
+ indexBindingsByOwningComponent(requestKey, ImmutableSet.copyOf(bindings)),
+ multibindingDeclarations,
+ subcomponentDeclarations,
+ optionalBindingDeclarations);
+ }
+
+ /**
+ * Returns true if this binding graph resolution is for a partial graph and the {@code @Inject}
+ * binding's scope doesn't match any of the components in the current component ancestry. If so,
+ * the binding is not owned by any of the currently known components, and will be owned by a
+ * future ancestor (or, if never owned, will result in an incompatibly scoped binding error at
+ * the root component).
+ */
+ private boolean isIncorrectlyScopedInPartialGraph(ProvisionBinding binding) {
+ checkArgument(binding.kind().equals(INJECTION));
+ Resolver owningResolver = getOwningResolver(binding).orElse(this);
+ ComponentDescriptor owningComponent = owningResolver.componentDescriptor;
+ return rootComponent().isSubcomponent()
+ && binding.scope().isPresent()
+ && !binding.scope().get().isReusable()
+ && !owningComponent.scopes().contains(binding.scope().get());
+ }
+
+ private ComponentDescriptor rootComponent() {
+ return parentResolver.map(Resolver::rootComponent).orElse(componentDescriptor);
+ }
+
+ /** Returns the resolved members injection bindings for the given {@link Key}. */
+ ResolvedBindings lookUpMembersInjectionBinding(Key requestKey) {
+ // no explicit deps for members injection, so just look it up
+ Optional<MembersInjectionBinding> binding =
+ injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey);
+ return binding.isPresent()
+ ? ResolvedBindings.forMembersInjectionBinding(
+ requestKey, componentDescriptor, binding.get())
+ : ResolvedBindings.noBindings(requestKey);
+ }
+
+ /**
+ * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link
+ * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue
+ * will be used to detect which subcomponents need to be resolved.
+ */
+ private void addSubcomponentToOwningResolver(ProvisionBinding subcomponentCreatorBinding) {
+ checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR));
+ Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get();
+
+ TypeElement builderType = MoreTypes.asTypeElement(subcomponentCreatorBinding.key().type());
+ owningResolver.subcomponentsToResolve.add(
+ owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType));
+ }
+
+ /**
+ * Profiling has determined that computing the keys matching {@code requestKey} has measurable
+ * performance impact. It is called repeatedly (at least 3 times per key resolved per {@link
+ * BindingGraph}. {@code javac}'s name-checking performance seems suboptimal (converting byte
+ * strings to Strings repeatedly), and the matching keys creations relies on that. This also
+ * ensures that the resulting keys have their hash codes cached on successive calls to this
+ * method.
+ *
+ * <p>This caching may become obsolete if:
+ *
+ * <ul>
+ * <li>We decide to intern all {@link Key} instances
+ * <li>We fix javac's name-checking peformance (though we may want to keep this for older
+ * javac users)
+ * </ul>
+ */
+ private ImmutableSet<Key> keysMatchingRequest(Key requestKey) {
+ return keysMatchingRequestCache.computeIfAbsent(
+ requestKey, this::keysMatchingRequestUncached);
+ }
+
+ private ImmutableSet<Key> keysMatchingRequestUncached(Key requestKey) {
+ ImmutableSet.Builder<Key> keys = ImmutableSet.builder();
+ keys.add(requestKey);
+ keyFactory.unwrapSetKey(requestKey, Produced.class).ifPresent(keys::add);
+ keyFactory.rewrapMapKey(requestKey, Producer.class, Provider.class).ifPresent(keys::add);
+ keyFactory.rewrapMapKey(requestKey, Provider.class, Producer.class).ifPresent(keys::add);
+ keys.addAll(keyFactory.implicitFrameworkMapKeys(requestKey));
+ return keys.build();
+ }
+
+ /**
+ * Returns a synthetic binding that depends on individual multibinding contributions.
+ *
+ * <p>If there are no {@code multibindingContributions} or {@code multibindingDeclarations},
+ * returns {@link Optional#empty()}.
+ *
+ * <p>If there are production {@code multibindingContributions} or the request is for any of the
+ * following types, returns a {@link ProductionBinding}.
+ *
+ * <ul>
+ * <li>{@code Set<Produced<T>>}
+ * <li>{@code Map<K, Producer<V>>}
+ * <li>{@code Map<K, Produced<V>>}
+ * </ul>
+ *
+ * Otherwise, returns a {@link ProvisionBinding}.
+ */
+ private Optional<ContributionBinding> syntheticMultibinding(
+ Key key,
+ Iterable<ContributionBinding> multibindingContributions,
+ Iterable<MultibindingDeclaration> multibindingDeclarations) {
+ return isEmpty(multibindingContributions) && isEmpty(multibindingDeclarations)
+ ? Optional.empty()
+ : Optional.of(bindingFactory.syntheticMultibinding(key, multibindingContributions));
+ }
+
+ private Optional<ProvisionBinding> syntheticSubcomponentBuilderBinding(
+ ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
+ return subcomponentDeclarations.isEmpty()
+ ? Optional.empty()
+ : Optional.of(bindingFactory.subcomponentCreatorBinding(subcomponentDeclarations));
+ }
+
+ /**
+ * Returns a synthetic binding for {@code @Qualifier Optional<Type>} if there are any {@code
+ * optionalBindingDeclarations}.
+ *
+ * <p>If there are no bindings for the underlying key (the key for dependency requests for
+ * {@code Type}), returns a provision binding that always returns {@link Optional#empty()}.
+ *
+ * <p>If there are any production bindings for the underlying key, returns a production binding.
+ * Otherwise returns a provision binding.
+ */
+ private Optional<ContributionBinding> syntheticOptionalBinding(
+ Key key, ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations) {
+ return optionalBindingDeclarations.isEmpty()
+ ? Optional.empty()
+ : Optional.of(
+ bindingFactory.syntheticOptionalBinding(
+ key,
+ getRequestKind(OptionalType.from(key).valueType()),
+ lookUpBindings(keyFactory.unwrapOptional(key).get())));
+ }
+
+ private ImmutableSet<ContributionBinding> createDelegateBindings(
+ ImmutableSet<DelegateDeclaration> delegateDeclarations) {
+ ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
+ for (DelegateDeclaration delegateDeclaration : delegateDeclarations) {
+ builder.add(createDelegateBinding(delegateDeclaration));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved
+ * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate
+ * bindings for the dependency key, there should still be only one binding for the delegate key.
+ */
+ private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) {
+ Key delegateKey = delegateDeclaration.delegateRequest().key();
+ if (cycleStack.contains(delegateKey)) {
+ return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
+ }
+
+ ResolvedBindings resolvedDelegate;
+ try {
+ cycleStack.push(delegateKey);
+ resolvedDelegate = lookUpBindings(delegateKey);
+ } finally {
+ cycleStack.pop();
+ }
+ if (resolvedDelegate.contributionBindings().isEmpty()) {
+ // This is guaranteed to result in a missing binding error, so it doesn't matter if the
+ // binding is a Provision or Production, except if it is a @IntoMap method, in which
+ // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a
+ // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a
+ // strange error, that the RHS needs to be provided with an @Inject or @Provides
+ // annotated method, but a user should be able to figure out if a @Produces annotation
+ // is needed.
+ // TODO(gak): revisit how we model missing delegates if/when we clean up how we model
+ // binding declarations
+ return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
+ }
+ // It doesn't matter which of these is selected, since they will later on produce a
+ // duplicate binding error.
+ ContributionBinding explicitDelegate =
+ resolvedDelegate.contributionBindings().iterator().next();
+ return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate);
+ }
+
+ // TODO(dpb,ronshapiro): requestKey appears to be interchangeable with each binding's .key(),
+ // but should it? We're currently conflating the two all over the place and it would be good
+ // to unify, or if it's necessary, clarify why with docs+tests. Specifically, should we also
+ // be checking these for keysMatchingRequest?
+ private ImmutableSetMultimap<TypeElement, ContributionBinding> indexBindingsByOwningComponent(
+ Key requestKey, Iterable<? extends ContributionBinding> bindings) {
+ ImmutableSetMultimap.Builder<TypeElement, ContributionBinding> index =
+ ImmutableSetMultimap.builder();
+ for (ContributionBinding binding : bindings) {
+ index.put(getOwningComponent(requestKey, binding), binding);
+ }
+ return index.build();
+ }
+
+ /**
+ * Returns the component that should contain the framework field for {@code binding}.
+ *
+ * <p>If {@code binding} is either not bound in an ancestor component or depends transitively on
+ * bindings in this component, returns this component.
+ *
+ * <p>Otherwise, resolves {@code request} in this component's parent in order to resolve any
+ * multibinding contributions in the parent, and returns the parent-resolved {@link
+ * ResolvedBindings#owningComponent(ContributionBinding)}.
+ */
+ private TypeElement getOwningComponent(Key requestKey, ContributionBinding binding) {
+ if (isResolvedInParent(requestKey, binding)
+ && !new LocalDependencyChecker().dependsOnLocalBindings(binding)) {
+ ResolvedBindings parentResolvedBindings =
+ parentResolver.get().resolvedContributionBindings.get(requestKey);
+ return parentResolvedBindings.owningComponent(binding);
+ } else {
+ return componentDescriptor.typeElement();
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code binding} is owned by an ancestor. If so, {@linkplain #resolve
+ * resolves} the {@link Key} in this component's parent. Don't resolve directly in the owning
+ * component in case it depends on multibindings in any of its descendants.
+ */
+ private boolean isResolvedInParent(Key requestKey, ContributionBinding binding) {
+ Optional<Resolver> owningResolver = getOwningResolver(binding);
+ if (owningResolver.isPresent() && !owningResolver.get().equals(this)) {
+ parentResolver.get().resolve(requestKey);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private Optional<Resolver> getOwningResolver(ContributionBinding binding) {
+ // TODO(ronshapiro): extract the different pieces of this method into their own methods
+ if ((binding.scope().isPresent() && binding.scope().get().isProductionScope())
+ || binding.bindingType().equals(BindingType.PRODUCTION)) {
+ for (Resolver requestResolver : getResolverLineage()) {
+ // Resolve @Inject @ProductionScope bindings at the highest production component.
+ if (binding.kind().equals(INJECTION)
+ && requestResolver.componentDescriptor.isProduction()) {
+ return Optional.of(requestResolver);
+ }
+
+ // Resolve explicit @Produces and @ProductionScope bindings at the highest component that
+ // installs the binding.
+ if (requestResolver.containsExplicitBinding(binding)) {
+ return Optional.of(requestResolver);
+ }
+ }
+ }
+
+ if (binding.scope().isPresent() && binding.scope().get().isReusable()) {
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ // If a @Reusable binding was resolved in an ancestor, use that component.
+ ResolvedBindings resolvedBindings =
+ requestResolver.resolvedContributionBindings.get(binding.key());
+ if (resolvedBindings != null
+ && resolvedBindings.contributionBindings().contains(binding)) {
+ return Optional.of(requestResolver);
+ }
+ }
+ // If a @Reusable binding was not resolved in any ancestor, resolve it here.
+ return Optional.empty();
+ }
+
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ if (requestResolver.containsExplicitBinding(binding)) {
+ return Optional.of(requestResolver);
+ }
+ }
+
+ // look for scope separately. we do this for the case where @Singleton can appear twice
+ // in the † compatibility mode
+ Optional<Scope> bindingScope = binding.scope();
+ if (bindingScope.isPresent()) {
+ for (Resolver requestResolver : getResolverLineage().reverse()) {
+ if (requestResolver.componentDescriptor.scopes().contains(bindingScope.get())) {
+ return Optional.of(requestResolver);
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ private boolean containsExplicitBinding(ContributionBinding binding) {
+ return explicitBindingsSet.contains(binding)
+ || resolverContainsDelegateDeclarationForBinding(binding)
+ || subcomponentDeclarations.containsKey(binding.key());
+ }
+
+ /** Returns true if {@code binding} was installed in a module in this resolver's component. */
+ private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) {
+ return binding.kind().equals(DELEGATE)
+ && delegateDeclarations.get(binding.key()).stream()
+ .anyMatch(
+ declaration ->
+ declaration.contributingModule().equals(binding.contributingModule())
+ && declaration.bindingElement().equals(binding.bindingElement()));
+ }
+
+ /** Returns the resolver lineage from parent to child. */
+ private ImmutableList<Resolver> getResolverLineage() {
+ ImmutableList.Builder<Resolver> resolverList = ImmutableList.builder();
+ for (Optional<Resolver> currentResolver = Optional.of(this);
+ currentResolver.isPresent();
+ currentResolver = currentResolver.get().parentResolver) {
+ resolverList.add(currentResolver.get());
+ }
+ return resolverList.build().reverse();
+ }
+
+ /**
+ * For all {@linkplain #keysMatchingRequest(Key) keys matching {@code requestKey}}, applies
+ * {@code getDeclarationsPerKey} and collects the values into an {@link ImmutableSet}.
+ */
+ private <T extends BindingDeclaration> ImmutableSet<T> getAllMatchingBindingDeclarations(
+ Key requestKey, Function<Key, Collection<T>> getDeclarationsPerKey) {
+ return keysMatchingRequest(requestKey)
+ .stream()
+ .flatMap(key -> getDeclarationsPerKey.apply(key).stream())
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this and
+ * all ancestor resolvers.
+ */
+ private ImmutableSet<ContributionBinding> getExplicitBindings(Key key) {
+ ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ bindings.addAll(resolver.getLocalExplicitBindings(key));
+ }
+ return bindings.build();
+ }
+
+ /**
+ * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this
+ * resolver.
+ */
+ private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) {
+ return new ImmutableSet.Builder<ContributionBinding>()
+ .addAll(explicitBindings.get(key))
+ // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces
+ // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's
+ // value type if it's a Map<K, Provider/Producer<V>> before looking in
+ // delegateDeclarations. createDelegateBindings() will create bindings with the properly
+ // wrapped key type.
+ .addAll(
+ createDelegateBindings(delegateDeclarations.get(keyFactory.unwrapMapValueType(key))))
+ .build();
+ }
+
+ /**
+ * Returns the explicit multibinding contributions that contribute to the map or set requested
+ * by {@code key} from this and all ancestor resolvers.
+ */
+ private ImmutableSet<ContributionBinding> getExplicitMultibindings(Key key) {
+ ImmutableSet.Builder<ContributionBinding> multibindings = ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ multibindings.addAll(resolver.getLocalExplicitMultibindings(key));
+ }
+ return multibindings.build();
+ }
+
+ /**
+ * Returns the explicit multibinding contributions that contribute to the map or set requested
+ * by {@code key} from this resolver.
+ */
+ private ImmutableSet<ContributionBinding> getLocalExplicitMultibindings(Key key) {
+ ImmutableSet.Builder<ContributionBinding> multibindings = ImmutableSet.builder();
+ multibindings.addAll(explicitMultibindings.get(key));
+ if (!MapType.isMap(key)
+ || MapType.from(key).isRawType()
+ || MapType.from(key).valuesAreFrameworkType()) {
+ // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces
+ // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's
+ // value type if it's a Map<K, Provider/Producer<V>> before looking in
+ // delegateMultibindingDeclarations. createDelegateBindings() will create bindings with the
+ // properly wrapped key type.
+ multibindings.addAll(
+ createDelegateBindings(
+ delegateMultibindingDeclarations.get(keyFactory.unwrapMapValueType(key))));
+ }
+ return multibindings.build();
+ }
+
+ /**
+ * Returns the {@link MultibindingDeclaration}s that match the {@code key} from this and all
+ * ancestor resolvers.
+ */
+ private ImmutableSet<MultibindingDeclaration> getMultibindingDeclarations(Key key) {
+ ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations =
+ ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ multibindingDeclarations.addAll(resolver.multibindingDeclarations.get(key));
+ }
+ return multibindingDeclarations.build();
+ }
+
+ /**
+ * Returns the {@link SubcomponentDeclaration}s that match the {@code key} from this and all
+ * ancestor resolvers.
+ */
+ private ImmutableSet<SubcomponentDeclaration> getSubcomponentDeclarations(Key key) {
+ ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations =
+ ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ subcomponentDeclarations.addAll(resolver.subcomponentDeclarations.get(key));
+ }
+ return subcomponentDeclarations.build();
+ }
+ /**
+ * Returns the {@link OptionalBindingDeclaration}s that match the {@code key} from this and all
+ * ancestor resolvers.
+ */
+ private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) {
+ Optional<Key> unwrapped = keyFactory.unwrapOptional(key);
+ if (!unwrapped.isPresent()) {
+ return ImmutableSet.of();
+ }
+ ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder();
+ for (Resolver resolver : getResolverLineage()) {
+ declarations.addAll(resolver.optionalBindingDeclarations.get(unwrapped.get()));
+ }
+ return declarations.build();
+ }
+
+ /**
+ * Returns the {@link ResolvedBindings} for {@code key} that was resolved in this resolver or an
+ * ancestor resolver. Only checks for {@link ContributionBinding}s as {@link
+ * MembersInjectionBinding}s are not inherited.
+ */
+ private Optional<ResolvedBindings> getPreviouslyResolvedBindings(Key key) {
+ Optional<ResolvedBindings> result =
+ Optional.ofNullable(resolvedContributionBindings.get(key));
+ if (result.isPresent()) {
+ return result;
+ } else if (parentResolver.isPresent()) {
+ return parentResolver.get().getPreviouslyResolvedBindings(key);
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ private void resolveMembersInjection(Key key) {
+ ResolvedBindings bindings = lookUpMembersInjectionBinding(key);
+ resolveDependencies(bindings);
+ resolvedMembersInjectionBindings.put(key, bindings);
+ }
+
+ void resolve(Key key) {
+ // If we find a cycle, stop resolving. The original request will add it with all of the
+ // other resolved deps.
+ if (cycleStack.contains(key)) {
+ return;
+ }
+
+ // If the binding was previously resolved in this (sub)component, don't resolve it again.
+ if (resolvedContributionBindings.containsKey(key)) {
+ return;
+ }
+
+ /*
+ * If the binding was previously resolved in an ancestor component, then we may be able to
+ * avoid resolving it here and just depend on the ancestor component resolution.
+ *
+ * 1. If it depends transitively on multibinding contributions or optional bindings with
+ * bindings from this subcomponent, then we have to resolve it in this subcomponent so
+ * that it sees the local bindings.
+ *
+ * 2. If there are any explicit bindings in this component, they may conflict with those in
+ * the ancestor component, so resolve them here so that conflicts can be caught.
+ */
+ if (getPreviouslyResolvedBindings(key).isPresent()) {
+ /* Resolve in the parent in case there are multibinding contributions or conflicts in some
+ * component between this one and the previously-resolved one. */
+ parentResolver.get().resolve(key);
+ if (!new LocalDependencyChecker().dependsOnLocalBindings(key)
+ && getLocalExplicitBindings(key).isEmpty()) {
+ /* Cache the inherited parent component's bindings in case resolving at the parent found
+ * bindings in some component between this one and the previously-resolved one. */
+ resolvedContributionBindings.put(key, getPreviouslyResolvedBindings(key).get());
+ return;
+ }
+ }
+
+ cycleStack.push(key);
+ try {
+ ResolvedBindings bindings = lookUpBindings(key);
+ resolvedContributionBindings.put(key, bindings);
+ resolveDependencies(bindings);
+ } finally {
+ cycleStack.pop();
+ }
+ }
+
+ /**
+ * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this
+ * component.
+ */
+ private void resolveDependencies(ResolvedBindings resolvedBindings) {
+ for (Binding binding : resolvedBindings.bindingsOwnedBy(componentDescriptor)) {
+ for (DependencyRequest dependency : binding.dependencies()) {
+ resolve(dependency.key());
+ }
+ }
+ }
+
+ /**
+ * Returns all of the {@link ResolvedBindings} for {@link ContributionBinding}s from this and
+ * all ancestor resolvers, indexed by {@link ResolvedBindings#key()}.
+ */
+ Map<Key, ResolvedBindings> getResolvedContributionBindings() {
+ Map<Key, ResolvedBindings> bindings = new LinkedHashMap<>();
+ parentResolver.ifPresent(parent -> bindings.putAll(parent.getResolvedContributionBindings()));
+ bindings.putAll(resolvedContributionBindings);
+ return bindings;
+ }
+
+ /**
+ * Returns all of the {@link ResolvedBindings} for {@link MembersInjectionBinding} from this
+ * resolvers, indexed by {@link ResolvedBindings#key()}.
+ */
+ ImmutableMap<Key, ResolvedBindings> getResolvedMembersInjectionBindings() {
+ return ImmutableMap.copyOf(resolvedMembersInjectionBindings);
+ }
+
+ ImmutableSet<ModuleDescriptor> getInheritedModules() {
+ return parentResolver.isPresent()
+ ? Sets.union(
+ parentResolver.get().getInheritedModules(),
+ parentResolver.get().componentDescriptor.modules())
+ .immutableCopy()
+ : ImmutableSet.<ModuleDescriptor>of();
+ }
+
+ ImmutableSet<ModuleDescriptor> getOwnedModules() {
+ return Sets.difference(componentDescriptor.modules(), getInheritedModules()).immutableCopy();
+ }
+
+ private final class LocalDependencyChecker {
+ private final Set<Object> cycleChecker = new HashSet<>();
+
+ /**
+ * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with
+ * contributions declared within this component's modules or optional bindings with present
+ * values declared within this component's modules, or if any of its unscoped dependencies
+ * depend on such bindings.
+ *
+ * <p>We don't care about scoped dependencies because they will never depend on bindings from
+ * subcomponents.
+ *
+ * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty
+ */
+ boolean dependsOnLocalBindings(Key key) {
+ // Don't recur infinitely if there are valid cycles in the dependency graph.
+ // http://b/23032377
+ if (!cycleChecker.add(key)) {
+ return false;
+ }
+ return reentrantComputeIfAbsent(
+ keyDependsOnLocalBindingsCache, key, this::dependsOnLocalBindingsUncached);
+ }
+
+ private boolean dependsOnLocalBindingsUncached(Key key) {
+ checkArgument(
+ getPreviouslyResolvedBindings(key).isPresent(),
+ "no previously resolved bindings in %s for %s",
+ Resolver.this,
+ key);
+ ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings(key).get();
+ if (hasLocalMultibindingContributions(key)
+ || hasLocalOptionalBindingContribution(previouslyResolvedBindings)) {
+ return true;
+ }
+
+ for (Binding binding : previouslyResolvedBindings.bindings()) {
+ if (dependsOnLocalBindings(binding)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable}
+ * scope) and depends on multibindings with contributions declared within this component's
+ * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend
+ * on such local multibindings.
+ *
+ * <p>We don't care about non-reusable scoped dependencies because they will never depend on
+ * multibindings with contributions from subcomponents.
+ */
+ boolean dependsOnLocalBindings(Binding binding) {
+ if (!cycleChecker.add(binding)) {
+ return false;
+ }
+ return reentrantComputeIfAbsent(
+ bindingDependsOnLocalBindingsCache, binding, this::dependsOnLocalBindingsUncached);
+ }
+
+ private boolean dependsOnLocalBindingsUncached(Binding binding) {
+ if ((!binding.scope().isPresent() || binding.scope().get().isReusable())
+ // TODO(beder): Figure out what happens with production subcomponents.
+ && !binding.bindingType().equals(BindingType.PRODUCTION)) {
+ for (DependencyRequest dependency : binding.dependencies()) {
+ if (dependsOnLocalBindings(dependency.key())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if there is at least one multibinding contribution declared within
+ * this component's modules that matches the key.
+ */
+ private boolean hasLocalMultibindingContributions(Key requestKey) {
+ return keysMatchingRequest(requestKey)
+ .stream()
+ .anyMatch(key -> !getLocalExplicitMultibindings(key).isEmpty());
+ }
+
+ /**
+ * Returns {@code true} if there is a contribution in this component for an {@code
+ * Optional<Foo>} key that has not been contributed in a parent.
+ */
+ private boolean hasLocalOptionalBindingContribution(ResolvedBindings resolvedBindings) {
+ if (resolvedBindings
+ .contributionBindings()
+ .stream()
+ .map(ContributionBinding::kind)
+ .anyMatch(isEqual(OPTIONAL))) {
+ return !getLocalExplicitBindings(keyFactory.unwrapOptional(resolvedBindings.key()).get())
+ .isEmpty();
+ } else {
+ // If a parent contributes a @Provides Optional<Foo> binding and a child has a
+ // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for
+ // Foo on its own
+ return !getOptionalBindingDeclarations(resolvedBindings.key()).isEmpty();
+ }
+ }
+ }
+ }
+
+ /**
+ * A multimap of those {@code declarations} that are multibinding contribution declarations,
+ * indexed by the key of the set or map to which they contribute.
+ */
+ static <T extends BindingDeclaration>
+ ImmutableSetMultimap<Key, T> multibindingContributionsByMultibindingKey(
+ Iterable<T> declarations) {
+ ImmutableSetMultimap.Builder<Key, T> builder = ImmutableSetMultimap.builder();
+ for (T declaration : declarations) {
+ if (declaration.key().multibindingContributionIdentifier().isPresent()) {
+ builder.put(
+ declaration
+ .key()
+ .toBuilder()
+ .multibindingContributionIdentifier(Optional.empty())
+ .build(),
+ declaration);
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingGraphPlugins.java b/java/dagger/internal/codegen/BindingGraphPlugins.java
new file mode 100644
index 0000000..e2c3812
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraphPlugins.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.DaggerStreams.toImmutableSet;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.spi.BindingGraphPlugin;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+
+/** Initializes {@link BindingGraphPlugin}s. */
+final class BindingGraphPlugins {
+ private final ImmutableSet<BindingGraphPlugin> plugins;
+ private final Filer filer;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final Map<String, String> processingOptions;
+
+ @Inject
+ BindingGraphPlugins(
+ @Validation Set<BindingGraphPlugin> validationPlugins,
+ ImmutableSet<BindingGraphPlugin> externalPlugins,
+ Filer filer,
+ DaggerTypes types,
+ DaggerElements elements,
+ @ProcessingOptions Map<String, String> processingOptions) {
+ this.plugins = Sets.union(validationPlugins, externalPlugins).immutableCopy();
+ this.filer = filer;
+ this.types = types;
+ this.elements = elements;
+ this.processingOptions = processingOptions;
+ }
+
+ /** Returns {@link BindingGraphPlugin#supportedOptions()} from all the plugins. */
+ ImmutableSet<String> allSupportedOptions() {
+ return plugins.stream()
+ .flatMap(plugin -> plugin.supportedOptions().stream())
+ .collect(toImmutableSet());
+ }
+
+ /** Initializes the plugins. */
+ // TODO(ronshapiro): Should we validate the uniqueness of plugin names?
+ void initializePlugins() {
+ plugins.forEach(this::initializePlugin);
+ }
+
+ private void initializePlugin(BindingGraphPlugin plugin) {
+ plugin.initFiler(filer);
+ plugin.initTypes(types);
+ plugin.initElements(elements);
+ Set<String> supportedOptions = plugin.supportedOptions();
+ if (!supportedOptions.isEmpty()) {
+ plugin.initOptions(Maps.filterKeys(processingOptions, supportedOptions::contains));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingGraphStatisticsCollector.java b/java/dagger/internal/codegen/BindingGraphStatisticsCollector.java
new file mode 100644
index 0000000..129647f
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraphStatisticsCollector.java
@@ -0,0 +1,93 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.errorprone.util.ASTHelpers.getSymbol;
+import static dagger.internal.codegen.ComponentAnnotation.rootComponentAnnotation;
+
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.sun.source.tree.ClassTree;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.util.Context;
+import dagger.BindsInstance;
+import dagger.Component;
+import dagger.model.BindingGraph;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** A {@link BugChecker} that collects statistics derived from a {@link BindingGraph}. */
+public abstract class BindingGraphStatisticsCollector extends BugChecker
+ implements ClassTreeMatcher {
+ private BindingGraphConverter bindingGraphConverter;
+ private BindingGraphFactory bindingGraphFactory;
+ private ComponentDescriptorFactory componentDescriptorFactory;
+ private boolean isInjected;
+
+ @Singleton
+ @Component(modules = JavacPluginModule.class)
+ interface Injector {
+ void inject(BindingGraphStatisticsCollector collector);
+
+ @Component.Factory
+ interface Factory {
+ Injector create(@BindsInstance Context context);
+ }
+ }
+
+ // BugCheckers must have no-arg constructors, so we'll use method injection instead.
+ @Inject
+ void inject(
+ BindingGraphConverter bindingGraphConverter,
+ BindingGraphFactory bindingGraphFactory,
+ ComponentDescriptorFactory componentDescriptorFactory) {
+ this.bindingGraphConverter = bindingGraphConverter;
+ this.bindingGraphFactory = bindingGraphFactory;
+ this.componentDescriptorFactory = componentDescriptorFactory;
+ }
+
+ @Override
+ public final Description matchClass(ClassTree tree, VisitorState state) {
+ injectIfNecessary(state.context);
+
+ ClassSymbol symbol = getSymbol(tree);
+ rootComponentAnnotation(symbol)
+ .map(annotation -> createBindingGraph(symbol))
+ .ifPresent(graph -> visitBindingGraph(graph, state));
+
+ return Description.NO_MATCH;
+ }
+
+ private BindingGraph createBindingGraph(ClassSymbol component) {
+ return bindingGraphConverter.convert(
+ bindingGraphFactory.create(
+ componentDescriptorFactory.rootComponentDescriptor(component), false));
+ }
+
+ /** Visits a {@link BindingGraph} and emits stats to a {@link VisitorState}. */
+ protected abstract void visitBindingGraph(BindingGraph graph, VisitorState state);
+
+ private void injectIfNecessary(Context context) {
+ if (isInjected) {
+ return;
+ }
+ DaggerBindingGraphStatisticsCollector_Injector.factory().create(context).inject(this);
+ isInjected = true;
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingGraphValidationModule.java b/java/dagger/internal/codegen/BindingGraphValidationModule.java
new file mode 100644
index 0000000..63e1fa2
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraphValidationModule.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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 dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.IntoSet;
+import dagger.spi.BindingGraphPlugin;
+
+/** Binds the set of {@link BindingGraphPlugin}s used to implement Dagger validation. */
+@Module
+interface BindingGraphValidationModule {
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin dependencyCycle(DependencyCycleValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin dependsOnProductionExecutor(DependsOnProductionExecutorValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin duplicateBindings(DuplicateBindingsValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin incompatiblyScopedBindings(IncompatiblyScopedBindingsValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin injectBinding(InjectBindingValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin mapMultibinding(MapMultibindingValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin missingBinding(MissingBindingValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin nullableBinding(NullableBindingValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin provisionDependencyOnProducerBinding(
+ ProvisionDependencyOnProducerBindingValidator validation);
+
+ @Binds
+ @IntoSet
+ @Validation
+ BindingGraphPlugin subcomponentFactoryMethod(SubcomponentFactoryMethodValidator validation);
+}
diff --git a/java/dagger/internal/codegen/BindingGraphValidator.java b/java/dagger/internal/codegen/BindingGraphValidator.java
new file mode 100644
index 0000000..df17b15
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingGraphValidator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.DiagnosticReporterFactory.DiagnosticReporterImpl;
+import dagger.model.BindingGraph;
+import dagger.spi.BindingGraphPlugin;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Validates a {@link BindingGraph}. */
+@Singleton
+final class BindingGraphValidator {
+ private final ImmutableSet<BindingGraphPlugin> validationPlugins;
+ private final ImmutableSet<BindingGraphPlugin> externalPlugins;
+ private final DiagnosticReporterFactory diagnosticReporterFactory;
+
+ @Inject
+ BindingGraphValidator(
+ @Validation Set<BindingGraphPlugin> validationPlugins,
+ ImmutableSet<BindingGraphPlugin> externalPlugins,
+ DiagnosticReporterFactory diagnosticReporterFactory) {
+ this.validationPlugins = ImmutableSet.copyOf(validationPlugins);
+ this.externalPlugins = ImmutableSet.copyOf(externalPlugins);
+ this.diagnosticReporterFactory = checkNotNull(diagnosticReporterFactory);
+ }
+
+ /** Returns {@code true} if no errors are reported for {@code graph}. */
+ boolean isValid(BindingGraph graph) {
+ return isValid(validationPlugins, graph) && isValid(externalPlugins, graph);
+ }
+
+ private boolean isValid(ImmutableSet<BindingGraphPlugin> plugins, BindingGraph graph) {
+ boolean isValid = true;
+ for (BindingGraphPlugin plugin : plugins) {
+ DiagnosticReporterImpl reporter = diagnosticReporterFactory.reporter(graph, plugin);
+ plugin.visitGraph(graph, reporter);
+ if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
+ isValid = false;
+ }
+ }
+ return isValid;
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingMethodProcessingStep.java b/java/dagger/internal/codegen/BindingMethodProcessingStep.java
new file mode 100644
index 0000000..e6c4f8e
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingMethodProcessingStep.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+
+/** A step that validates all binding methods that were not validated while processing modules. */
+final class BindingMethodProcessingStep extends TypeCheckingProcessingStep<ExecutableElement> {
+
+ private final Messager messager;
+ private final AnyBindingMethodValidator anyBindingMethodValidator;
+
+ @Inject
+ BindingMethodProcessingStep(
+ Messager messager, AnyBindingMethodValidator anyBindingMethodValidator) {
+ super(MoreElements::asExecutable);
+ this.messager = messager;
+ this.anyBindingMethodValidator = anyBindingMethodValidator;
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotations() {
+ return anyBindingMethodValidator.methodAnnotations();
+ }
+
+ @Override
+ protected void process(
+ ExecutableElement method, ImmutableSet<Class<? extends Annotation>> annotations) {
+ checkArgument(
+ anyBindingMethodValidator.isBindingMethod(method),
+ "%s is not annotated with any of %s",
+ method,
+ annotations());
+ if (!anyBindingMethodValidator.wasAlreadyValidated(method)) {
+ anyBindingMethodValidator.validate(method).printMessagesTo(messager);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingMethodValidator.java b/java/dagger/internal/codegen/BindingMethodValidator.java
new file mode 100644
index 0000000..21c05cc
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingMethodValidator.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016 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 dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static java.util.stream.Collectors.joining;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.lang.annotation.Annotation;
+import java.util.Optional;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+/** A validator for methods that represent binding declarations. */
+abstract class BindingMethodValidator extends BindingElementValidator<ExecutableElement> {
+
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final DependencyRequestValidator dependencyRequestValidator;
+ private final Class<? extends Annotation> methodAnnotation;
+ private final ImmutableSet<? extends Class<? extends Annotation>> enclosingElementAnnotations;
+ private final Abstractness abstractness;
+ private final ExceptionSuperclass exceptionSuperclass;
+
+ /**
+ * Creates a validator object.
+ *
+ * @param methodAnnotation the annotation on a method that identifies it as a binding method
+ * @param enclosingElementAnnotation the method must be declared in a class or interface annotated
+ * with this annotation
+ */
+ protected BindingMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestValidator dependencyRequestValidator,
+ Class<? extends Annotation> methodAnnotation,
+ Class<? extends Annotation> enclosingElementAnnotation,
+ Abstractness abstractness,
+ ExceptionSuperclass exceptionSuperclass,
+ AllowsMultibindings allowsMultibindings,
+ AllowsScoping allowsScoping) {
+ this(
+ elements,
+ types,
+ methodAnnotation,
+ ImmutableSet.of(enclosingElementAnnotation),
+ dependencyRequestValidator,
+ abstractness,
+ exceptionSuperclass,
+ allowsMultibindings,
+ allowsScoping);
+ }
+
+ /**
+ * Creates a validator object.
+ *
+ * @param methodAnnotation the annotation on a method that identifies it as a binding method
+ * @param enclosingElementAnnotations the method must be declared in a class or interface
+ * annotated with one of these annotations
+ */
+ protected BindingMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ Class<? extends Annotation> methodAnnotation,
+ Iterable<? extends Class<? extends Annotation>> enclosingElementAnnotations,
+ DependencyRequestValidator dependencyRequestValidator,
+ Abstractness abstractness,
+ ExceptionSuperclass exceptionSuperclass,
+ AllowsMultibindings allowsMultibindings,
+ AllowsScoping allowsScoping) {
+ super(methodAnnotation, allowsMultibindings, allowsScoping);
+ this.elements = elements;
+ this.types = types;
+ this.methodAnnotation = methodAnnotation;
+ this.enclosingElementAnnotations = ImmutableSet.copyOf(enclosingElementAnnotations);
+ this.dependencyRequestValidator = dependencyRequestValidator;
+ this.abstractness = abstractness;
+ this.exceptionSuperclass = exceptionSuperclass;
+ }
+
+ /** The annotation that identifies binding methods validated by this object. */
+ final Class<? extends Annotation> methodAnnotation() {
+ return methodAnnotation;
+ }
+
+ /**
+ * Returns an error message of the form "@<i>annotation</i> methods <i>rule</i>", where
+ * <i>rule</i> comes from calling {@link String#format(String, Object...)} on {@code ruleFormat}
+ * and the other arguments.
+ */
+ @FormatMethod
+ protected final String bindingMethods(String ruleFormat, Object... args) {
+ return bindingElements(ruleFormat, args);
+ }
+
+ @Override
+ protected final String bindingElements() {
+ return String.format("@%s methods", methodAnnotation.getSimpleName());
+ }
+
+ @Override
+ protected final String bindingElementTypeVerb() {
+ return "return";
+ }
+
+ /** Abstract validator for individual binding method elements. */
+ protected abstract class MethodValidator extends ElementValidator {
+ protected MethodValidator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected final Optional<TypeMirror> bindingElementType() {
+ return Optional.of(element.getReturnType());
+ }
+
+ @Override
+ protected final void checkAdditionalProperties() {
+ checkEnclosingElement();
+ checkTypeParameters();
+ checkNotPrivate();
+ checkAbstractness();
+ checkThrows();
+ checkParameters();
+ checkAdditionalMethodProperties();
+ }
+
+ /** Checks additional properties of the binding method. */
+ protected void checkAdditionalMethodProperties() {}
+
+ /**
+ * Adds an error if the method is not declared in a class or interface annotated with one of the
+ * {@link #enclosingElementAnnotations}.
+ */
+ private void checkEnclosingElement() {
+ if (!isAnyAnnotationPresent(
+ element.getEnclosingElement(), enclosingElementAnnotations)) {
+ report.addError(
+ bindingMethods(
+ "can only be present within a @%s",
+ enclosingElementAnnotations.stream()
+ .map(Class::getSimpleName)
+ .collect(joining(" or @"))));
+ }
+ }
+
+ /** Adds an error if the method is generic. */
+ private void checkTypeParameters() {
+ if (!element.getTypeParameters().isEmpty()) {
+ report.addError(bindingMethods("may not have type parameters"));
+ }
+ }
+
+ /** Adds an error if the method is private. */
+ private void checkNotPrivate() {
+ if (element.getModifiers().contains(PRIVATE)) {
+ report.addError(bindingMethods("cannot be private"));
+ }
+ }
+
+ /** Adds an error if the method is abstract but must not be, or is not and must be. */
+ private void checkAbstractness() {
+ boolean isAbstract = element.getModifiers().contains(ABSTRACT);
+ switch (abstractness) {
+ case MUST_BE_ABSTRACT:
+ if (!isAbstract) {
+ report.addError(bindingMethods("must be abstract"));
+ }
+ break;
+
+ case MUST_BE_CONCRETE:
+ if (isAbstract) {
+ report.addError(bindingMethods("cannot be abstract"));
+ }
+ }
+ }
+
+ /**
+ * Adds an error if the method declares throws anything but an {@link Error} or an appropriate
+ * subtype of {@link Exception}.
+ */
+ private void checkThrows() {
+ exceptionSuperclass.checkThrows(BindingMethodValidator.this, element, report);
+ }
+
+ /** Adds errors for the method parameters. */
+ protected void checkParameters() {
+ for (VariableElement parameter : element.getParameters()) {
+ checkParameter(parameter);
+ }
+ }
+
+ /**
+ * Adds errors for a method parameter. This implementation reports an error if the parameter has
+ * more than one qualifier.
+ */
+ protected void checkParameter(VariableElement parameter) {
+ dependencyRequestValidator.validateDependencyRequest(report, parameter, parameter.asType());
+ }
+ }
+
+ /** An abstract/concrete restriction on methods. */
+ protected enum Abstractness {
+ MUST_BE_ABSTRACT,
+ MUST_BE_CONCRETE
+ }
+
+ /**
+ * The exception class that all {@code throws}-declared throwables must extend, other than {@link
+ * Error}.
+ */
+ protected enum ExceptionSuperclass {
+ /** Methods may not declare any throwable types. */
+ NO_EXCEPTIONS {
+ @Override
+ protected String errorMessage(BindingMethodValidator validator) {
+ return validator.bindingMethods("may not throw");
+ }
+
+ @Override
+ protected void checkThrows(
+ BindingMethodValidator validator,
+ ExecutableElement element,
+ ValidationReport.Builder<ExecutableElement> report) {
+ if (!element.getThrownTypes().isEmpty()) {
+ report.addError(validator.bindingMethods("may not throw"));
+ return;
+ }
+ }
+ },
+
+ /** Methods may throw checked or unchecked exceptions or errors. */
+ EXCEPTION(Exception.class) {
+ @Override
+ protected String errorMessage(BindingMethodValidator validator) {
+ return validator.bindingMethods(
+ "may only throw unchecked exceptions or exceptions subclassing Exception");
+ }
+ },
+
+ /** Methods may throw unchecked exceptions or errors. */
+ RUNTIME_EXCEPTION(RuntimeException.class) {
+ @Override
+ protected String errorMessage(BindingMethodValidator validator) {
+ return validator.bindingMethods("may only throw unchecked exceptions");
+ }
+ },
+ ;
+
+ private final Class<? extends Exception> superclass;
+
+ ExceptionSuperclass() {
+ this(null);
+ }
+
+ ExceptionSuperclass(Class<? extends Exception> superclass) {
+ this.superclass = superclass;
+ }
+
+ /**
+ * Adds an error if the method declares throws anything but an {@link Error} or an appropriate
+ * subtype of {@link Exception}.
+ *
+ * <p>This method is overridden in {@link #NO_EXCEPTIONS}.
+ */
+ protected void checkThrows(
+ BindingMethodValidator validator,
+ ExecutableElement element,
+ ValidationReport.Builder<ExecutableElement> report) {
+ TypeMirror exceptionSupertype = validator.elements.getTypeElement(superclass).asType();
+ TypeMirror errorType = validator.elements.getTypeElement(Error.class).asType();
+ for (TypeMirror thrownType : element.getThrownTypes()) {
+ if (!validator.types.isSubtype(thrownType, exceptionSupertype)
+ && !validator.types.isSubtype(thrownType, errorType)) {
+ report.addError(errorMessage(validator));
+ break;
+ }
+ }
+ }
+
+ protected abstract String errorMessage(BindingMethodValidator validator);
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingMethodValidatorsModule.java b/java/dagger/internal/codegen/BindingMethodValidatorsModule.java
new file mode 100644
index 0000000..28a272d
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingMethodValidatorsModule.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 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.collect.Maps.uniqueIndex;
+
+import com.google.common.collect.ImmutableMap;
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoSet;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+/**
+ * Binds each {@link BindingMethodValidator} into a map, keyed by {@link
+ * BindingMethodValidator#methodAnnotation()}.
+ */
+@Module
+interface BindingMethodValidatorsModule {
+ @Provides
+ static ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> indexValidators(
+ Set<BindingMethodValidator> validators) {
+ return uniqueIndex(validators, BindingMethodValidator::methodAnnotation);
+ }
+
+ @Binds
+ @IntoSet
+ BindingMethodValidator provides(ProvidesMethodValidator validator);
+
+ @Binds
+ @IntoSet
+ BindingMethodValidator produces(ProducesMethodValidator validator);
+
+ @Binds
+ @IntoSet
+ BindingMethodValidator binds(BindsMethodValidator validator);
+
+ @Binds
+ @IntoSet
+ BindingMethodValidator multibinds(MultibindsMethodValidator validator);
+
+ @Binds
+ @IntoSet
+ BindingMethodValidator bindsOptionalOf(BindsOptionalOfMethodValidator validator);
+}
diff --git a/java/dagger/internal/codegen/BindingNode.java b/java/dagger/internal/codegen/BindingNode.java
new file mode 100644
index 0000000..a7da092
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingNode.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.BindingType.PRODUCTION;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import dagger.BindsOptionalOf;
+import dagger.Module;
+import dagger.model.BindingKind;
+import dagger.model.ComponentPath;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.Scope;
+import dagger.multibindings.Multibinds;
+import java.util.Optional;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * An implementation of {@link dagger.model.Binding} that also exposes {@link BindingDeclaration}s
+ * associated with the binding.
+ */
+// TODO(dpb): Consider a supertype of dagger.model.Binding that dagger.internal.codegen.Binding
+// could also implement.
+@AutoValue
+abstract class BindingNode implements dagger.model.Binding {
+ static BindingNode create(
+ ComponentPath component,
+ Binding delegate,
+ ImmutableSet<MultibindingDeclaration> multibindingDeclarations,
+ ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations,
+ ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations,
+ BindingDeclarationFormatter bindingDeclarationFormatter) {
+ BindingNode node =
+ new AutoValue_BindingNode(
+ component,
+ delegate,
+ multibindingDeclarations,
+ optionalBindingDeclarations,
+ subcomponentDeclarations);
+ node.bindingDeclarationFormatter = checkNotNull(bindingDeclarationFormatter);
+ return node;
+ }
+
+ private BindingDeclarationFormatter bindingDeclarationFormatter;
+
+ abstract Binding delegate();
+
+ abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
+
+ abstract ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations();
+
+ abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
+
+ /**
+ * The {@link Element}s (other than the binding's {@link #bindingElement()}) that are associated
+ * with the binding.
+ *
+ * <ul>
+ * <li>{@linkplain BindsOptionalOf optional binding} declarations
+ * <li>{@linkplain Module#subcomponents() module subcomponent} declarations
+ * <li>{@linkplain Multibinds multibinding} declarations
+ * </ul>
+ */
+ final Iterable<BindingDeclaration> associatedDeclarations() {
+ return Iterables.concat(
+ multibindingDeclarations(), optionalBindingDeclarations(), subcomponentDeclarations());
+ }
+
+ @Override
+ public Key key() {
+ return delegate().key();
+ }
+
+ @Override
+ public ImmutableSet<DependencyRequest> dependencies() {
+ return delegate().dependencies();
+ }
+
+ @Override
+ public Optional<Element> bindingElement() {
+ return delegate().bindingElement();
+ }
+
+ @Override
+ public Optional<TypeElement> contributingModule() {
+ return delegate().contributingModule();
+ }
+
+ @Override
+ public boolean requiresModuleInstance() {
+ return delegate().requiresModuleInstance();
+ }
+
+ @Override
+ public Optional<Scope> scope() {
+ return delegate().scope();
+ }
+
+ @Override
+ public boolean isNullable() {
+ return delegate().isNullable();
+ }
+
+ @Override
+ public boolean isProduction() {
+ return delegate().bindingType().equals(PRODUCTION);
+ }
+
+ @Override
+ public BindingKind kind() {
+ return delegate().kind();
+ }
+
+ @Override
+ public final String toString() {
+ return bindingDeclarationFormatter.format(delegate());
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingRequest.java b/java/dagger/internal/codegen/BindingRequest.java
new file mode 100644
index 0000000..27067aa
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingRequest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.RequestKinds.requestType;
+
+import com.google.auto.value.AutoValue;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.serialization.BindingRequestProto;
+import dagger.internal.codegen.serialization.FrameworkTypeWrapper;
+import dagger.internal.codegen.serialization.RequestKindWrapper;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A request for a binding, which may be in the form of a request for a dependency to pass to a
+ * constructor or module method ({@link RequestKind}) or an internal request for a framework
+ * instance ({@link FrameworkType}).
+ */
+@AutoValue
+abstract class BindingRequest {
+ /** Creates a {@link BindingRequest} for the given {@link DependencyRequest}. */
+ static BindingRequest bindingRequest(DependencyRequest dependencyRequest) {
+ return bindingRequest(dependencyRequest.key(), dependencyRequest.kind());
+ }
+
+ /**
+ * Creates a {@link BindingRequest} for a normal dependency request for the given {@link Key} and
+ * {@link RequestKind}.
+ */
+ static BindingRequest bindingRequest(Key key, RequestKind requestKind) {
+ // When there's a request that has a 1:1 mapping to a FrameworkType, the request should be
+ // associated with that FrameworkType as well, because we want to ensure that if a request
+ // comes in for that as a dependency first and as a framework instance later, they resolve to
+ // the same binding expression.
+ // TODO(cgdecker): Instead of doing this, make ComponentBindingExpressions create a
+ // BindingExpression for the RequestKind that simply delegates to the BindingExpression for the
+ // FrameworkType. Then there are separate BindingExpressions, but we don't end up doing weird
+ // things like creating two fields when there should only be one.
+ return new AutoValue_BindingRequest(
+ key, Optional.of(requestKind), FrameworkType.forRequestKind(requestKind));
+ }
+
+ /**
+ * Creates a {@link BindingRequest} for a request for a framework instance for the given {@link
+ * Key} with the given {@link FrameworkType}.
+ */
+ static BindingRequest bindingRequest(Key key, FrameworkType frameworkType) {
+ return new AutoValue_BindingRequest(
+ key, frameworkType.requestKind(), Optional.of(frameworkType));
+ }
+
+ /** Creates a {@link BindingRequest} for the given {@link FrameworkDependency}. */
+ static BindingRequest bindingRequest(FrameworkDependency frameworkDependency) {
+ return bindingRequest(frameworkDependency.key(), frameworkDependency.frameworkType());
+ }
+
+ /** Returns the {@link Key} for the requested binding. */
+ abstract Key key();
+
+ /** Returns the request kind associated with this request, if any. */
+ abstract Optional<RequestKind> requestKind();
+
+ /** Returns the framework type associated with this request, if any. */
+ abstract Optional<FrameworkType> frameworkType();
+
+ /** Returns whether this request is of the given kind. */
+ final boolean isRequestKind(RequestKind requestKind) {
+ return requestKind.equals(requestKind().orElse(null));
+ }
+
+ final TypeMirror requestedType(TypeMirror contributedType, DaggerTypes types) {
+ if (requestKind().isPresent()) {
+ return requestType(requestKind().get(), contributedType, types);
+ }
+ return types.wrapType(contributedType, frameworkType().get().frameworkClass());
+ }
+
+ /** Returns a name that can be used for the kind of request this is. */
+ final String kindName() {
+ Object requestKindObject =
+ requestKind().isPresent()
+ ? requestKind().get()
+ : frameworkType().get().frameworkClass().getSimpleName();
+ return requestKindObject.toString();
+ }
+
+ /** Returns {@code true} if this request can be satisfied by a production binding. */
+ final boolean canBeSatisfiedByProductionBinding() {
+ if (requestKind().isPresent()) {
+ return RequestKinds.canBeSatisfiedByProductionBinding(requestKind().get());
+ }
+ return frameworkType().get().equals(FrameworkType.PRODUCER_NODE);
+ }
+
+ /** Creates a proto representation of this binding request. */
+ BindingRequestProto toProto() {
+ BindingRequestProto.Builder builder =
+ BindingRequestProto.newBuilder().setKey(KeyFactory.toProto(key()));
+ if (frameworkType().isPresent()) {
+ builder.setFrameworkType(
+ FrameworkTypeWrapper.FrameworkType.valueOf(frameworkType().get().name()));
+ } else {
+ builder.setRequestKind(RequestKindWrapper.RequestKind.valueOf(requestKind().get().name()));
+ }
+ return builder.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/BindingType.java b/java/dagger/internal/codegen/BindingType.java
new file mode 100644
index 0000000..37109c7
--- /dev/null
+++ b/java/dagger/internal/codegen/BindingType.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import dagger.MembersInjector;
+
+/** Whether a binding or declaration is for provision, production, or a {@link MembersInjector}. */
+enum BindingType {
+ /** A binding with this type is a {@link ProvisionBinding}. */
+ PROVISION,
+
+ /** A binding with this type is a {@link MembersInjectionBinding}. */
+ MEMBERS_INJECTION,
+
+ /** A binding with this type is a {@link ProductionBinding}. */
+ PRODUCTION,
+}
diff --git a/java/dagger/internal/codegen/BindsInstanceElementValidator.java b/java/dagger/internal/codegen/BindsInstanceElementValidator.java
new file mode 100644
index 0000000..9249c8e
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsInstanceElementValidator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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 dagger.BindsInstance;
+import javax.lang.model.element.Element;
+
+abstract class BindsInstanceElementValidator<E extends Element> extends BindingElementValidator<E> {
+ BindsInstanceElementValidator() {
+ super(BindsInstance.class, AllowsMultibindings.NO_MULTIBINDINGS, AllowsScoping.NO_SCOPING);
+ }
+
+ @Override
+ protected final String bindingElements() {
+ // Even though @BindsInstance may be placed on methods, the subject of errors is the
+ // parameter
+ return "@BindsInstance parameters";
+ }
+
+ @Override
+ protected final String bindingElementTypeVerb() {
+ return "be";
+ }
+}
diff --git a/java/dagger/internal/codegen/BindsInstanceMethodValidator.java b/java/dagger/internal/codegen/BindsInstanceMethodValidator.java
new file mode 100644
index 0000000..1a491c7
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsInstanceMethodValidator.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ComponentAnnotation.anyComponentAnnotation;
+import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+
+import com.google.auto.common.MoreElements;
+import java.util.List;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+final class BindsInstanceMethodValidator extends BindsInstanceElementValidator<ExecutableElement> {
+ @Inject
+ BindsInstanceMethodValidator() {}
+
+ @Override
+ protected ElementValidator elementValidator(ExecutableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends ElementValidator {
+ Validator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkAdditionalProperties() {
+ if (!element.getModifiers().contains(ABSTRACT)) {
+ report.addError("@BindsInstance methods must be abstract");
+ }
+ if (element.getParameters().size() != 1) {
+ report.addError(
+ "@BindsInstance methods should have exactly one parameter for the bound type");
+ }
+ TypeElement enclosingType = MoreElements.asType(element.getEnclosingElement());
+ moduleAnnotation(enclosingType)
+ .ifPresent(moduleAnnotation -> report.addError(didYouMeanBinds(moduleAnnotation)));
+ anyComponentAnnotation(enclosingType)
+ .ifPresent(
+ componentAnnotation ->
+ report.addError(
+ String.format(
+ "@BindsInstance methods should not be included in @%1$ss. "
+ + "Did you mean to put it in a @%1$s.Builder?",
+ componentAnnotation.simpleName())));
+ }
+
+ @Override
+ protected Optional<TypeMirror> bindingElementType() {
+ List<? extends VariableElement> parameters =
+ MoreElements.asExecutable(element).getParameters();
+ return parameters.size() == 1
+ ? Optional.of(getOnlyElement(parameters).asType())
+ : Optional.empty();
+ }
+ }
+
+ private static String didYouMeanBinds(ModuleAnnotation moduleAnnotation) {
+ return String.format(
+ "@BindsInstance methods should not be included in @%ss. Did you mean @Binds?",
+ moduleAnnotation.annotationClass().getSimpleName());
+ }
+}
diff --git a/java/dagger/internal/codegen/BindsInstanceParameterValidator.java b/java/dagger/internal/codegen/BindsInstanceParameterValidator.java
new file mode 100644
index 0000000..b2dc8d8
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsInstanceParameterValidator.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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 javax.lang.model.element.ElementKind.METHOD;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.TYPEVAR;
+
+import com.google.auto.common.MoreElements;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+final class BindsInstanceParameterValidator extends BindsInstanceElementValidator<VariableElement> {
+ @Inject
+ BindsInstanceParameterValidator() {}
+
+ @Override
+ protected ElementValidator elementValidator(VariableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends ElementValidator {
+ Validator(VariableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkAdditionalProperties() {
+ Element enclosing = element.getEnclosingElement();
+ if (!enclosing.getKind().equals(METHOD)) {
+ report.addError(
+ "@BindsInstance should only be applied to methods or parameters of methods");
+ return;
+ }
+
+ ExecutableElement method = MoreElements.asExecutable(enclosing);
+ if (!method.getModifiers().contains(ABSTRACT)) {
+ report.addError("@BindsInstance parameters may only be used in abstract methods");
+ }
+
+ TypeKind returnKind = method.getReturnType().getKind();
+ if (!(returnKind.equals(DECLARED) || returnKind.equals(TYPEVAR))) {
+ report.addError(
+ "@BindsInstance parameters may not be used in methods with a void, array or primitive "
+ + "return type");
+ }
+ }
+
+ @Override
+ protected Optional<TypeMirror> bindingElementType() {
+ return Optional.of(element.asType());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindsInstanceProcessingStep.java b/java/dagger/internal/codegen/BindsInstanceProcessingStep.java
new file mode 100644
index 0000000..4c222a9
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsInstanceProcessingStep.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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 com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import dagger.BindsInstance;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+
+/**
+ * Processing step that validates that the {@code BindsInstance} annotation is applied to the
+ * correct elements.
+ */
+final class BindsInstanceProcessingStep extends TypeCheckingProcessingStep<Element> {
+ private final BindsInstanceMethodValidator methodValidator;
+ private final BindsInstanceParameterValidator parameterValidator;
+ private final Messager messager;
+
+ @Inject
+ BindsInstanceProcessingStep(
+ BindsInstanceMethodValidator methodValidator,
+ BindsInstanceParameterValidator parameterValidator,
+ Messager messager) {
+ super(element -> element);
+ this.methodValidator = methodValidator;
+ this.parameterValidator = parameterValidator;
+ this.messager = messager;
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(BindsInstance.class);
+ }
+
+ @Override
+ protected void process(Element element, ImmutableSet<Class<? extends Annotation>> annotations) {
+ switch (element.getKind()) {
+ case PARAMETER:
+ parameterValidator.validate(MoreElements.asVariable(element)).printMessagesTo(messager);
+ break;
+ case METHOD:
+ methodValidator.validate(MoreElements.asExecutable(element)).printMessagesTo(messager);
+ break;
+ default:
+ throw new AssertionError(element);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindsMethodValidator.java b/java/dagger/internal/codegen/BindsMethodValidator.java
new file mode 100644
index 0000000..e198c3a
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsMethodValidator.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 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 dagger.internal.codegen.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
+import static dagger.internal.codegen.BindingElementValidator.AllowsScoping.ALLOWS_SCOPING;
+import static dagger.internal.codegen.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.BindingMethodValidator.ExceptionSuperclass.RUNTIME_EXCEPTION;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.Binds;
+import dagger.Module;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.producers.ProducerModule;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+/** A validator for {@link Binds} methods. */
+final class BindsMethodValidator extends BindingMethodValidator {
+ private final DaggerTypes types;
+ private final BindsTypeChecker bindsTypeChecker;
+
+ @Inject
+ BindsMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestValidator dependencyRequestValidator) {
+ super(
+ elements,
+ types,
+ Binds.class,
+ ImmutableSet.of(Module.class, ProducerModule.class),
+ dependencyRequestValidator,
+ MUST_BE_ABSTRACT,
+ RUNTIME_EXCEPTION,
+ ALLOWS_MULTIBINDINGS,
+ ALLOWS_SCOPING);
+ this.types = types;
+ this.bindsTypeChecker = new BindsTypeChecker(types, elements);
+ }
+
+ @Override
+ protected ElementValidator elementValidator(ExecutableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends MethodValidator {
+ Validator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkParameters() {
+ if (element.getParameters().size() != 1) {
+ report.addError(
+ bindingMethods(
+ "must have exactly one parameter, whose type is assignable to the return type"));
+ } else {
+ super.checkParameters();
+ }
+ }
+
+ @Override
+ protected void checkParameter(VariableElement parameter) {
+ super.checkParameter(parameter);
+ TypeMirror leftHandSide = boxIfNecessary(element.getReturnType());
+ TypeMirror rightHandSide = parameter.asType();
+ ContributionType contributionType = ContributionType.fromBindingElement(element);
+ if (contributionType.equals(ContributionType.SET_VALUES) && !SetType.isSet(leftHandSide)) {
+ report.addError(
+ "@Binds @ElementsIntoSet methods must return a Set and take a Set parameter");
+ }
+
+ if (!bindsTypeChecker.isAssignable(rightHandSide, leftHandSide, contributionType)) {
+ // TODO(ronshapiro): clarify this error message for @ElementsIntoSet cases, where the
+ // right-hand-side might not be assignable to the left-hand-side, but still compatible with
+ // Set.addAll(Collection<? extends E>)
+ report.addError("@Binds methods' parameter type must be assignable to the return type");
+ }
+ }
+
+ private TypeMirror boxIfNecessary(TypeMirror maybePrimitive) {
+ if (maybePrimitive.getKind().isPrimitive()) {
+ return types.boxedClass(MoreTypes.asPrimitiveType(maybePrimitive)).asType();
+ }
+ return maybePrimitive;
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindsOptionalOfMethodValidator.java b/java/dagger/internal/codegen/BindsOptionalOfMethodValidator.java
new file mode 100644
index 0000000..e1c9d73
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsOptionalOfMethodValidator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 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 dagger.internal.codegen.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS;
+import static dagger.internal.codegen.BindingElementValidator.AllowsScoping.NO_SCOPING;
+import static dagger.internal.codegen.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.InjectionAnnotations.injectedConstructors;
+import static dagger.internal.codegen.Keys.isValidImplicitProvisionKey;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.BindsOptionalOf;
+import dagger.Module;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.producers.ProducerModule;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeMirror;
+
+/** A validator for {@link BindsOptionalOf} methods. */
+final class BindsOptionalOfMethodValidator extends BindingMethodValidator {
+
+ private final DaggerTypes types;
+
+ @Inject
+ BindsOptionalOfMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestValidator dependencyRequestValidator) {
+ super(
+ elements,
+ types,
+ BindsOptionalOf.class,
+ ImmutableSet.of(Module.class, ProducerModule.class),
+ dependencyRequestValidator,
+ MUST_BE_ABSTRACT,
+ NO_EXCEPTIONS,
+ NO_MULTIBINDINGS,
+ NO_SCOPING);
+ this.types = types;
+ }
+
+ @Override
+ protected ElementValidator elementValidator(ExecutableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends MethodValidator {
+ Validator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkKeyType(TypeMirror keyType) {
+ super.checkKeyType(keyType);
+ if (isValidImplicitProvisionKey(
+ getQualifiers(element).stream().findFirst(), keyType, types)
+ && !injectedConstructors(MoreElements.asType(MoreTypes.asDeclared(keyType).asElement()))
+ .isEmpty()) {
+ report.addError(
+ "@BindsOptionalOf methods cannot return unqualified types that have an @Inject-"
+ + "annotated constructor because those are always present");
+ }
+ }
+
+ @Override
+ protected void checkParameters() {
+ if (!element.getParameters().isEmpty()) {
+ report.addError("@BindsOptionalOf methods cannot have parameters");
+ }
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/BindsTypeChecker.java b/java/dagger/internal/codegen/BindsTypeChecker.java
new file mode 100644
index 0000000..acecc9e
--- /dev/null
+++ b/java/dagger/internal/codegen/BindsTypeChecker.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 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.collect.Iterables.getOnlyElement;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Checks the assignability of one type to another, given a {@link ContributionType} context. This
+ * is used by {@link BindsMethodValidator} to validate that the right-hand-side of a {@link
+ * dagger.Binds} method is valid, as well as in {@link DelegateBindingExpression} when the
+ * right-hand-side in generated code might be an erased type due to accessibility.
+ */
+final class BindsTypeChecker {
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ @Inject
+ BindsTypeChecker(DaggerTypes types, DaggerElements elements) {
+ this.types = types;
+ this.elements = elements;
+ }
+
+ /**
+ * Checks the assignability of {@code rightHandSide} to {@code leftHandSide} given a {@link
+ * ContributionType} context.
+ */
+ boolean isAssignable(
+ TypeMirror rightHandSide, TypeMirror leftHandSide, ContributionType contributionType) {
+ return types.isAssignable(rightHandSide, desiredAssignableType(leftHandSide, contributionType));
+ }
+
+ private TypeMirror desiredAssignableType(
+ TypeMirror leftHandSide, ContributionType contributionType) {
+ switch (contributionType) {
+ case UNIQUE:
+ return leftHandSide;
+ case SET:
+ DeclaredType parameterizedSetType = types.getDeclaredType(setElement(), leftHandSide);
+ return methodParameterType(parameterizedSetType, "add");
+ case SET_VALUES:
+ return methodParameterType(MoreTypes.asDeclared(leftHandSide), "addAll");
+ case MAP:
+ DeclaredType parameterizedMapType =
+ types.getDeclaredType(mapElement(), unboundedWildcard(), leftHandSide);
+ return methodParameterTypes(parameterizedMapType, "put").get(1);
+ }
+ throw new AssertionError("Unknown contribution type: " + contributionType);
+ }
+
+ private ImmutableList<TypeMirror> methodParameterTypes(DeclaredType type, String methodName) {
+ ImmutableList.Builder<ExecutableElement> methodsForName = ImmutableList.builder();
+ for (ExecutableElement method :
+ // type.asElement().getEnclosedElements() is not used because some non-standard JDKs (e.g.
+ // J2CL) don't redefine Set.add() (whose only purpose of being redefined in the standard JDK
+ // is documentation, and J2CL's implementation doesn't declare docs for JDK types).
+ // MoreElements.getLocalAndInheritedMethods ensures that the method will always be present.
+ MoreElements.getLocalAndInheritedMethods(MoreTypes.asTypeElement(type), types, elements)) {
+ if (method.getSimpleName().contentEquals(methodName)) {
+ methodsForName.add(method);
+ }
+ }
+ ExecutableElement method = getOnlyElement(methodsForName.build());
+ return ImmutableList.copyOf(
+ MoreTypes.asExecutable(types.asMemberOf(type, method)).getParameterTypes());
+ }
+
+ private TypeMirror methodParameterType(DeclaredType type, String methodName) {
+ return getOnlyElement(methodParameterTypes(type, methodName));
+ }
+
+ private TypeElement setElement() {
+ return elements.getTypeElement(Set.class);
+ }
+
+ private TypeElement mapElement() {
+ return elements.getTypeElement(Map.class);
+ }
+
+ private TypeMirror unboundedWildcard() {
+ return types.getWildcardType(null, null);
+ }
+}
diff --git a/java/dagger/internal/codegen/ChildFactoryMethodEdgeImpl.java b/java/dagger/internal/codegen/ChildFactoryMethodEdgeImpl.java
new file mode 100644
index 0000000..a5e0219
--- /dev/null
+++ b/java/dagger/internal/codegen/ChildFactoryMethodEdgeImpl.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.ElementFormatter.elementToString;
+
+import dagger.model.BindingGraph.ChildFactoryMethodEdge;
+import javax.lang.model.element.ExecutableElement;
+
+/** An implementation of {@link ChildFactoryMethodEdge}. */
+final class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
+
+ private final ExecutableElement factoryMethod;
+
+ ChildFactoryMethodEdgeImpl(ExecutableElement factoryMethod) {
+ this.factoryMethod = factoryMethod;
+ }
+
+ @Override
+ public ExecutableElement factoryMethod() {
+ return factoryMethod;
+ }
+
+ @Override
+ public String toString() {
+ return elementToString(factoryMethod);
+ }
+}
diff --git a/java/dagger/internal/codegen/ClearableCache.java b/java/dagger/internal/codegen/ClearableCache.java
new file mode 100644
index 0000000..66ce3ef
--- /dev/null
+++ b/java/dagger/internal/codegen/ClearableCache.java
@@ -0,0 +1,23 @@
+/*
+ * 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.internal.codegen;
+
+/** A cache of objects that can be cleared. */
+interface ClearableCache {
+ /** Releases cached references. */
+ void clearCache();
+}
diff --git a/java/dagger/internal/codegen/CompilerOptions.java b/java/dagger/internal/codegen/CompilerOptions.java
new file mode 100644
index 0000000..bc3cbf8
--- /dev/null
+++ b/java/dagger/internal/codegen/CompilerOptions.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2016 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 com.squareup.javapoet.AnnotationSpec;
+import dagger.internal.GenerationOptions;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+/** A collection of options that dictate how the compiler will run. */
+abstract class CompilerOptions {
+ abstract boolean usesProducers();
+
+ /**
+ * Returns true if the fast initialization flag, {@code fastInit}, is enabled.
+ *
+ * <p>If enabled, the generated code will attempt to optimize for fast component initialization.
+ * This is done by reducing the number of factory classes loaded during initialization and the
+ * number of eagerly initialized fields at the cost of potential memory leaks and higher
+ * per-provision instantiation time.
+ */
+ abstract boolean fastInit();
+
+ abstract boolean formatGeneratedSource();
+
+ abstract boolean writeProducerNameInToken();
+
+ abstract Diagnostic.Kind nullableValidationKind();
+
+ final boolean doCheckForNulls() {
+ return nullableValidationKind().equals(Diagnostic.Kind.ERROR);
+ }
+
+ abstract Diagnostic.Kind privateMemberValidationKind();
+
+ abstract Diagnostic.Kind staticMemberValidationKind();
+
+ /**
+ * If {@code true}, Dagger will generate factories and components even if some members-injected
+ * types have {@code private} or {@code static} {@code @Inject}-annotated members.
+ *
+ * <p>This should only ever be enabled by the TCK tests. Disabling this validation could lead to
+ * generating code that does not compile.
+ */
+ abstract boolean ignorePrivateAndStaticInjectionForComponent();
+
+ abstract ValidationType scopeCycleValidationType();
+
+ abstract boolean warnIfInjectionFactoryNotGeneratedUpstream();
+
+ abstract boolean headerCompilation();
+
+ abstract boolean aheadOfTimeSubcomponents();
+
+ /**
+ * Enables a testing configuration where all superclass {@link ComponentImplementation}s are
+ * derived from their serialized forms.
+ */
+ abstract boolean forceUseSerializedComponentImplementations();
+
+ /**
+ * If {@code true}, in {@link #aheadOfTimeSubcomponents()} mode, Dagger will emit metadata
+ * annotations to deserialize aspects of the {@link ComponentImplementation}.
+ *
+ * This should only be disabled in compile-testing tests that want to ignore the annotations when
+ * asserting on generated source.
+ */
+ abstract boolean emitModifiableMetadataAnnotations();
+
+ abstract boolean useGradleIncrementalProcessing();
+
+ /**
+ * Returns the validation that should be done for the full binding graph for the element.
+ *
+ * @throws IllegalArgumentException if {@code element} is not a module or (sub)component
+ */
+ abstract ValidationType fullBindingGraphValidationType(TypeElement element);
+
+ abstract Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind();
+
+ abstract ValidationType explicitBindingConflictsWithInjectValidationType();
+
+ /**
+ * Creates a new {@link CompilerOptions} from the serialized {@link GenerationOptions} of a base
+ * component implementation.
+ */
+ final CompilerOptions withGenerationOptions(GenerationOptions generationOptions) {
+ return new ForwardingCompilerOptions(this) {
+ @Override
+ public boolean fastInit() {
+ return generationOptions.fastInit();
+ }
+ };
+ }
+
+ /**
+ * Returns a {@link GenerationOptions} annotation that serializes any options for this compilation
+ * that should be reused in future compilations.
+ */
+ final AnnotationSpec toGenerationOptionsAnnotation() {
+ return AnnotationSpec.builder(GenerationOptions.class)
+ .addMember("fastInit", "$L", fastInit())
+ .build();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentAnnotation.java b/java/dagger/internal/codegen/ComponentAnnotation.java
new file mode 100644
index 0000000..a8f2ece
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentAnnotation.java
@@ -0,0 +1,323 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreTypes.asTypeElements;
+import static com.google.auto.common.MoreTypes.isTypeOf;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
+
+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.ImmutableSet;
+import dagger.Component;
+import dagger.Subcomponent;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionComponent;
+import dagger.producers.ProductionSubcomponent;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A {@code @Component}, {@code @Subcomponent}, {@code @ProductionComponent}, or
+ * {@code @ProductionSubcomponent} annotation, or a {@code @Module} or {@code @ProducerModule}
+ * annotation that is being treated as a component annotation when validating full binding graphs
+ * for modules.
+ */
+abstract class ComponentAnnotation {
+ /** The root component annotation types. */
+ private static final ImmutableSet<Class<? extends Annotation>> ROOT_COMPONENT_ANNOTATIONS =
+ ImmutableSet.of(Component.class, ProductionComponent.class);
+
+ /** The subcomponent annotation types. */
+ private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_ANNOTATIONS =
+ ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
+
+ /** All component annotation types. */
+ private static final ImmutableSet<Class<? extends Annotation>> ALL_COMPONENT_ANNOTATIONS =
+ ImmutableSet.<Class<? extends Annotation>>builder()
+ .addAll(ROOT_COMPONENT_ANNOTATIONS)
+ .addAll(SUBCOMPONENT_ANNOTATIONS)
+ .build();
+
+ /** The annotation itself. */
+ abstract AnnotationMirror annotation();
+
+ /** The simple name of the annotation type. */
+ String simpleName() {
+ return MoreAnnotationMirrors.simpleName(annotation()).toString();
+ }
+
+ /**
+ * Returns {@code true} if the annotation is a {@code @Subcomponent} or
+ * {@code @ProductionSubcomponent}.
+ */
+ abstract boolean isSubcomponent();
+
+ /**
+ * Returns {@code true} if the annotation is a {@code @ProductionComponent},
+ * {@code @ProductionSubcomponent}, or {@code @ProducerModule}.
+ */
+ abstract boolean isProduction();
+
+ /**
+ * Returns {@code true} if the annotation is a real component annotation and not a module
+ * annotation.
+ */
+ abstract boolean isRealComponent();
+
+ /** The values listed as {@code dependencies}. */
+ abstract ImmutableList<AnnotationValue> dependencyValues();
+
+ /** The types listed as {@code dependencies}. */
+ ImmutableList<TypeMirror> dependencyTypes() {
+ return dependencyValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
+ }
+
+ /**
+ * The types listed as {@code dependencies}.
+ *
+ * @throws IllegalArgumentException if any of {@link #dependencyTypes()} are error types
+ */
+ ImmutableList<TypeElement> dependencies() {
+ return asTypeElements(dependencyTypes()).asList();
+ }
+
+ /** The values listed as {@code modules}. */
+ abstract ImmutableList<AnnotationValue> moduleValues();
+
+ /** The types listed as {@code modules}. */
+ ImmutableList<TypeMirror> moduleTypes() {
+ return moduleValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
+ }
+
+ /**
+ * The types listed as {@code modules}.
+ *
+ * @throws IllegalArgumentException if any of {@link #moduleTypes()} are error types
+ */
+ ImmutableSet<TypeElement> modules() {
+ return asTypeElements(moduleTypes());
+ }
+
+ protected final ImmutableList<AnnotationValue> getAnnotationValues(String parameterName) {
+ return asAnnotationValues(getAnnotationValue(annotation(), parameterName));
+ }
+
+ /**
+ * Returns an object representing a root component annotation, not a subcomponent annotation, if
+ * one is present on {@code typeElement}.
+ */
+ static Optional<ComponentAnnotation> rootComponentAnnotation(TypeElement typeElement) {
+ return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS);
+ }
+
+ /**
+ * Returns an object representing a subcomponent annotation, if one is present on {@code
+ * typeElement}.
+ */
+ static Optional<ComponentAnnotation> subcomponentAnnotation(TypeElement typeElement) {
+ return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS);
+ }
+
+ /**
+ * Returns an object representing a root component or subcomponent annotation, if one is present
+ * on {@code typeElement}.
+ */
+ static Optional<ComponentAnnotation> anyComponentAnnotation(TypeElement typeElement) {
+ return anyComponentAnnotation(typeElement, ALL_COMPONENT_ANNOTATIONS);
+ }
+
+ private static Optional<ComponentAnnotation> anyComponentAnnotation(
+ TypeElement typeElement, Collection<Class<? extends Annotation>> annotations) {
+ return getAnyAnnotation(typeElement, annotations).map(ComponentAnnotation::componentAnnotation);
+ }
+
+ /** Returns {@code true} if the argument is a component annotation. */
+ static boolean isComponentAnnotation(AnnotationMirror annotation) {
+ return ALL_COMPONENT_ANNOTATIONS.stream()
+ .anyMatch(annotationClass -> isTypeOf(annotationClass, annotation.getAnnotationType()));
+ }
+
+ /** Creates an object representing a component or subcomponent annotation. */
+ static ComponentAnnotation componentAnnotation(AnnotationMirror annotation) {
+ RealComponentAnnotation.Builder annotationBuilder =
+ RealComponentAnnotation.builder().annotation(annotation);
+
+ if (isTypeOf(Component.class, annotation.getAnnotationType())) {
+ return annotationBuilder.isProduction(false).isSubcomponent(false).build();
+ }
+ if (isTypeOf(Subcomponent.class, annotation.getAnnotationType())) {
+ return annotationBuilder.isProduction(false).isSubcomponent(true).build();
+ }
+ if (isTypeOf(ProductionComponent.class, annotation.getAnnotationType())) {
+ return annotationBuilder.isProduction(true).isSubcomponent(false).build();
+ }
+ if (isTypeOf(ProductionSubcomponent.class, annotation.getAnnotationType())) {
+ return annotationBuilder.isProduction(true).isSubcomponent(true).build();
+ }
+ throw new IllegalArgumentException(
+ annotation
+ + " must be a Component, Subcomponent, ProductionComponent, "
+ + "or ProductionSubcomponent annotation");
+ }
+
+ /** Creates a fictional component annotation representing a module. */
+ static ComponentAnnotation fromModuleAnnotation(ModuleAnnotation moduleAnnotation) {
+ return new AutoValue_ComponentAnnotation_FictionalComponentAnnotation(moduleAnnotation);
+ }
+
+ /** The root component annotation types. */
+ static ImmutableSet<Class<? extends Annotation>> rootComponentAnnotations() {
+ return ROOT_COMPONENT_ANNOTATIONS;
+ }
+
+ /** The subcomponent annotation types. */
+ static ImmutableSet<Class<? extends Annotation>> subcomponentAnnotations() {
+ return SUBCOMPONENT_ANNOTATIONS;
+ }
+
+ /** All component annotation types. */
+ static ImmutableSet<Class<? extends Annotation>> allComponentAnnotations() {
+ return ALL_COMPONENT_ANNOTATIONS;
+ }
+
+ /**
+ * An actual component annotation.
+ *
+ * @see FictionalComponentAnnotation
+ */
+ @AutoValue
+ abstract static class RealComponentAnnotation extends ComponentAnnotation {
+
+ @Override
+ @Memoized
+ ImmutableList<AnnotationValue> dependencyValues() {
+ return isSubcomponent() ? ImmutableList.of() : getAnnotationValues("dependencies");
+ }
+
+ @Override
+ @Memoized
+ ImmutableList<TypeMirror> dependencyTypes() {
+ return super.dependencyTypes();
+ }
+
+ @Override
+ @Memoized
+ ImmutableList<TypeElement> dependencies() {
+ return super.dependencies();
+ }
+
+ @Override
+ boolean isRealComponent() {
+ return true;
+ }
+
+ @Override
+ @Memoized
+ ImmutableList<AnnotationValue> moduleValues() {
+ return getAnnotationValues("modules");
+ }
+
+ @Override
+ @Memoized
+ ImmutableList<TypeMirror> moduleTypes() {
+ return super.moduleTypes();
+ }
+
+ @Override
+ @Memoized
+ ImmutableSet<TypeElement> modules() {
+ return super.modules();
+ }
+
+ static Builder builder() {
+ return new AutoValue_ComponentAnnotation_RealComponentAnnotation.Builder();
+ }
+
+ @AutoValue.Builder
+ interface Builder {
+ Builder annotation(AnnotationMirror annotation);
+
+ Builder isSubcomponent(boolean isSubcomponent);
+
+ Builder isProduction(boolean isProduction);
+
+ RealComponentAnnotation build();
+ }
+ }
+
+ /**
+ * A fictional component annotation used to represent modules or other collections of bindings as
+ * a component.
+ */
+ @AutoValue
+ abstract static class FictionalComponentAnnotation extends ComponentAnnotation {
+
+ @Override
+ AnnotationMirror annotation() {
+ return moduleAnnotation().annotation();
+ }
+
+ @Override
+ boolean isSubcomponent() {
+ return false;
+ }
+
+ @Override
+ boolean isProduction() {
+ return moduleAnnotation().annotationClass().equals(ProducerModule.class);
+ }
+
+ @Override
+ boolean isRealComponent() {
+ return false;
+ }
+
+ @Override
+ ImmutableList<AnnotationValue> dependencyValues() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ ImmutableList<AnnotationValue> moduleValues() {
+ return moduleAnnotation().includesAsAnnotationValues();
+ }
+
+ @Override
+ @Memoized
+ ImmutableList<TypeMirror> moduleTypes() {
+ return super.moduleTypes();
+ }
+
+ @Override
+ @Memoized
+ ImmutableSet<TypeElement> modules() {
+ return super.modules();
+ }
+
+ abstract ModuleAnnotation moduleAnnotation();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentBindingExpressions.java b/java/dagger/internal/codegen/ComponentBindingExpressions.java
new file mode 100644
index 0000000..37cf1e8
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentBindingExpressions.java
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION;
+import static dagger.internal.codegen.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope;
+import static dagger.internal.codegen.MemberSelect.staticFactoryCreation;
+import static dagger.internal.codegen.RequestKinds.isDerivedFromProvider;
+import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
+import static dagger.internal.codegen.javapoet.TypeNames.SINGLE_CHECK;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.model.BindingKind.DELEGATE;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.model.BindingKind.MULTIBOUND_SET;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.MethodBindingExpression.MethodImplementationStrategy;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.RequestKind;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.type.TypeMirror;
+
+/** A central repository of code expressions used to access any binding available to a component. */
+@PerComponentImplementation
+final class ComponentBindingExpressions {
+ // TODO(dpb,ronshapiro): refactor this and ComponentRequirementExpressions into a
+ // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
+ // parents? If so, maybe make BindingExpression.Factory create it.
+
+ private final Optional<ComponentBindingExpressions> parent;
+ private final BindingGraph graph;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final OptionalFactories optionalFactories;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final SourceVersion sourceVersion;
+ private final CompilerOptions compilerOptions;
+ private final MembersInjectionMethods membersInjectionMethods;
+ private final InnerSwitchingProviders innerSwitchingProviders;
+ private final ModifiableBindingExpressions modifiableBindingExpressions;
+ private final Map<BindingRequest, BindingExpression> expressions = new HashMap<>();
+
+ @Inject
+ ComponentBindingExpressions(
+ @ParentComponent Optional<ComponentBindingExpressions> parent,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ OptionalFactories optionalFactories,
+ DaggerTypes types,
+ DaggerElements elements,
+ SourceVersion sourceVersion,
+ @GenerationCompilerOptions CompilerOptions compilerOptions) {
+ this.parent = parent;
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
+ this.optionalFactories = checkNotNull(optionalFactories);
+ this.types = checkNotNull(types);
+ this.elements = checkNotNull(elements);
+ this.sourceVersion = checkNotNull(sourceVersion);
+ this.compilerOptions = checkNotNull(compilerOptions);
+ this.membersInjectionMethods =
+ new MembersInjectionMethods(componentImplementation, this, graph, elements, types);
+ this.innerSwitchingProviders =
+ new InnerSwitchingProviders(componentImplementation, this, types);
+ this.modifiableBindingExpressions =
+ new ModifiableBindingExpressions(
+ parent.map(cbe -> cbe.modifiableBindingExpressions),
+ this,
+ graph,
+ componentImplementation,
+ compilerOptions,
+ types);
+ }
+
+ /* Returns the {@link ModifiableBindingExpressions} for this component. */
+ ModifiableBindingExpressions modifiableBindingExpressions() {
+ return modifiableBindingExpressions;
+ }
+
+ /**
+ * Returns an expression that evaluates to the value of a binding request for a binding owned by
+ * this component or an ancestor.
+ *
+ * @param requestingClass the class that will contain the expression
+ * @throws IllegalStateException if there is no binding expression that satisfies the request
+ */
+ Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) {
+ return getBindingExpression(request).getDependencyExpression(requestingClass);
+ }
+
+ /**
+ * Equivalent to {@link #getDependencyExpression(BindingRequest, ClassName)} that is used only
+ * when the request is for implementation of a component method.
+ *
+ * @throws IllegalStateException if there is no binding expression that satisfies the request
+ */
+ Expression getDependencyExpressionForComponentMethod(
+ BindingRequest request,
+ ComponentMethodDescriptor componentMethod,
+ ComponentImplementation componentImplementation) {
+ return getBindingExpression(request)
+ .getDependencyExpressionForComponentMethod(componentMethod, componentImplementation);
+ }
+
+ /**
+ * Returns the {@link CodeBlock} for the method arguments used with the factory {@code create()}
+ * method for the given {@link ContributionBinding binding}.
+ */
+ CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) {
+ return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding));
+ }
+
+ private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) {
+ ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
+
+ if (binding.requiresModuleInstance()) {
+ arguments.add(
+ componentRequirementExpressions.getExpressionDuringInitialization(
+ ComponentRequirement.forModule(binding.contributingModule().get().asType()),
+ componentImplementation.name()));
+ }
+
+ binding.frameworkDependencies().stream()
+ .map(BindingRequest::bindingRequest)
+ .map(request -> getDependencyExpression(request, componentImplementation.name()))
+ .map(Expression::codeBlock)
+ .forEach(arguments::add);
+
+ return arguments.build();
+ }
+
+ /**
+ * Returns an expression that evaluates to the value of a dependency request, for passing to a
+ * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
+ *
+ * <p>If the method is a generated static {@link InjectionMethods injection method}, each
+ * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
+ * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
+ *
+ * @param requestingClass the class that will contain the expression
+ */
+ Expression getDependencyArgumentExpression(
+ DependencyRequest dependencyRequest, ClassName requestingClass) {
+
+ TypeMirror dependencyType = dependencyRequest.key().type();
+ BindingRequest bindingRequest = bindingRequest(dependencyRequest);
+ Expression dependencyExpression = getDependencyExpression(bindingRequest, requestingClass);
+
+ if (compilerOptions.aheadOfTimeSubcomponents()) {
+ TypeMirror requestedType =
+ bindingRequest.requestedType(dependencyRequest.key().type(), types);
+ // If dependencyExpression.type() has been erased to it's publicly accessible type in AOT,
+ // we must sometimes cast the expression so that it is usable in the current component. To do
+ // so, we check that without the cast the assignment would fail, that argument to this proxy
+ // method erased the type, and that the raw type of the requested type is actually accessible
+ // in the current class so that the cast is valid.
+ if (!types.isAssignable(dependencyExpression.type(), requestedType)
+ && !isRawTypePubliclyAccessible(requestedType)
+ && isRawTypeAccessible(requestedType, requestingClass.packageName())) {
+ return dependencyExpression.castTo(types.erasure(requestedType));
+ }
+ }
+
+ if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
+ && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
+ && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
+ return dependencyExpression.castTo(types.erasure(dependencyType));
+ }
+
+ return dependencyExpression;
+ }
+
+ /** Returns the implementation of a component method. */
+ MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
+ checkArgument(componentMethod.dependencyRequest().isPresent());
+ BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
+ MethodSpec.Builder method =
+ MethodSpec.overriding(
+ componentMethod.methodElement(),
+ MoreTypes.asDeclared(graph.componentTypeElement().asType()),
+ types);
+ // Even though this is not used if the method is abstract, we need to invoke the binding
+ // expression in order for the side of effect of the method being added to the
+ // ComponentImplementation
+ CodeBlock methodBody =
+ getBindingExpression(request)
+ .getComponentMethodImplementation(componentMethod, componentImplementation);
+ if (!componentImplementation.superclassImplementation().isPresent()
+ && !modifiableBindingExpressions
+ .getModifiableBindingType(request)
+ .hasBaseClassImplementation()
+ && !componentImplementation.getModifiableBindingMethod(request).isPresent()) {
+ return method.addModifiers(ABSTRACT).build();
+ }
+ return method.addCode(methodBody).build();
+ }
+
+ /** Returns the {@link BindingExpression} for the given {@link BindingRequest}. */
+ BindingExpression getBindingExpression(BindingRequest request) {
+ if (expressions.containsKey(request)) {
+ return expressions.get(request);
+ }
+ Optional<BindingExpression> expression =
+ modifiableBindingExpressions.maybeCreateModifiableBindingExpression(request);
+ if (!expression.isPresent()) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ if (resolvedBindings != null
+ && !resolvedBindings.bindingsOwnedBy(graph.componentDescriptor()).isEmpty()) {
+ expression = Optional.of(createBindingExpression(resolvedBindings, request));
+ }
+ }
+ if (!expression.isPresent()
+ && compilerOptions.aheadOfTimeSubcomponents()
+ && request.requestKind().isPresent()
+ && isDerivedFromProvider(request.requestKind().get())) {
+ RequestKind requestKind = request.requestKind().get();
+ expression =
+ Optional.of(
+ new DerivedFromFrameworkInstanceBindingExpression(
+ request.key(), FrameworkType.PROVIDER, requestKind, this, types));
+ }
+
+ if (expression.isPresent()) {
+ expressions.put(request, expression.get());
+ return expression.get();
+ }
+ checkArgument(parent.isPresent(), "no expression found for %s", request);
+ return parent.get().getBindingExpression(request);
+ }
+
+ /** Creates a binding expression. */
+ BindingExpression createBindingExpression(
+ ResolvedBindings resolvedBindings, BindingRequest request) {
+ switch (resolvedBindings.bindingType()) {
+ case MEMBERS_INJECTION:
+ checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
+ return new MembersInjectionBindingExpression(resolvedBindings, membersInjectionMethods);
+
+ case PROVISION:
+ return provisionBindingExpression(resolvedBindings, request);
+
+ case PRODUCTION:
+ return productionBindingExpression(resolvedBindings, request);
+ }
+ throw new AssertionError(resolvedBindings);
+ }
+
+ /**
+ * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
+ * or a {@link dagger.producers.Producer} for production bindings.
+ */
+ private BindingExpression frameworkInstanceBindingExpression(ResolvedBindings resolvedBindings) {
+ // TODO(user): Consider merging the static factory creation logic into CreationExpressions?
+ Optional<MemberSelect> staticMethod =
+ useStaticFactoryCreation(resolvedBindings.contributionBinding())
+ ? staticFactoryCreation(resolvedBindings)
+ : Optional.empty();
+ FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
+ resolvedBindings.scope().isPresent()
+ ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings))
+ : frameworkInstanceCreationExpression(resolvedBindings);
+ FrameworkInstanceSupplier frameworkInstanceSupplier =
+ staticMethod.isPresent()
+ ? staticMethod::get
+ : new FrameworkFieldInitializer(
+ componentImplementation, resolvedBindings, frameworkInstanceCreationExpression);
+
+ switch (resolvedBindings.bindingType()) {
+ case PROVISION:
+ return new ProviderInstanceBindingExpression(
+ resolvedBindings, frameworkInstanceSupplier, types, elements);
+ case PRODUCTION:
+ return new ProducerNodeInstanceBindingExpression(
+ resolvedBindings, frameworkInstanceSupplier, types, elements, componentImplementation);
+ default:
+ throw new AssertionError("invalid binding type: " + resolvedBindings.bindingType());
+ }
+ }
+
+ private FrameworkInstanceCreationExpression scope(
+ ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) {
+ return () ->
+ CodeBlock.of(
+ "$T.provider($L)",
+ resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
+ unscoped.creationExpression());
+ }
+
+ /**
+ * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
+ * {@link dagger.producers.Producer} for production bindings.
+ */
+ private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
+ ResolvedBindings resolvedBindings) {
+ checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
+ ContributionBinding binding = resolvedBindings.contributionBinding();
+ switch (binding.kind()) {
+ case COMPONENT:
+ // The cast can be removed when we drop java 7 source support
+ return new InstanceFactoryCreationExpression(
+ () -> CodeBlock.of("($T) this", binding.key().type()));
+
+ case BOUND_INSTANCE:
+ return instanceFactoryCreationExpression(
+ binding, ComponentRequirement.forBoundInstance(binding));
+
+ case COMPONENT_DEPENDENCY:
+ return instanceFactoryCreationExpression(
+ binding, ComponentRequirement.forDependency(binding.key().type()));
+
+ case COMPONENT_PROVISION:
+ return new DependencyMethodProviderCreationExpression(
+ binding,
+ componentImplementation,
+ componentRequirementExpressions,
+ compilerOptions,
+ graph);
+
+ case SUBCOMPONENT_CREATOR:
+ return new AnonymousProviderCreationExpression(
+ binding, this, componentImplementation.name());
+
+ case INJECTION:
+ case PROVISION:
+ return new InjectionOrProvisionProviderCreationExpression(binding, this);
+
+ case COMPONENT_PRODUCTION:
+ return new DependencyMethodProducerCreationExpression(
+ binding, componentImplementation, componentRequirementExpressions, graph);
+
+ case PRODUCTION:
+ return new ProducerCreationExpression(binding, this);
+
+ case MULTIBOUND_SET:
+ return new SetFactoryCreationExpression(binding, componentImplementation, this, graph);
+
+ case MULTIBOUND_MAP:
+ return new MapFactoryCreationExpression(
+ binding, componentImplementation, this, graph, elements);
+
+ case DELEGATE:
+ return new DelegatingFrameworkInstanceCreationExpression(
+ binding, componentImplementation, this);
+
+ case OPTIONAL:
+ return new OptionalFactoryInstanceCreationExpression(
+ optionalFactories, binding, componentImplementation, this);
+
+ case MEMBERS_INJECTOR:
+ return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
+
+ default:
+ throw new AssertionError(binding);
+ }
+ }
+
+ private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
+ ContributionBinding binding, ComponentRequirement componentRequirement) {
+ return new InstanceFactoryCreationExpression(
+ binding.nullableType().isPresent(),
+ () ->
+ componentRequirementExpressions.getExpressionDuringInitialization(
+ componentRequirement, componentImplementation.name()));
+ }
+
+ /** Returns a binding expression for a provision binding. */
+ private BindingExpression provisionBindingExpression(
+ ResolvedBindings resolvedBindings, BindingRequest request) {
+ if (!request.requestKind().isPresent()) {
+ verify(
+ request.frameworkType().get().equals(FrameworkType.PRODUCER_NODE),
+ "expected a PRODUCER_NODE: %s",
+ request);
+ return producerFromProviderBindingExpression(resolvedBindings);
+ }
+ RequestKind requestKind = request.requestKind().get();
+ switch (requestKind) {
+ case INSTANCE:
+ return instanceBindingExpression(resolvedBindings);
+
+ case PROVIDER:
+ return providerBindingExpression(resolvedBindings);
+
+ case LAZY:
+ case PRODUCED:
+ case PROVIDER_OF_LAZY:
+ return new DerivedFromFrameworkInstanceBindingExpression(
+ resolvedBindings.key(), FrameworkType.PROVIDER, requestKind, this, types);
+
+ case PRODUCER:
+ return producerFromProviderBindingExpression(resolvedBindings);
+
+ case FUTURE:
+ return new ImmediateFutureBindingExpression(resolvedBindings, this, types, sourceVersion);
+
+ case MEMBERS_INJECTION:
+ throw new IllegalArgumentException();
+ }
+
+ throw new AssertionError();
+ }
+
+ /** Returns a binding expression for a production binding. */
+ private BindingExpression productionBindingExpression(
+ ResolvedBindings resolvedBindings, BindingRequest request) {
+ if (request.frameworkType().isPresent()) {
+ return frameworkInstanceBindingExpression(resolvedBindings);
+ } else {
+ // If no FrameworkType is present, a RequestKind is guaranteed to be present.
+ RequestKind requestKind = request.requestKind().get();
+ return new DerivedFromFrameworkInstanceBindingExpression(
+ resolvedBindings.key(), FrameworkType.PRODUCER_NODE, requestKind, this, types);
+ }
+ }
+
+ /**
+ * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
+ *
+ * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be
+ * cached} can use a {@link DelegateBindingExpression}.
+ *
+ * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
+ * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
+ * which case, just use that Provider directly).
+ *
+ * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
+ */
+ private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) {
+ if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)
+ && !needsCaching(resolvedBindings)) {
+ return new DelegateBindingExpression(
+ resolvedBindings, RequestKind.PROVIDER, this, types, elements);
+ } else if (compilerOptions.fastInit()
+ && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider()
+ && !(instanceBindingExpression(resolvedBindings)
+ instanceof DerivedFromFrameworkInstanceBindingExpression)) {
+ return wrapInMethod(
+ resolvedBindings,
+ bindingRequest(resolvedBindings.key(), RequestKind.PROVIDER),
+ innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding()));
+ }
+ return frameworkInstanceBindingExpression(resolvedBindings);
+ }
+
+ /**
+ * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
+ * provision binding.
+ */
+ private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
+ ResolvedBindings resolvedBindings) {
+ checkArgument(resolvedBindings.bindingType().equals(BindingType.PROVISION));
+ return new ProducerNodeInstanceBindingExpression(
+ resolvedBindings,
+ new FrameworkFieldInitializer(
+ componentImplementation,
+ resolvedBindings,
+ new ProducerFromProviderCreationExpression(
+ resolvedBindings.contributionBinding(), componentImplementation, this)),
+ types,
+ elements,
+ componentImplementation);
+ }
+
+ /**
+ * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
+ *
+ * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
+ * instance of this binding, return it, wrapped in a method if the binding {@linkplain
+ * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies.
+ *
+ * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
+ */
+ private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) {
+ Optional<BindingExpression> maybeDirectInstanceExpression =
+ unscopedDirectInstanceExpression(resolvedBindings);
+ if (canUseDirectInstanceExpression(resolvedBindings)
+ && maybeDirectInstanceExpression.isPresent()) {
+ BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
+ return directInstanceExpression.requiresMethodEncapsulation()
+ || needsCaching(resolvedBindings)
+ ? wrapInMethod(
+ resolvedBindings,
+ bindingRequest(resolvedBindings.key(), RequestKind.INSTANCE),
+ directInstanceExpression)
+ : directInstanceExpression;
+ }
+ return new DerivedFromFrameworkInstanceBindingExpression(
+ resolvedBindings.key(), FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types);
+ }
+
+ /**
+ * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
+ * {@code get()} on its provider, if there is one.
+ */
+ private Optional<BindingExpression> unscopedDirectInstanceExpression(
+ ResolvedBindings resolvedBindings) {
+ switch (resolvedBindings.contributionBinding().kind()) {
+ case DELEGATE:
+ return Optional.of(
+ new DelegateBindingExpression(
+ resolvedBindings, RequestKind.INSTANCE, this, types, elements));
+
+ case COMPONENT:
+ return Optional.of(
+ new ComponentInstanceBindingExpression(
+ resolvedBindings, componentImplementation.name()));
+
+ case COMPONENT_DEPENDENCY:
+ return Optional.of(
+ new ComponentRequirementBindingExpression(
+ resolvedBindings,
+ ComponentRequirement.forDependency(resolvedBindings.key().type()),
+ componentRequirementExpressions));
+
+ case COMPONENT_PROVISION:
+ return Optional.of(
+ new ComponentProvisionBindingExpression(
+ resolvedBindings, graph, componentRequirementExpressions, compilerOptions));
+
+ case SUBCOMPONENT_CREATOR:
+ return Optional.of(
+ new SubcomponentCreatorBindingExpression(
+ resolvedBindings,
+ componentImplementation.getSubcomponentCreatorSimpleName(resolvedBindings.key())));
+
+ case MULTIBOUND_SET:
+ return Optional.of(
+ new SetBindingExpression(
+ resolvedBindings, componentImplementation, graph, this, types, elements));
+
+ case MULTIBOUND_MAP:
+ return Optional.of(
+ new MapBindingExpression(
+ resolvedBindings, componentImplementation, graph, this, types, elements));
+
+ case OPTIONAL:
+ return Optional.of(
+ new OptionalBindingExpression(resolvedBindings, this, types, sourceVersion));
+
+ case BOUND_INSTANCE:
+ return Optional.of(
+ new ComponentRequirementBindingExpression(
+ resolvedBindings,
+ ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()),
+ componentRequirementExpressions));
+
+ case INJECTION:
+ case PROVISION:
+ return Optional.of(
+ new SimpleMethodBindingExpression(
+ resolvedBindings,
+ compilerOptions,
+ this,
+ membersInjectionMethods,
+ componentRequirementExpressions,
+ types,
+ elements,
+ sourceVersion));
+
+ case MEMBERS_INJECTOR:
+ return Optional.empty();
+
+ case MEMBERS_INJECTION:
+ case COMPONENT_PRODUCTION:
+ case PRODUCTION:
+ throw new IllegalArgumentException(
+ resolvedBindings.contributionBinding().kind().toString());
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns {@code true} if the binding should use the static factory creation strategy.
+ *
+ * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we
+ * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
+ * however, we allow static factories that can reused across multiple bindings, e.g. {@code
+ * MapFactory} or {@code SetFactory}.
+ */
+ private boolean useStaticFactoryCreation(ContributionBinding binding) {
+ return !compilerOptions.fastInit()
+ || binding.kind().equals(MULTIBOUND_MAP)
+ || binding.kind().equals(MULTIBOUND_SET);
+ }
+
+ /**
+ * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
+ * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached},
+ * we can.
+ *
+ * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
+ * #needsCaching(ResolvedBindings) needs to be cached}.
+ */
+ private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) {
+ return !needsCaching(resolvedBindings) || compilerOptions.fastInit();
+ }
+
+ /**
+ * Returns a binding expression that uses a given one as the body of a method that users call. If
+ * a component provision method matches it, it will be the method implemented. If it does not
+ * match a component provision method and the binding is modifiable, then a new public modifiable
+ * binding method will be written. If the binding doesn't match a component method and is not
+ * modifiable, then a new private method will be written.
+ */
+ BindingExpression wrapInMethod(
+ ResolvedBindings resolvedBindings,
+ BindingRequest request,
+ BindingExpression bindingExpression) {
+ // If we've already wrapped the expression, then use the delegate.
+ if (bindingExpression instanceof MethodBindingExpression) {
+ return bindingExpression;
+ }
+
+ MethodImplementationStrategy methodImplementationStrategy =
+ methodImplementationStrategy(resolvedBindings, request);
+ Optional<ComponentMethodDescriptor> matchingComponentMethod =
+ graph.componentDescriptor().firstMatchingComponentMethod(request);
+
+ if (modifiableBindingExpressions.getModifiableBindingType(request).isModifiable()
+ && (componentImplementation.superclassImplementation().isPresent()
+ || !matchingComponentMethod.isPresent())) {
+ return modifiableBindingExpressions.wrapInModifiableMethodBindingExpression(
+ request, resolvedBindings, methodImplementationStrategy, bindingExpression);
+ } else if (matchingComponentMethod.isPresent()) {
+ ComponentMethodDescriptor componentMethod = matchingComponentMethod.get();
+ return new ComponentMethodBindingExpression(
+ request,
+ resolvedBindings,
+ methodImplementationStrategy,
+ bindingExpression,
+ componentImplementation,
+ componentMethod,
+ types);
+ } else {
+ return new PrivateMethodBindingExpression(
+ request,
+ resolvedBindings,
+ methodImplementationStrategy,
+ bindingExpression,
+ componentImplementation,
+ types);
+ }
+ }
+
+ private MethodImplementationStrategy methodImplementationStrategy(
+ ResolvedBindings resolvedBindings, BindingRequest request) {
+ if (compilerOptions.fastInit()) {
+ if (request.isRequestKind(RequestKind.PROVIDER)) {
+ return MethodImplementationStrategy.SINGLE_CHECK;
+ } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) {
+ return resolvedBindings.scope().get().isReusable()
+ ? MethodImplementationStrategy.SINGLE_CHECK
+ : MethodImplementationStrategy.DOUBLE_CHECK;
+ }
+ }
+ return MethodImplementationStrategy.SIMPLE;
+ }
+
+ /**
+ * Returns {@code true} if the component needs to make sure the provided value is cached.
+ *
+ * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
+ * bindings whose scope is no stronger than their delegate's.
+ */
+ private boolean needsCaching(ResolvedBindings resolvedBindings) {
+ if (!resolvedBindings.scope().isPresent()) {
+ return false;
+ }
+ if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) {
+ return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph);
+ }
+ return true;
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentCreatorAnnotation.java b/java/dagger/internal/codegen/ComponentCreatorAnnotation.java
new file mode 100644
index 0000000..31bbfab
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentCreatorAnnotation.java
@@ -0,0 +1,150 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Ascii.toUpperCase;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.valuesOf;
+import static java.util.stream.Collectors.mapping;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.Component;
+import dagger.Subcomponent;
+import dagger.producers.ProductionComponent;
+import dagger.producers.ProductionSubcomponent;
+import java.lang.annotation.Annotation;
+import java.util.stream.Collector;
+import java.util.stream.Stream;
+import javax.lang.model.element.TypeElement;
+
+/** Simple representation of a component creator annotation type. */
+enum ComponentCreatorAnnotation {
+ COMPONENT_BUILDER(Component.Builder.class),
+ COMPONENT_FACTORY(Component.Factory.class),
+ SUBCOMPONENT_BUILDER(Subcomponent.Builder.class),
+ SUBCOMPONENT_FACTORY(Subcomponent.Factory.class),
+ PRODUCTION_COMPONENT_BUILDER(ProductionComponent.Builder.class),
+ PRODUCTION_COMPONENT_FACTORY(ProductionComponent.Factory.class),
+ PRODUCTION_SUBCOMPONENT_BUILDER(ProductionSubcomponent.Builder.class),
+ PRODUCTION_SUBCOMPONENT_FACTORY(ProductionSubcomponent.Factory.class),
+ ;
+
+ private final Class<? extends Annotation> annotation;
+ private final ComponentCreatorKind creatorKind;
+ private final Class<? extends Annotation> componentAnnotation;
+
+ ComponentCreatorAnnotation(Class<? extends Annotation> annotation) {
+ this.annotation = annotation;
+ this.creatorKind = ComponentCreatorKind.valueOf(toUpperCase(annotation.getSimpleName()));
+ this.componentAnnotation = (Class<? extends Annotation>) annotation.getEnclosingClass();
+ }
+
+ /** The actual annotation type. */
+ Class<? extends Annotation> annotation() {
+ return annotation;
+ }
+
+ /** The component annotation type that encloses this creator annotation type. */
+ final Class<? extends Annotation> componentAnnotation() {
+ return componentAnnotation;
+ }
+
+ /** Returns {@code true} if the creator annotation is for a subcomponent. */
+ final boolean isSubcomponentCreatorAnnotation() {
+ return componentAnnotation().getSimpleName().endsWith("Subcomponent");
+ }
+
+ /**
+ * Returns {@code true} if the creator annotation is for a production component or subcomponent.
+ */
+ final boolean isProductionCreatorAnnotation() {
+ return componentAnnotation().getSimpleName().startsWith("Production");
+ }
+
+ /** The creator kind the annotation is associated with. */
+ // TODO(dpb): Remove ComponentCreatorKind.
+ ComponentCreatorKind creatorKind() {
+ return creatorKind;
+ }
+
+ @Override
+ public final String toString() {
+ return annotation().getName();
+ }
+
+ /** Returns all component creator annotations. */
+ static ImmutableSet<Class<? extends Annotation>> allCreatorAnnotations() {
+ return stream().collect(toAnnotationClasses());
+ }
+
+ /** Returns all root component creator annotations. */
+ static ImmutableSet<Class<? extends Annotation>> rootComponentCreatorAnnotations() {
+ return stream()
+ .filter(
+ componentCreatorAnnotation ->
+ !componentCreatorAnnotation.isSubcomponentCreatorAnnotation())
+ .collect(toAnnotationClasses());
+ }
+
+ /** Returns all subcomponent creator annotations. */
+ static ImmutableSet<Class<? extends Annotation>> subcomponentCreatorAnnotations() {
+ return stream()
+ .filter(
+ componentCreatorAnnotation ->
+ componentCreatorAnnotation.isSubcomponentCreatorAnnotation())
+ .collect(toAnnotationClasses());
+ }
+
+ /** Returns all production component creator annotations. */
+ static ImmutableSet<Class<? extends Annotation>> productionCreatorAnnotations() {
+ return stream()
+ .filter(
+ componentCreatorAnnotation ->
+ componentCreatorAnnotation.isProductionCreatorAnnotation())
+ .collect(toAnnotationClasses());
+ }
+
+ /** Returns the legal creator annotations for the given {@code componentAnnotation}. */
+ static ImmutableSet<Class<? extends Annotation>> creatorAnnotationsFor(
+ ComponentAnnotation componentAnnotation) {
+ return stream()
+ .filter(
+ creatorAnnotation ->
+ creatorAnnotation
+ .componentAnnotation()
+ .getSimpleName()
+ .equals(componentAnnotation.simpleName()))
+ .collect(toAnnotationClasses());
+ }
+
+ /** Returns all creator annotations present on the given {@code type}. */
+ static ImmutableSet<ComponentCreatorAnnotation> getCreatorAnnotations(TypeElement type) {
+ return stream()
+ .filter(cca -> isAnnotationPresent(type, cca.annotation()))
+ .collect(toImmutableSet());
+ }
+
+ private static Stream<ComponentCreatorAnnotation> stream() {
+ return valuesOf(ComponentCreatorAnnotation.class);
+ }
+
+ private static Collector<ComponentCreatorAnnotation, ?, ImmutableSet<Class<? extends Annotation>>>
+ toAnnotationClasses() {
+ return mapping(ComponentCreatorAnnotation::annotation, toImmutableSet());
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentCreatorDescriptor.java b/java/dagger/internal/codegen/ComponentCreatorDescriptor.java
new file mode 100644
index 0000000..f6ec7a2
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentCreatorDescriptor.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.auto.common.MoreTypes.asTypeElement;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.getCreatorAnnotations;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
+
+import com.google.auto.common.MoreTypes;
+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.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import dagger.BindsInstance;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import java.util.List;
+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.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A descriptor for a component <i>creator</i> type: that is, a type annotated with
+ * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions).
+ */
+@AutoValue
+abstract class ComponentCreatorDescriptor {
+
+ /** Returns the annotation marking this creator. */
+ abstract ComponentCreatorAnnotation annotation();
+
+ /** The kind of this creator. */
+ final ComponentCreatorKind kind() {
+ return annotation().creatorKind();
+ }
+
+ /** The annotated creator type. */
+ abstract TypeElement typeElement();
+
+ /** The method that creates and returns a component instance. */
+ abstract ExecutableElement factoryMethod();
+
+ /**
+ * Multimap of component requirements to setter methods that set that requirement.
+ *
+ * <p>In a valid creator, there will be exactly one element per component requirement, so this
+ * method should only be called when validating the descriptor.
+ */
+ abstract ImmutableSetMultimap<ComponentRequirement, ExecutableElement> unvalidatedSetterMethods();
+
+ /**
+ * Multimap of component requirements to factory method parameters that set that requirement.
+ *
+ * <p>In a valid creator, there will be exactly one element per component requirement, so this
+ * method should only be called when validating the descriptor.
+ */
+ abstract ImmutableSetMultimap<ComponentRequirement, VariableElement>
+ unvalidatedFactoryParameters();
+
+ /**
+ * Multimap of component requirements to elements (methods or parameters) that set that
+ * requirement.
+ *
+ * <p>In a valid creator, there will be exactly one element per component requirement, so this
+ * method should only be called when validating the descriptor.
+ */
+ final ImmutableSetMultimap<ComponentRequirement, Element> unvalidatedRequirementElements() {
+ // ComponentCreatorValidator ensures that there are either setter methods or factory method
+ // parameters, but not both, so we can cheat a little here since we know that only one of
+ // the two multimaps will be non-empty.
+ return ImmutableSetMultimap.copyOf( // no actual copy
+ unvalidatedSetterMethods().isEmpty()
+ ? unvalidatedFactoryParameters()
+ : unvalidatedSetterMethods());
+ }
+
+ /**
+ * Map of component requirements to elements (setter methods or factory method parameters) that
+ * set them.
+ */
+ @Memoized
+ ImmutableMap<ComponentRequirement, Element> requirementElements() {
+ return flatten(unvalidatedRequirementElements());
+ }
+
+ /** Map of component requirements to setter methods for those requirements. */
+ @Memoized
+ ImmutableMap<ComponentRequirement, ExecutableElement> setterMethods() {
+ return flatten(unvalidatedSetterMethods());
+ }
+
+ /** Map of component requirements to factory method parameters for those requirements. */
+ @Memoized
+ ImmutableMap<ComponentRequirement, VariableElement> factoryParameters() {
+ return flatten(unvalidatedFactoryParameters());
+ }
+
+ private static <K, V> ImmutableMap<K, V> flatten(Multimap<K, V> multimap) {
+ return ImmutableMap.copyOf(
+ Maps.transformValues(multimap.asMap(), values -> getOnlyElement(values)));
+ }
+
+ /** Returns the set of component requirements this creator allows the user to set. */
+ final ImmutableSet<ComponentRequirement> userSettableRequirements() {
+ // Note: they should have been validated at the point this is used, so this set is valid.
+ return unvalidatedRequirementElements().keySet();
+ }
+
+ /** Returns the set of requirements for modules and component dependencies for this creator. */
+ final ImmutableSet<ComponentRequirement> moduleAndDependencyRequirements() {
+ return userSettableRequirements().stream()
+ .filter(requirement -> !requirement.isBoundInstance())
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the set of bound instance requirements for this creator. */
+ final ImmutableSet<ComponentRequirement> boundInstanceRequirements() {
+ return userSettableRequirements().stream()
+ .filter(ComponentRequirement::isBoundInstance)
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the element in this creator that sets the given {@code requirement}. */
+ final Element elementForRequirement(ComponentRequirement requirement) {
+ return requirementElements().get(requirement);
+ }
+
+ /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */
+ static ComponentCreatorDescriptor create(
+ DeclaredType type,
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestFactory dependencyRequestFactory) {
+ TypeElement typeElement = asTypeElement(type);
+ TypeMirror componentType = typeElement.getEnclosingElement().asType();
+
+ ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods =
+ ImmutableSetMultimap.builder();
+
+ ExecutableElement factoryMethod = null;
+ for (ExecutableElement method : elements.getUnimplementedMethods(typeElement)) {
+ ExecutableType resolvedMethodType = MoreTypes.asExecutable(types.asMemberOf(type, method));
+
+ if (types.isSubtype(componentType, resolvedMethodType.getReturnType())) {
+ factoryMethod = method;
+ } else {
+ VariableElement parameter = getOnlyElement(method.getParameters());
+ TypeMirror parameterType = getOnlyElement(resolvedMethodType.getParameterTypes());
+ setterMethods.put(
+ requirement(method, parameter, parameterType, dependencyRequestFactory, method),
+ method);
+ }
+ }
+ verify(factoryMethod != null); // validation should have ensured this.
+
+ ImmutableSetMultimap.Builder<ComponentRequirement, VariableElement> factoryParameters =
+ ImmutableSetMultimap.builder();
+
+ ExecutableType resolvedFactoryMethodType =
+ MoreTypes.asExecutable(types.asMemberOf(type, factoryMethod));
+ List<? extends VariableElement> parameters = factoryMethod.getParameters();
+ List<? extends TypeMirror> parameterTypes = resolvedFactoryMethodType.getParameterTypes();
+ for (int i = 0; i < parameters.size(); i++) {
+ VariableElement parameter = parameters.get(i);
+ TypeMirror parameterType = parameterTypes.get(i);
+ factoryParameters.put(
+ requirement(factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter),
+ parameter);
+ }
+
+ // Validation should have ensured exactly one creator annotation is present on the type.
+ ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(typeElement));
+ return new AutoValue_ComponentCreatorDescriptor(
+ annotation, typeElement, factoryMethod, setterMethods.build(), factoryParameters.build());
+ }
+
+ private static ComponentRequirement requirement(
+ ExecutableElement method,
+ VariableElement parameter,
+ TypeMirror type,
+ DependencyRequestFactory dependencyRequestFactory,
+ Element elementForVariableName) {
+ if (isAnnotationPresent(method, BindsInstance.class)
+ || isAnnotationPresent(parameter, BindsInstance.class)) {
+ DependencyRequest request =
+ dependencyRequestFactory.forRequiredResolvedVariable(parameter, type);
+ String variableName = elementForVariableName.getSimpleName().toString();
+ return ComponentRequirement.forBoundInstance(
+ request.key(), request.isNullable(), variableName);
+ }
+
+ return moduleAnnotation(asTypeElement(type)).isPresent()
+ ? ComponentRequirement.forModule(type)
+ : ComponentRequirement.forDependency(type);
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentCreatorImplementation.java b/java/dagger/internal/codegen/ComponentCreatorImplementation.java
new file mode 100644
index 0000000..a5eb680
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentCreatorImplementation.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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 com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeSpec;
+
+/** The implementation of a component creator type. */
+@AutoValue
+abstract class ComponentCreatorImplementation {
+
+ /** Creates a new {@link ComponentCreatorImplementation}. */
+ static ComponentCreatorImplementation create(
+ TypeSpec spec,
+ ClassName name,
+ ImmutableMap<ComponentRequirement, FieldSpec> fields) {
+ return new AutoValue_ComponentCreatorImplementation(spec, name, fields);
+ }
+
+ /** The type spec for the creator implementation. */
+ abstract TypeSpec spec();
+
+ /** The name of the creator implementation class. */
+ abstract ClassName name();
+
+ /**
+ * All fields that are present in this implementation or its supertype.
+ *
+ * <p>In the case of ahead-of-time subcomponents, not all fields will necessarily be passed to
+ * the component's constructor (because, for example, it turns out that a particular module that
+ * the creator can set is actually inherited from an ancestor module).
+ */
+ abstract ImmutableMap<ComponentRequirement, FieldSpec> fields();
+}
diff --git a/java/dagger/internal/codegen/ComponentCreatorImplementationFactory.java b/java/dagger/internal/codegen/ComponentCreatorImplementationFactory.java
new file mode 100644
index 0000000..4f06b90
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentCreatorImplementationFactory.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (C) 2017 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.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.SourceFiles.simpleVariableName;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeSpecs.addSupertype;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.Preconditions;
+import dagger.internal.codegen.ComponentRequirement.NullPolicy;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Optional;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+
+/** Factory for creating {@link ComponentCreatorImplementation} instances. */
+final class ComponentCreatorImplementationFactory {
+
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+
+ @Inject
+ ComponentCreatorImplementationFactory(DaggerElements elements, DaggerTypes types) {
+ this.elements = elements;
+ this.types = types;
+ }
+
+ /** Returns a new creator implementation for the given component, if necessary. */
+ Optional<ComponentCreatorImplementation> create(
+ ComponentImplementation componentImplementation, Optional<BindingGraph> graph) {
+ if (!componentImplementation.componentDescriptor().hasCreator()) {
+ return Optional.empty();
+ }
+
+ Optional<ComponentCreatorDescriptor> creatorDescriptor =
+ componentImplementation.componentDescriptor().creatorDescriptor();
+
+ if (componentImplementation.isAbstract()
+ && (hasNoSetterMethods(creatorDescriptor)
+ || componentImplementation.superclassImplementation().isPresent())) {
+ // 1. Factory-like creators (those with no setter methods) are only generated in concrete
+ // components, because they only have a factory method and the factory method must call
+ // a concrete component's constructor.
+ // 2. The component builder in ahead-of-time mode is generated with the base subcomponent
+ // implementation, with the exception of the build method since that requires invoking the
+ // constructor of a concrete component implementation. Intermediate component
+ // implementations, because they still can't invoke the eventual constructor and have no
+ // additional extensions to the builder, can ignore generating a builder implementation.
+ return Optional.empty();
+ }
+
+ Builder builder =
+ creatorDescriptor.isPresent()
+ ? new BuilderForCreatorDescriptor(
+ componentImplementation, creatorDescriptor.get(), graph)
+ : new BuilderForGeneratedRootComponentBuilder(componentImplementation);
+ return Optional.of(builder.build());
+ }
+
+ private static boolean hasNoSetterMethods(
+ Optional<ComponentCreatorDescriptor> creatorDescriptor) {
+ return creatorDescriptor.filter(descriptor -> descriptor.setterMethods().isEmpty()).isPresent();
+ }
+
+ /** Base class for building a creator implementation. */
+ private abstract class Builder {
+ final ComponentImplementation componentImplementation;
+ final ClassName className;
+ final TypeSpec.Builder classBuilder;
+
+ private ImmutableMap<ComponentRequirement, FieldSpec> fields;
+
+ Builder(ComponentImplementation componentImplementation) {
+ this.componentImplementation = componentImplementation;
+ this.className = componentImplementation.getCreatorName();
+ this.classBuilder = classBuilder(className);
+ }
+
+ /** Builds the {@link ComponentCreatorImplementation}. */
+ ComponentCreatorImplementation build() {
+ setModifiers();
+ setSupertype();
+ this.fields = getOrAddFields();
+ addConstructor();
+ addSetterMethods();
+ addFactoryMethod();
+ return ComponentCreatorImplementation.create(classBuilder.build(), className, fields);
+ }
+
+ /** Returns the descriptor for the component. */
+ final ComponentDescriptor componentDescriptor() {
+ return componentImplementation.componentDescriptor();
+ }
+
+ /**
+ * The set of requirements that must be passed to the component's constructor in the order
+ * they must be passed.
+ */
+ final ImmutableSet<ComponentRequirement> componentConstructorRequirements() {
+ return componentImplementation.requirements();
+ }
+
+ /** Returns the requirements that have setter methods on the creator type. */
+ abstract ImmutableSet<ComponentRequirement> setterMethods();
+
+ /**
+ * Returns the component requirements that have factory method parameters, mapped to the name
+ * for that parameter.
+ */
+ abstract ImmutableMap<ComponentRequirement, String> factoryMethodParameters();
+
+ /**
+ * The {@link ComponentRequirement}s that this creator allows users to set. Values are a status
+ * for each requirement indicating what's needed for that requirement in the implementation
+ * class currently being generated.
+ */
+ abstract ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements();
+
+ /**
+ * Component requirements that are both settable by the creator and needed to construct the
+ * component.
+ */
+ private Set<ComponentRequirement> neededUserSettableRequirements() {
+ return Sets.intersection(
+ userSettableRequirements().keySet(), componentConstructorRequirements());
+ }
+
+ private void setModifiers() {
+ visibility().ifPresent(classBuilder::addModifiers);
+ if (!componentImplementation.isNested()) {
+ classBuilder.addModifiers(STATIC);
+ }
+ classBuilder.addModifiers(componentImplementation.isAbstract() ? ABSTRACT : FINAL);
+ }
+
+ /** Returns the visibility modifier the generated class should have, if any. */
+ protected abstract Optional<Modifier> visibility();
+
+ /** Sets the superclass being extended or interface being implemented for this creator. */
+ protected abstract void setSupertype();
+
+ /** Adds a constructor for the creator type, if needed. */
+ protected abstract void addConstructor();
+
+ private ImmutableMap<ComponentRequirement, FieldSpec> getOrAddFields() {
+ // If a base implementation is present, any fields are already defined there and don't need to
+ // be created in this implementation.
+ return componentImplementation
+ .baseCreatorImplementation()
+ .map(ComponentCreatorImplementation::fields)
+ .orElseGet(this::addFields);
+ }
+
+ private ImmutableMap<ComponentRequirement, FieldSpec> addFields() {
+ // Fields in an abstract creator class need to be visible from subclasses.
+ Modifier modifier = componentImplementation.isAbstract() ? PROTECTED : PRIVATE;
+ UniqueNameSet fieldNames = new UniqueNameSet();
+ ImmutableMap<ComponentRequirement, FieldSpec> result =
+ Maps.toMap(
+ Sets.intersection(neededUserSettableRequirements(), setterMethods()),
+ requirement ->
+ FieldSpec.builder(
+ TypeName.get(requirement.type()),
+ fieldNames.getUniqueName(requirement.variableName()),
+ modifier)
+ .build());
+ classBuilder.addFields(result.values());
+ return result;
+ }
+
+ private void addSetterMethods() {
+ Maps.filterKeys(userSettableRequirements(), setterMethods()::contains)
+ .forEach(
+ (requirement, status) ->
+ createSetterMethod(requirement, status).ifPresent(classBuilder::addMethod));
+ }
+
+ /** Creates a new setter method builder, with no method body, for the given requirement. */
+ protected abstract MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement);
+
+ private Optional<MethodSpec> createSetterMethod(
+ ComponentRequirement requirement, RequirementStatus status) {
+ switch (status) {
+ case NEEDED:
+ return Optional.of(normalSetterMethod(requirement));
+ case UNNEEDED:
+ return Optional.of(noopSetterMethod(requirement));
+ case UNSETTABLE_REPEATED_MODULE:
+ return Optional.of(repeatedModuleSetterMethod(requirement));
+ case IMPLEMENTED_IN_SUPERTYPE:
+ return Optional.empty();
+ }
+ throw new AssertionError();
+ }
+
+ private MethodSpec normalSetterMethod(ComponentRequirement requirement) {
+ MethodSpec.Builder method = setterMethodBuilder(requirement);
+ ParameterSpec parameter = parameter(method.build());
+ method.addStatement(
+ "this.$N = $L",
+ fields.get(requirement),
+ requirement.nullPolicy(elements, types).equals(NullPolicy.ALLOW)
+ ? CodeBlock.of("$N", parameter)
+ : CodeBlock.of("$T.checkNotNull($N)", Preconditions.class, parameter));
+ return maybeReturnThis(method);
+ }
+
+ private MethodSpec noopSetterMethod(ComponentRequirement requirement) {
+ MethodSpec.Builder method = setterMethodBuilder(requirement);
+ ParameterSpec parameter = parameter(method.build());
+ method
+ .addAnnotation(Deprecated.class)
+ .addJavadoc(
+ "@deprecated This module is declared, but an instance is not used in the component. "
+ + "This method is a no-op. For more, see https://dagger.dev/unused-modules.\n")
+ .addStatement("$T.checkNotNull($N)", Preconditions.class, parameter);
+ return maybeReturnThis(method);
+ }
+
+ private MethodSpec repeatedModuleSetterMethod(ComponentRequirement requirement) {
+ return setterMethodBuilder(requirement)
+ .addStatement(
+ "throw new $T($T.format($S, $T.class.getCanonicalName()))",
+ UnsupportedOperationException.class,
+ String.class,
+ "%s cannot be set because it is inherited from the enclosing component",
+ TypeNames.rawTypeName(TypeName.get(requirement.type())))
+ .build();
+ }
+
+ private ParameterSpec parameter(MethodSpec method) {
+ return getOnlyElement(method.parameters);
+ }
+
+ private MethodSpec maybeReturnThis(MethodSpec.Builder method) {
+ MethodSpec built = method.build();
+ return built.returnType.equals(TypeName.VOID)
+ ? built
+ : method.addStatement("return this").build();
+ }
+
+ private void addFactoryMethod() {
+ if (!componentImplementation.isAbstract()) {
+ classBuilder.addMethod(factoryMethod());
+ }
+ }
+
+ MethodSpec factoryMethod() {
+ MethodSpec.Builder factoryMethod = factoryMethodBuilder();
+ factoryMethod
+ .returns(ClassName.get(componentDescriptor().typeElement()))
+ .addModifiers(PUBLIC);
+
+ ImmutableMap<ComponentRequirement, String> factoryMethodParameters =
+ factoryMethodParameters();
+ userSettableRequirements()
+ .keySet()
+ .forEach(
+ requirement -> {
+ if (fields.containsKey(requirement)
+ && componentConstructorRequirements().contains(requirement)) {
+ // In AOT mode, there can be a field for a requirement even if the component's
+ // constructor doesn't need it, because the base class for the creator was created
+ // before the final graph for the component was known.
+ FieldSpec field = fields.get(requirement);
+ addNullHandlingForField(requirement, field, factoryMethod);
+ } else if (factoryMethodParameters.containsKey(requirement)) {
+ String parameterName = factoryMethodParameters.get(requirement);
+ addNullHandlingForParameter(requirement, parameterName, factoryMethod);
+ }
+ });
+ factoryMethod.addStatement(
+ "return new $T($L)",
+ componentImplementation.name(),
+ componentConstructorArgs(factoryMethodParameters));
+ return factoryMethod.build();
+ }
+
+ private void addNullHandlingForField(
+ ComponentRequirement requirement, FieldSpec field, MethodSpec.Builder factoryMethod) {
+ switch (requirement.nullPolicy(elements, types)) {
+ case NEW:
+ checkState(requirement.kind().isModule());
+ factoryMethod
+ .beginControlFlow("if ($N == null)", field)
+ .addStatement("this.$N = $L", field, newModuleInstance(requirement))
+ .endControlFlow();
+ break;
+ case THROW:
+ // TODO(cgdecker,ronshapiro): ideally this should use the key instead of a class for
+ // @BindsInstance requirements, but that's not easily proguardable.
+ factoryMethod.addStatement(
+ "$T.checkBuilderRequirement($N, $T.class)",
+ Preconditions.class,
+ field,
+ TypeNames.rawTypeName(field.type));
+ break;
+ case ALLOW:
+ break;
+ }
+ }
+
+ private void addNullHandlingForParameter(
+ ComponentRequirement requirement, String parameter, MethodSpec.Builder factoryMethod) {
+ if (!requirement.nullPolicy(elements, types).equals(NullPolicy.ALLOW)) {
+ // Factory method parameters are always required unless they are a nullable
+ // binds-instance (i.e. ALLOW)
+ factoryMethod.addStatement("$T.checkNotNull($L)", Preconditions.class, parameter);
+ }
+ }
+
+ /** Returns a builder for the creator's factory method. */
+ protected abstract MethodSpec.Builder factoryMethodBuilder();
+
+ private CodeBlock componentConstructorArgs(
+ ImmutableMap<ComponentRequirement, String> factoryMethodParameters) {
+ return componentConstructorRequirements().stream()
+ .map(
+ requirement -> {
+ if (fields.containsKey(requirement)) {
+ return CodeBlock.of("$N", fields.get(requirement));
+ } else if (factoryMethodParameters.containsKey(requirement)) {
+ return CodeBlock.of("$L", factoryMethodParameters.get(requirement));
+ } else {
+ return newModuleInstance(requirement);
+ }
+ })
+ .collect(toParametersCodeBlock());
+ }
+
+ private CodeBlock newModuleInstance(ComponentRequirement requirement) {
+ checkArgument(requirement.kind().isModule()); // this should be guaranteed to be true here
+ return ModuleProxies.newModuleInstance(requirement.typeElement(), className, elements);
+ }
+ }
+
+ /** Builder for a creator type defined by a {@code ComponentCreatorDescriptor}. */
+ private final class BuilderForCreatorDescriptor extends Builder {
+ final ComponentCreatorDescriptor creatorDescriptor;
+ private final Optional<BindingGraph> graph;
+
+ BuilderForCreatorDescriptor(
+ ComponentImplementation componentImplementation,
+ ComponentCreatorDescriptor creatorDescriptor,
+ Optional<BindingGraph> graph) {
+ super(componentImplementation);
+ this.creatorDescriptor = creatorDescriptor;
+ this.graph = graph;
+ }
+
+ @Override
+ protected ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements() {
+ return Maps.toMap(creatorDescriptor.userSettableRequirements(), this::requirementStatus);
+ }
+
+ @Override
+ protected Optional<Modifier> visibility() {
+ if (componentImplementation.isAbstract()) {
+ // The component creator class of a top-level component implementation in ahead-of-time
+ // subcomponents mode must be public, not protected, because the creator's subclass will
+ // be a sibling of the component subclass implementation, not nested.
+ return Optional.of(componentImplementation.isNested() ? PROTECTED : PUBLIC);
+ }
+ return Optional.of(PRIVATE);
+ }
+
+ @Override
+ protected void setSupertype() {
+ if (componentImplementation.baseCreatorImplementation().isPresent()) {
+ // If an abstract base implementation for this creator exists, extend that class.
+ classBuilder.superclass(componentImplementation.baseCreatorImplementation().get().name());
+ } else {
+ addSupertype(classBuilder, creatorDescriptor.typeElement());
+ }
+ }
+
+ @Override
+ protected void addConstructor() {
+ // Just use the implicit no-arg public constructor.
+ }
+
+ @Override
+ protected ImmutableSet<ComponentRequirement> setterMethods() {
+ return ImmutableSet.copyOf(creatorDescriptor.setterMethods().keySet());
+ }
+
+ @Override
+ protected ImmutableMap<ComponentRequirement, String> factoryMethodParameters() {
+ return ImmutableMap.copyOf(
+ Maps.transformValues(
+ creatorDescriptor.factoryParameters(),
+ element -> element.getSimpleName().toString()));
+ }
+
+ private DeclaredType creatorType() {
+ return asDeclared(creatorDescriptor.typeElement().asType());
+ }
+
+ @Override
+ protected MethodSpec.Builder factoryMethodBuilder() {
+ return MethodSpec.overriding(creatorDescriptor.factoryMethod(), creatorType(), types);
+ }
+
+ private RequirementStatus requirementStatus(ComponentRequirement requirement) {
+ // In ahead-of-time subcomponents mode, all builder methods are defined at the base
+ // implementation. The only case where a method needs to be overridden is for a repeated
+ // module, which is unknown at the point when a base implementation is generated. We do this
+ // at the root for simplicity (and as an aside, repeated modules are never used in google
+ // as of 11/28/18, and thus the additional cost of including these methods at the root is
+ // negligible).
+ if (isRepeatedModule(requirement)) {
+ return RequirementStatus.UNSETTABLE_REPEATED_MODULE;
+ }
+
+ if (hasBaseCreatorImplementation()) {
+ return RequirementStatus.IMPLEMENTED_IN_SUPERTYPE;
+ }
+
+ return componentConstructorRequirements().contains(requirement)
+ ? RequirementStatus.NEEDED
+ : RequirementStatus.UNNEEDED;
+ }
+
+ /**
+ * Returns whether the given requirement is for a repeat of a module inherited from an ancestor
+ * component. This creator is not allowed to set such a module.
+ */
+ final boolean isRepeatedModule(ComponentRequirement requirement) {
+ return !componentConstructorRequirements().contains(requirement)
+ && !isOwnedModule(requirement);
+ }
+
+ /**
+ * Returns whether the given {@code requirement} is for a module type owned by the component.
+ */
+ private boolean isOwnedModule(ComponentRequirement requirement) {
+ return graph.map(g -> g.ownedModuleTypes().contains(requirement.typeElement())).orElse(true);
+ }
+
+ private boolean hasBaseCreatorImplementation() {
+ return !componentImplementation.isAbstract()
+ && componentImplementation.baseImplementation().isPresent();
+ }
+
+ @Override
+ protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
+ ExecutableElement supertypeMethod = creatorDescriptor.setterMethods().get(requirement);
+ MethodSpec.Builder method = MethodSpec.overriding(supertypeMethod, creatorType(), types);
+ if (!supertypeMethod.getReturnType().getKind().equals(TypeKind.VOID)) {
+ // Take advantage of covariant returns so that we don't have to worry about type variables
+ method.returns(className);
+ }
+ return method;
+ }
+ }
+
+ /**
+ * Builder for a component builder class that is automatically generated for a root component that
+ * does not have its own user-defined creator type (i.e. a {@code ComponentCreatorDescriptor}).
+ */
+ private final class BuilderForGeneratedRootComponentBuilder extends Builder {
+ BuilderForGeneratedRootComponentBuilder(ComponentImplementation componentImplementation) {
+ super(componentImplementation);
+ }
+
+ @Override
+ protected ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements() {
+ return Maps.toMap(
+ setterMethods(),
+ requirement ->
+ componentConstructorRequirements().contains(requirement)
+ ? RequirementStatus.NEEDED
+ : RequirementStatus.UNNEEDED);
+ }
+
+ @Override
+ protected Optional<Modifier> visibility() {
+ return componentImplementation
+ .componentDescriptor()
+ .typeElement()
+ .getModifiers()
+ .contains(PUBLIC) ? Optional.of(PUBLIC) : Optional.empty();
+ }
+
+ @Override
+ protected void setSupertype() {
+ // There's never a supertype for a root component auto-generated builder type.
+ }
+
+ @Override
+ protected void addConstructor() {
+ classBuilder.addMethod(constructorBuilder().addModifiers(PRIVATE).build());
+ }
+
+ @Override
+ protected ImmutableSet<ComponentRequirement> setterMethods() {
+ return componentDescriptor().dependenciesAndConcreteModules();
+ }
+
+ @Override
+ protected ImmutableMap<ComponentRequirement, String> factoryMethodParameters() {
+ return ImmutableMap.of();
+ }
+
+ @Override
+ protected MethodSpec.Builder factoryMethodBuilder() {
+ return methodBuilder("build");
+ }
+
+ @Override
+ protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
+ String name = simpleVariableName(requirement.typeElement());
+ return methodBuilder(name)
+ .addModifiers(PUBLIC)
+ .addParameter(TypeName.get(requirement.type()), name)
+ .returns(className);
+ }
+ }
+
+ /** Enumeration of statuses a component requirement may have in a creator. */
+ enum RequirementStatus {
+ /** An instance is needed to create the component. */
+ NEEDED,
+
+ /**
+ * An instance is not needed to create the component, but the requirement is for a module owned
+ * by the component. Setting the requirement is a no-op and any setter method should be marked
+ * deprecated on the generated type as a warning to the user.
+ */
+ UNNEEDED,
+
+ /**
+ * The requirement may not be set in this creator because the module it is for is already
+ * inherited from an ancestor component. Any setter method for it should throw an exception.
+ */
+ UNSETTABLE_REPEATED_MODULE,
+
+ /**
+ * The requirement is settable by the creator, but the setter method implementation already
+ * exists in a supertype.
+ */
+ IMPLEMENTED_IN_SUPERTYPE,
+ ;
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentCreatorKind.java b/java/dagger/internal/codegen/ComponentCreatorKind.java
new file mode 100644
index 0000000..dc203de
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentCreatorKind.java
@@ -0,0 +1,42 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+
+import com.google.common.base.Ascii;
+
+/** Enumeration of the different kinds of component creators. */
+enum ComponentCreatorKind {
+ /** {@code @Component.Builder} or one of its subcomponent/production variants. */
+ BUILDER,
+
+ /** {@code @Component.Factory} or one of its subcomponent/production variants. */
+ FACTORY,
+ ;
+
+ /** Name to use as (or as part of) a type name for a creator of this kind. */
+ String typeName() {
+ return UPPER_UNDERSCORE.to(UPPER_CAMEL, name());
+ }
+
+ /** Name to use for a component's static method returning a creator of this kind. */
+ String methodName() {
+ return Ascii.toLowerCase(name());
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentCreatorValidator.java b/java/dagger/internal/codegen/ComponentCreatorValidator.java
new file mode 100644
index 0000000..c55dadd
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentCreatorValidator.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.getCreatorAnnotations;
+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 static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ObjectArrays;
+import dagger.BindsInstance;
+import dagger.internal.codegen.ErrorMessages.ComponentCreatorMessages;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.List;
+import java.util.Set;
+import javax.inject.Inject;
+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.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+
+/** Validates types annotated with component creator annotations. */
+final class ComponentCreatorValidator {
+
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+
+ @Inject
+ ComponentCreatorValidator(DaggerElements elements, DaggerTypes types) {
+ this.elements = elements;
+ this.types = types;
+ }
+
+ /** Validates that the given {@code type} is potentially a valid component creator type. */
+ public ValidationReport<TypeElement> validate(TypeElement type) {
+ ValidationReport.Builder<TypeElement> report = ValidationReport.about(type);
+
+ ImmutableSet<ComponentCreatorAnnotation> creatorAnnotations = getCreatorAnnotations(type);
+ if (!validateOnlyOneCreatorAnnotation(creatorAnnotations, report)) {
+ return report.build();
+ }
+
+ // Note: there's more validation in ComponentDescriptorValidator:
+ // - to make sure the setter methods/factory parameters mirror the deps
+ // - to make sure each type or key is set by only one method or parameter
+ ElementValidator validator =
+ new ElementValidator(type, report, getOnlyElement(creatorAnnotations));
+ return validator.validate();
+ }
+
+ private boolean validateOnlyOneCreatorAnnotation(
+ ImmutableSet<ComponentCreatorAnnotation> creatorAnnotations,
+ ValidationReport.Builder<?> report) {
+ // creatorAnnotations should never be empty because this should only ever be called for
+ // types that have been found to have some creator annotation
+ if (creatorAnnotations.size() > 1) {
+ String error =
+ "May not have more than one component Factory or Builder annotation on a type"
+ + ": found "
+ + creatorAnnotations;
+ report.addError(error);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Validator for a single {@link TypeElement} that is annotated with a {@code Builder} or {@code
+ * Factory} annotation.
+ */
+ private final class ElementValidator {
+ private final TypeElement type;
+ private final Element component;
+ private final ValidationReport.Builder<TypeElement> report;
+ private final ComponentCreatorAnnotation annotation;
+ private final ComponentCreatorMessages messages;
+
+ private ElementValidator(
+ TypeElement type,
+ ValidationReport.Builder<TypeElement> report,
+ ComponentCreatorAnnotation annotation) {
+ this.type = type;
+ this.component = type.getEnclosingElement();
+ this.report = report;
+ this.annotation = annotation;
+ this.messages = ErrorMessages.creatorMessagesFor(annotation);
+ }
+
+ /** Validates the creator type. */
+ final ValidationReport<TypeElement> validate() {
+ if (!isAnnotationPresent(component, annotation.componentAnnotation())) {
+ report.addError(messages.mustBeInComponent());
+ }
+
+ // If the type isn't a class or interface, don't validate anything else since the rest of the
+ // messages will be bogus.
+ if (!validateIsClassOrInterface()) {
+ return report.build();
+ }
+
+ validateTypeRequirements();
+ switch (annotation.creatorKind()) {
+ case FACTORY:
+ validateFactory();
+ break;
+ case BUILDER:
+ validateBuilder();
+ }
+
+ return report.build();
+ }
+
+ /** Validates that the type is a class or interface type and returns true if it is. */
+ private boolean validateIsClassOrInterface() {
+ switch (type.getKind()) {
+ case CLASS:
+ validateConstructor();
+ return true;
+ case INTERFACE:
+ return true;
+ default:
+ report.addError(messages.mustBeClassOrInterface());
+ }
+ return false;
+ }
+
+ private void validateConstructor() {
+ List<? extends Element> allElements = type.getEnclosedElements();
+ List<ExecutableElement> constructors = ElementFilter.constructorsIn(allElements);
+
+ boolean valid = true;
+ if (constructors.size() != 1) {
+ valid = false;
+ } else {
+ ExecutableElement constructor = getOnlyElement(constructors);
+ valid =
+ constructor.getParameters().isEmpty() && !constructor.getModifiers().contains(PRIVATE);
+ }
+
+ if (!valid) {
+ report.addError(messages.invalidConstructor());
+ }
+ }
+
+ /** Validates basic requirements about the type that are common to both creator kinds. */
+ private void validateTypeRequirements() {
+ if (!type.getTypeParameters().isEmpty()) {
+ report.addError(messages.generics());
+ }
+
+ Set<Modifier> modifiers = type.getModifiers();
+ if (modifiers.contains(PRIVATE)) {
+ report.addError(messages.isPrivate());
+ }
+ if (!modifiers.contains(STATIC)) {
+ report.addError(messages.mustBeStatic());
+ }
+ // Note: Must be abstract, so no need to check for final.
+ if (!modifiers.contains(ABSTRACT)) {
+ report.addError(messages.mustBeAbstract());
+ }
+ }
+
+ private void validateBuilder() {
+ ExecutableElement buildMethod = null;
+ for (ExecutableElement method : elements.getUnimplementedMethods(type)) {
+ switch (method.getParameters().size()) {
+ case 0: // If this is potentially a build() method, validate it returns the correct type.
+ if (validateFactoryMethodReturnType(method)) {
+ if (buildMethod != null) {
+ // If we found more than one build-like method, fail.
+ error(
+ method,
+ messages.twoFactoryMethods(),
+ messages.inheritedTwoFactoryMethods(),
+ buildMethod);
+ }
+ }
+ // We set the buildMethod regardless of the return type to reduce error spam.
+ buildMethod = method;
+ break;
+
+ case 1: // If this correctly had one parameter, make sure the return types are valid.
+ validateSetterMethod(method);
+ break;
+
+ default: // more than one parameter
+ error(
+ method,
+ messages.setterMethodsMustTakeOneArg(),
+ messages.inheritedSetterMethodsMustTakeOneArg());
+ break;
+ }
+ }
+
+ if (buildMethod == null) {
+ report.addError(messages.missingFactoryMethod());
+ } else {
+ validateNotGeneric(buildMethod);
+ }
+ }
+
+ private void validateSetterMethod(ExecutableElement method) {
+ TypeMirror returnType = types.resolveExecutableType(method, type.asType()).getReturnType();
+ if (returnType.getKind() != TypeKind.VOID && !types.isSubtype(type.asType(), returnType)) {
+ error(
+ method,
+ messages.setterMethodsMustReturnVoidOrBuilder(),
+ messages.inheritedSetterMethodsMustReturnVoidOrBuilder());
+ }
+
+ validateNotGeneric(method);
+
+ VariableElement parameter = method.getParameters().get(0);
+
+ boolean methodIsBindsInstance = isAnnotationPresent(method, BindsInstance.class);
+ boolean parameterIsBindsInstance = isAnnotationPresent(parameter, BindsInstance.class);
+ boolean bindsInstance = methodIsBindsInstance || parameterIsBindsInstance;
+
+ if (methodIsBindsInstance && parameterIsBindsInstance) {
+ error(
+ method,
+ messages.bindsInstanceNotAllowedOnBothSetterMethodAndParameter(),
+ messages.inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter());
+ }
+
+ if (!bindsInstance && parameter.asType().getKind().isPrimitive()) {
+ error(
+ method,
+ messages.nonBindsInstanceParametersMayNotBePrimitives(),
+ messages.inheritedNonBindsInstanceParametersMayNotBePrimitives());
+ }
+ }
+
+ private void validateFactory() {
+ ImmutableList<ExecutableElement> abstractMethods =
+ elements.getUnimplementedMethods(type).asList();
+ switch (abstractMethods.size()) {
+ case 0:
+ report.addError(messages.missingFactoryMethod());
+ return;
+ case 1:
+ break; // good
+ default:
+ error(
+ abstractMethods.get(1),
+ messages.twoFactoryMethods(),
+ messages.inheritedTwoFactoryMethods(),
+ abstractMethods.get(0));
+ return;
+ }
+
+ validateFactoryMethod(getOnlyElement(abstractMethods));
+ }
+
+ /** Validates that the given {@code method} is a valid component factory method. */
+ private void validateFactoryMethod(ExecutableElement method) {
+ validateNotGeneric(method);
+
+ if (!validateFactoryMethodReturnType(method)) {
+ // If we can't determine that the single method is a valid factory method, don't bother
+ // validating its parameters.
+ return;
+ }
+
+ for (VariableElement parameter : method.getParameters()) {
+ if (!isAnnotationPresent(parameter, BindsInstance.class)
+ && parameter.asType().getKind().isPrimitive()) {
+ error(
+ method,
+ messages.nonBindsInstanceParametersMayNotBePrimitives(),
+ messages.inheritedNonBindsInstanceParametersMayNotBePrimitives());
+ }
+ }
+ }
+
+ /**
+ * Validates that the factory method that actually returns a new component instance. Returns
+ * true if the return type was valid.
+ */
+ private boolean validateFactoryMethodReturnType(ExecutableElement method) {
+ TypeMirror returnType = types.resolveExecutableType(method, type.asType()).getReturnType();
+
+ if (!types.isSubtype(component.asType(), returnType)) {
+ error(
+ method,
+ messages.factoryMethodMustReturnComponentType(),
+ messages.inheritedFactoryMethodMustReturnComponentType());
+ return false;
+ }
+
+ if (isAnnotationPresent(method, BindsInstance.class)) {
+ error(
+ method,
+ messages.factoryMethodMayNotBeAnnotatedWithBindsInstance(),
+ messages.inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance());
+ return false;
+ }
+
+ TypeElement componentType = MoreElements.asType(component);
+ if (!types.isSameType(componentType.asType(), returnType)) {
+ ImmutableSet<ExecutableElement> methodsOnlyInComponent =
+ methodsOnlyInComponent(componentType);
+ if (!methodsOnlyInComponent.isEmpty()) {
+ report.addWarning(
+ messages.factoryMethodReturnsSupertypeWithMissingMethods(
+ componentType, type, returnType, method, methodsOnlyInComponent),
+ method);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Generates one of two error messages. If the method is enclosed in the subject, we target the
+ * error to the method itself. Otherwise we target the error to the subject and list the method
+ * as an argument. (Otherwise we have no way of knowing if the method is being compiled in this
+ * pass too, so javac might not be able to pinpoint it's line of code.)
+ */
+ /*
+ * For Component.Builder, the prototypical example would be if someone had:
+ * libfoo: interface SharedBuilder { void badSetter(A a, B b); }
+ * libbar: BarComponent { BarBuilder extends SharedBuilder } }
+ * ... the compiler only validates BarBuilder when compiling libbar, but it fails because
+ * of libfoo's SharedBuilder (which could have been compiled in a previous pass).
+ * So we can't point to SharedBuilder#badSetter as the subject of the BarBuilder validation
+ * failure.
+ *
+ * This check is a little more strict than necessary -- ideally we'd check if method's enclosing
+ * class was included in this compile run. But that's hard, and this is close enough.
+ */
+ private void error(
+ ExecutableElement method,
+ String enclosedError,
+ String inheritedError,
+ Object... extraArgs) {
+ if (method.getEnclosingElement().equals(type)) {
+ report.addError(String.format(enclosedError, extraArgs), method);
+ } else {
+ report.addError(String.format(inheritedError, ObjectArrays.concat(extraArgs, method)));
+ }
+ }
+
+ /** Validates that the given {@code method} is not generic. * */
+ private void validateNotGeneric(ExecutableElement method) {
+ if (!method.getTypeParameters().isEmpty()) {
+ error(
+ method,
+ messages.methodsMayNotHaveTypeParameters(),
+ messages.inheritedMethodsMayNotHaveTypeParameters());
+ }
+ }
+
+ /**
+ * Returns all methods defind in {@code componentType} which are not inherited from a supertype.
+ */
+ private ImmutableSet<ExecutableElement> methodsOnlyInComponent(TypeElement componentType) {
+ // TODO(ronshapiro): Ideally this shouldn't return methods which are redeclared from a
+ // supertype, but do not change the return type. We don't have a good/simple way of checking
+ // that, and it doesn't seem likely, so the warning won't be too bad.
+ return ImmutableSet.copyOf(methodsIn(componentType.getEnclosedElements()));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentDescriptor.java b/java/dagger/internal/codegen/ComponentDescriptor.java
new file mode 100644
index 0000000..769cc4c
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentDescriptor.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.DaggerStreams.toImmutableMap;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.type.TypeKind.VOID;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.Component;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.Scope;
+import dagger.producers.CancellationPolicy;
+import dagger.producers.ProductionComponent;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A component declaration.
+ *
+ * <p>Represents one type annotated with {@code @Component}, {@code Subcomponent},
+ * {@code @ProductionComponent}, or {@code @ProductionSubcomponent}.
+ *
+ * <p>When validating bindings installed in modules, a {@link ComponentDescriptor} can also
+ * represent a synthetic component for the module, where there is an entry point for each binding in
+ * the module.
+ */
+@AutoValue
+abstract class ComponentDescriptor {
+ /** The annotation that specifies that {@link #typeElement()} is a component. */
+ abstract ComponentAnnotation annotation();
+
+ /** Returns {@code true} if this is a subcomponent. */
+ final boolean isSubcomponent() {
+ return annotation().isSubcomponent();
+ }
+
+ /**
+ * Returns {@code true} if this is a production component or subcomponent, or a
+ * {@code @ProducerModule} when doing module binding validation.
+ */
+ final boolean isProduction() {
+ return annotation().isProduction();
+ }
+
+ /**
+ * Returns {@code true} if this is a real component, and not a fictional one used to validate
+ * module bindings.
+ */
+ final boolean isRealComponent() {
+ return annotation().isRealComponent();
+ }
+
+ /**
+ * The element that defines the component. This is the element to which the {@link #annotation()}
+ * was applied.
+ */
+ abstract TypeElement typeElement();
+
+ /**
+ * The set of component dependencies listed in {@link Component#dependencies} or {@link
+ * ProductionComponent#dependencies()}.
+ */
+ abstract ImmutableSet<ComponentRequirement> dependencies();
+
+ /** The non-abstract {@link #modules()} and the {@link #dependencies()}. */
+ final ImmutableSet<ComponentRequirement> dependenciesAndConcreteModules() {
+ return Stream.concat(
+ moduleTypes().stream()
+ .filter(dep -> !dep.getModifiers().contains(ABSTRACT))
+ .map(module -> ComponentRequirement.forModule(module.asType())),
+ dependencies().stream())
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by
+ * traversing {@link Module#includes()}.
+ */
+ abstract ImmutableSet<ModuleDescriptor> modules();
+
+ /** The types of the {@link #modules()}. */
+ final ImmutableSet<TypeElement> moduleTypes() {
+ return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
+ }
+
+ /**
+ * The types for which the component will need instances if all of its bindings are used. For the
+ * types the component will need in a given binding graph, use {@link
+ * BindingGraph#componentRequirements()}.
+ *
+ * <ul>
+ * <li>{@linkplain #modules()} modules} with concrete instance bindings
+ * <li>Bound instances
+ * <li>{@linkplain #dependencies() dependencies}
+ * </ul>
+ */
+ @Memoized
+ ImmutableSet<ComponentRequirement> requirements() {
+ ImmutableSet.Builder<ComponentRequirement> requirements = ImmutableSet.builder();
+ modules().stream()
+ .filter(
+ module ->
+ module.bindings().stream().anyMatch(ContributionBinding::requiresModuleInstance))
+ .map(module -> ComponentRequirement.forModule(module.moduleElement().asType()))
+ .forEach(requirements::add);
+ requirements.addAll(dependencies());
+ requirements.addAll(
+ creatorDescriptor()
+ .map(ComponentCreatorDescriptor::boundInstanceRequirements)
+ .orElse(ImmutableSet.of()));
+ return requirements.build();
+ }
+
+ /**
+ * This component's {@linkplain #dependencies() dependencies} keyed by each provision or
+ * production method defined by that dependency. Note that the dependencies' types are not simply
+ * the enclosing type of the method; a method may be declared by a supertype of the actual
+ * dependency.
+ */
+ abstract ImmutableMap<ExecutableElement, ComponentRequirement> dependenciesByDependencyMethod();
+
+ /** The {@linkplain #dependencies() component dependency} that defines a method. */
+ final ComponentRequirement getDependencyThatDefinesMethod(Element method) {
+ checkArgument(
+ method instanceof ExecutableElement, "method must be an executable element: %s", method);
+ return checkNotNull(
+ dependenciesByDependencyMethod().get(method), "no dependency implements %s", method);
+ }
+
+ /**
+ * The scopes of the component.
+ */
+ abstract ImmutableSet<Scope> scopes();
+
+ /**
+ * All {@link Subcomponent}s which are direct children of this component. This includes
+ * subcomponents installed from {@link Module#subcomponents()} as well as subcomponent {@linkplain
+ * #childComponentsDeclaredByFactoryMethods() factory methods} and {@linkplain
+ * #childComponentsDeclaredByBuilderEntryPoints() builder methods}.
+ */
+ final ImmutableSet<ComponentDescriptor> childComponents() {
+ return ImmutableSet.<ComponentDescriptor>builder()
+ .addAll(childComponentsDeclaredByFactoryMethods().values())
+ .addAll(childComponentsDeclaredByBuilderEntryPoints().values())
+ .addAll(childComponentsDeclaredByModules())
+ .build();
+ }
+
+ /**
+ * All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain
+ * Module#subcomponents() module's subcomponents}.
+ */
+ abstract ImmutableSet<ComponentDescriptor> childComponentsDeclaredByModules();
+
+ /**
+ * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
+ * factory method.
+ */
+ abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
+ childComponentsDeclaredByFactoryMethods();
+
+ /** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */
+ @Memoized
+ ImmutableMap<TypeElement, ComponentDescriptor> childComponentsByElement() {
+ return Maps.uniqueIndex(childComponents(), ComponentDescriptor::typeElement);
+ }
+
+ /** Returns the factory method that declares a child component. */
+ final Optional<ComponentMethodDescriptor> getFactoryMethodForChildComponent(
+ ComponentDescriptor childComponent) {
+ return Optional.ofNullable(
+ childComponentsDeclaredByFactoryMethods().inverse().get(childComponent));
+ }
+
+ /**
+ * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
+ * builder method.
+ */
+ abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
+ childComponentsDeclaredByBuilderEntryPoints();
+
+ private final Supplier<ImmutableMap<TypeElement, ComponentDescriptor>>
+ childComponentsByBuilderType =
+ Suppliers.memoize(
+ () ->
+ childComponents().stream()
+ .filter(child -> child.creatorDescriptor().isPresent())
+ .collect(
+ toImmutableMap(
+ child -> child.creatorDescriptor().get().typeElement(),
+ child -> child)));
+
+ /** Returns the child component with the given builder type. */
+ final ComponentDescriptor getChildComponentWithBuilderType(TypeElement builderType) {
+ return checkNotNull(
+ childComponentsByBuilderType.get().get(builderType),
+ "no child component found for builder type %s",
+ builderType.getQualifiedName());
+ }
+
+ abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
+
+ /** Returns the first component method associated with this binding request, if one exists. */
+ Optional<ComponentMethodDescriptor> firstMatchingComponentMethod(BindingRequest request) {
+ return componentMethods().stream()
+ .filter(method -> doesComponentMethodMatch(method, request))
+ .findFirst();
+ }
+
+ /** Returns true if the component method matches the binding request. */
+ private static boolean doesComponentMethodMatch(
+ ComponentMethodDescriptor componentMethod, BindingRequest request) {
+ return componentMethod
+ .dependencyRequest()
+ .map(BindingRequest::bindingRequest)
+ .filter(request::equals)
+ .isPresent();
+ }
+
+ /** The entry point methods on the component type. Each has a {@link DependencyRequest}. */
+ final ImmutableSet<ComponentMethodDescriptor> entryPointMethods() {
+ return componentMethods()
+ .stream()
+ .filter(method -> method.dependencyRequest().isPresent())
+ .collect(toImmutableSet());
+ }
+
+ // TODO(gak): Consider making this non-optional and revising the
+ // interaction between the spec & generation
+ /** Returns a descriptor for the creator type for this component type, if the user defined one. */
+ abstract Optional<ComponentCreatorDescriptor> creatorDescriptor();
+
+ /**
+ * Returns {@code true} for components that have a creator, either because the user {@linkplain
+ * #creatorDescriptor() specified one} or because it's a top-level component with an implicit
+ * builder.
+ */
+ final boolean hasCreator() {
+ return !isSubcomponent() || creatorDescriptor().isPresent();
+ }
+
+ /**
+ * Returns the {@link CancellationPolicy} for this component, or an empty optional if either the
+ * component is not a production component or no {@code CancellationPolicy} annotation is present.
+ */
+ final Optional<CancellationPolicy> cancellationPolicy() {
+ return isProduction()
+ ? Optional.ofNullable(typeElement().getAnnotation(CancellationPolicy.class))
+ : Optional.empty();
+ }
+
+ @Memoized
+ @Override
+ public int hashCode() {
+ // TODO(b/122962745): Only use typeElement().hashCode()
+ return Objects.hash(typeElement(), annotation());
+ }
+
+ // TODO(ronshapiro): simplify the equality semantics
+ @Override
+ public abstract boolean equals(Object obj);
+
+ /** A component method. */
+ @AutoValue
+ abstract static class ComponentMethodDescriptor {
+ /** The method itself. Note that this may be declared on a supertype of the component. */
+ abstract ExecutableElement methodElement();
+
+ /**
+ * The dependency request for production, provision, and subcomponent creator methods. Absent
+ * for subcomponent factory methods.
+ */
+ abstract Optional<DependencyRequest> dependencyRequest();
+
+ /** The subcomponent for subcomponent factory methods and subcomponent creator methods. */
+ abstract Optional<ComponentDescriptor> subcomponent();
+
+ /**
+ * Returns the return type of {@link #methodElement()} as resolved in the {@link
+ * ComponentDescriptor#typeElement() component type}. If there are no type variables in the
+ * return type, this is the equivalent of {@code methodElement().getReturnType()}.
+ */
+ TypeMirror resolvedReturnType(DaggerTypes types) {
+ checkState(dependencyRequest().isPresent());
+
+ TypeMirror returnType = methodElement().getReturnType();
+ if (returnType.getKind().isPrimitive() || returnType.getKind().equals(VOID)) {
+ return returnType;
+ }
+ return BindingRequest.bindingRequest(dependencyRequest().get())
+ .requestedType(dependencyRequest().get().key().type(), types);
+ }
+
+ /** A {@link ComponentMethodDescriptor}builder for a method. */
+ static Builder builder(ExecutableElement method) {
+ return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder()
+ .methodElement(method);
+ }
+
+ /** A builder of {@link ComponentMethodDescriptor}s. */
+ @AutoValue.Builder
+ @CanIgnoreReturnValue
+ interface Builder {
+ /** @see ComponentMethodDescriptor#methodElement() */
+ Builder methodElement(ExecutableElement methodElement);
+
+ /** @see ComponentMethodDescriptor#dependencyRequest() */
+ Builder dependencyRequest(DependencyRequest dependencyRequest);
+
+ /** @see ComponentMethodDescriptor#subcomponent() */
+ Builder subcomponent(ComponentDescriptor subcomponent);
+
+ /** Builds the descriptor. */
+ @CheckReturnValue
+ ComponentMethodDescriptor build();
+ }
+ }
+
+ /** No-argument methods defined on {@link Object} that are ignored for contribution. */
+ private static final ImmutableSet<String> NON_CONTRIBUTING_OBJECT_METHOD_NAMES =
+ ImmutableSet.of("toString", "hashCode", "clone", "getClass");
+
+ /**
+ * Returns {@code true} if a method could be a component entry point but not a members-injection
+ * method.
+ */
+ static boolean isComponentContributionMethod(DaggerElements elements, ExecutableElement method) {
+ return method.getParameters().isEmpty()
+ && !method.getReturnType().getKind().equals(VOID)
+ && !elements.getTypeElement(Object.class).equals(method.getEnclosingElement())
+ && !NON_CONTRIBUTING_OBJECT_METHOD_NAMES.contains(method.getSimpleName().toString());
+ }
+
+ /** Returns {@code true} if a method could be a component production entry point. */
+ static boolean isComponentProductionMethod(DaggerElements elements, ExecutableElement method) {
+ return isComponentContributionMethod(elements, method) && isFutureType(method.getReturnType());
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentDescriptorFactory.java b/java/dagger/internal/codegen/ComponentDescriptorFactory.java
new file mode 100644
index 0000000..7d87eac
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentDescriptorFactory.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.asType;
+import static com.google.auto.common.MoreTypes.asTypeElement;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ComponentAnnotation.subcomponentAnnotation;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.creatorAnnotationsFor;
+import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
+import static dagger.internal.codegen.ConfigurationAnnotations.enclosedAnnotatedTypes;
+import static dagger.internal.codegen.ConfigurationAnnotations.isSubcomponentCreator;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.Scopes.productionScope;
+import static dagger.internal.codegen.Scopes.scopesOf;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.VOID;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Scope;
+import java.util.Optional;
+import java.util.function.Function;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+/** A factory for {@link ComponentDescriptor}s. */
+final class ComponentDescriptorFactory {
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final DependencyRequestFactory dependencyRequestFactory;
+ private final ModuleDescriptor.Factory moduleDescriptorFactory;
+
+ @Inject
+ ComponentDescriptorFactory(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestFactory dependencyRequestFactory,
+ ModuleDescriptor.Factory moduleDescriptorFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ this.moduleDescriptorFactory = moduleDescriptorFactory;
+ }
+
+ /** Returns a descriptor for a root component type. */
+ ComponentDescriptor rootComponentDescriptor(TypeElement typeElement) {
+ return create(
+ typeElement,
+ checkAnnotation(
+ typeElement,
+ ComponentAnnotation::rootComponentAnnotation,
+ "must have a component annotation"));
+ }
+
+ /** Returns a descriptor for a subcomponent type. */
+ ComponentDescriptor subcomponentDescriptor(TypeElement typeElement) {
+ return create(
+ typeElement,
+ checkAnnotation(
+ typeElement,
+ ComponentAnnotation::subcomponentAnnotation,
+ "must have a subcomponent annotation"));
+ }
+
+ /**
+ * Returns a descriptor for a fictional component based on a module type in order to validate its
+ * bindings.
+ */
+ ComponentDescriptor moduleComponentDescriptor(TypeElement typeElement) {
+ return create(
+ typeElement,
+ ComponentAnnotation.fromModuleAnnotation(
+ checkAnnotation(
+ typeElement, ModuleAnnotation::moduleAnnotation, "must have a module annotation")));
+ }
+
+ private static <A> A checkAnnotation(
+ TypeElement typeElement,
+ Function<TypeElement, Optional<A>> annotationFunction,
+ String message) {
+ return annotationFunction
+ .apply(typeElement)
+ .orElseThrow(() -> new IllegalArgumentException(typeElement + " " + message));
+ }
+
+ private ComponentDescriptor create(
+ TypeElement typeElement, ComponentAnnotation componentAnnotation) {
+ ImmutableSet<ComponentRequirement> componentDependencies =
+ componentAnnotation.dependencyTypes().stream()
+ .map(ComponentRequirement::forDependency)
+ .collect(toImmutableSet());
+
+ ImmutableMap.Builder<ExecutableElement, ComponentRequirement> dependenciesByDependencyMethod =
+ ImmutableMap.builder();
+
+ for (ComponentRequirement componentDependency : componentDependencies) {
+ for (ExecutableElement dependencyMethod :
+ methodsIn(elements.getAllMembers(componentDependency.typeElement()))) {
+ if (isComponentContributionMethod(elements, dependencyMethod)) {
+ dependenciesByDependencyMethod.put(dependencyMethod, componentDependency);
+ }
+ }
+ }
+
+ // Start with the component's modules. For fictional components built from a module, start with
+ // that module.
+ ImmutableSet<TypeElement> modules =
+ componentAnnotation.isRealComponent()
+ ? componentAnnotation.modules()
+ : ImmutableSet.of(typeElement);
+
+ ImmutableSet<ModuleDescriptor> transitiveModules =
+ moduleDescriptorFactory.transitiveModules(modules);
+
+ ImmutableSet.Builder<ComponentDescriptor> subcomponentsFromModules = ImmutableSet.builder();
+ for (ModuleDescriptor module : transitiveModules) {
+ for (SubcomponentDeclaration subcomponentDeclaration : module.subcomponentDeclarations()) {
+ TypeElement subcomponent = subcomponentDeclaration.subcomponentType();
+ subcomponentsFromModules.add(subcomponentDescriptor(subcomponent));
+ }
+ }
+
+ ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
+ ImmutableSet.builder();
+ ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor>
+ subcomponentsByFactoryMethod = ImmutableBiMap.builder();
+ ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor>
+ subcomponentsByBuilderMethod = ImmutableBiMap.builder();
+ if (componentAnnotation.isRealComponent()) {
+ ImmutableSet<ExecutableElement> unimplementedMethods =
+ elements.getUnimplementedMethods(typeElement);
+ for (ExecutableElement componentMethod : unimplementedMethods) {
+ ComponentMethodDescriptor componentMethodDescriptor =
+ getDescriptorForComponentMethod(typeElement, componentAnnotation, componentMethod);
+ componentMethodsBuilder.add(componentMethodDescriptor);
+ componentMethodDescriptor
+ .subcomponent()
+ .ifPresent(
+ subcomponent -> {
+ // If the dependency request is present, that means the method returns the
+ // subcomponent factory.
+ if (componentMethodDescriptor.dependencyRequest().isPresent()) {
+ subcomponentsByBuilderMethod.put(componentMethodDescriptor, subcomponent);
+ } else {
+ subcomponentsByFactoryMethod.put(componentMethodDescriptor, subcomponent);
+ }
+ });
+ }
+ }
+
+ // Validation should have ensured that this set will have at most one element.
+ ImmutableSet<DeclaredType> enclosedCreators =
+ creatorAnnotationsFor(componentAnnotation).stream()
+ .flatMap(
+ creatorAnnotation ->
+ enclosedAnnotatedTypes(typeElement, creatorAnnotation).stream())
+ .collect(toImmutableSet());
+ Optional<ComponentCreatorDescriptor> creatorDescriptor =
+ enclosedCreators.isEmpty()
+ ? Optional.empty()
+ : Optional.of(
+ ComponentCreatorDescriptor.create(
+ getOnlyElement(enclosedCreators), elements, types, dependencyRequestFactory));
+
+ ImmutableSet<Scope> scopes = scopesOf(typeElement);
+ if (componentAnnotation.isProduction()) {
+ scopes = ImmutableSet.<Scope>builder().addAll(scopes).add(productionScope(elements)).build();
+ }
+
+ return new AutoValue_ComponentDescriptor(
+ componentAnnotation,
+ typeElement,
+ componentDependencies,
+ transitiveModules,
+ dependenciesByDependencyMethod.build(),
+ scopes,
+ subcomponentsFromModules.build(),
+ subcomponentsByFactoryMethod.build(),
+ subcomponentsByBuilderMethod.build(),
+ componentMethodsBuilder.build(),
+ creatorDescriptor);
+ }
+
+ private ComponentMethodDescriptor getDescriptorForComponentMethod(
+ TypeElement componentElement,
+ ComponentAnnotation componentAnnotation,
+ ExecutableElement componentMethod) {
+ ComponentMethodDescriptor.Builder descriptor =
+ ComponentMethodDescriptor.builder(componentMethod);
+
+ ExecutableType resolvedComponentMethod =
+ MoreTypes.asExecutable(
+ types.asMemberOf(MoreTypes.asDeclared(componentElement.asType()), componentMethod));
+ TypeMirror returnType = resolvedComponentMethod.getReturnType();
+ if (returnType.getKind().equals(DECLARED) && !getQualifier(componentMethod).isPresent()) {
+ TypeElement returnTypeElement = asTypeElement(returnType);
+ if (subcomponentAnnotation(returnTypeElement).isPresent()) {
+ // It's a subcomponent factory method. There is no dependency request, and there could be
+ // any number of parameters. Just return the descriptor.
+ return descriptor.subcomponent(subcomponentDescriptor(returnTypeElement)).build();
+ }
+ if (isSubcomponentCreator(returnTypeElement)) {
+ descriptor.subcomponent(
+ subcomponentDescriptor(asType(returnTypeElement.getEnclosingElement())));
+ }
+ }
+
+ switch (componentMethod.getParameters().size()) {
+ case 0:
+ checkArgument(
+ !returnType.getKind().equals(VOID),
+ "component method cannot be void: %s",
+ componentMethod);
+ descriptor.dependencyRequest(
+ componentAnnotation.isProduction()
+ ? dependencyRequestFactory.forComponentProductionMethod(
+ componentMethod, resolvedComponentMethod)
+ : dependencyRequestFactory.forComponentProvisionMethod(
+ componentMethod, resolvedComponentMethod));
+ break;
+
+ case 1:
+ checkArgument(
+ returnType.getKind().equals(VOID)
+ || MoreTypes.equivalence()
+ .equivalent(returnType, resolvedComponentMethod.getParameterTypes().get(0)),
+ "members injection method must return void or parameter type: %s",
+ componentMethod);
+ descriptor.dependencyRequest(
+ dependencyRequestFactory.forComponentMembersInjectionMethod(
+ componentMethod, resolvedComponentMethod));
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ "component method has too many parameters: " + componentMethod);
+ }
+
+ return descriptor.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentDescriptorValidator.java b/java/dagger/internal/codegen/ComponentDescriptorValidator.java
new file mode 100644
index 0000000..8f85b3a
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentDescriptorValidator.java
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2018 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.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.collect.Collections2.transform;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ComponentAnnotation.rootComponentAnnotation;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSetMultimap;
+import static dagger.internal.codegen.DiagnosticFormatting.stripCommonTypePrefixes;
+import static dagger.internal.codegen.Formatter.INDENT;
+import static dagger.internal.codegen.Scopes.getReadableSource;
+import static dagger.internal.codegen.Scopes.scopesOf;
+import static dagger.internal.codegen.Scopes.singletonScope;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toList;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import dagger.internal.codegen.ComponentRequirement.NullPolicy;
+import dagger.internal.codegen.ErrorMessages.ComponentCreatorMessages;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Scope;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringJoiner;
+import javax.inject.Inject;
+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.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic;
+
+/**
+ * Reports errors in the component hierarchy.
+ *
+ * <ul>
+ * <li>Validates scope hierarchy of component dependencies and subcomponents.
+ * <li>Reports errors if there are component dependency cycles.
+ * <li>Reports errors if any abstract modules have non-abstract instance binding methods.
+ * <li>Validates component creator types.
+ * </ul>
+ */
+// TODO(dpb): Combine with ComponentHierarchyValidator.
+final class ComponentDescriptorValidator {
+
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final CompilerOptions compilerOptions;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+ private final ComponentHierarchyValidator componentHierarchyValidator;
+
+ @Inject
+ ComponentDescriptorValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ CompilerOptions compilerOptions,
+ MethodSignatureFormatter methodSignatureFormatter,
+ ComponentHierarchyValidator componentHierarchyValidator) {
+ this.elements = elements;
+ this.types = types;
+ this.compilerOptions = compilerOptions;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ this.componentHierarchyValidator = componentHierarchyValidator;
+ }
+
+ ValidationReport<TypeElement> validate(ComponentDescriptor component) {
+ ComponentValidation validation = new ComponentValidation(component);
+ validation.visitComponent(component);
+ validation.report(component).addSubreport(componentHierarchyValidator.validate(component));
+ return validation.buildReport();
+ }
+
+ private final class ComponentValidation {
+ final ComponentDescriptor rootComponent;
+ final Map<ComponentDescriptor, ValidationReport.Builder<TypeElement>> reports =
+ new LinkedHashMap<>();
+
+ ComponentValidation(ComponentDescriptor rootComponent) {
+ this.rootComponent = checkNotNull(rootComponent);
+ }
+
+ /** Returns a report that contains all validation messages found during traversal. */
+ ValidationReport<TypeElement> buildReport() {
+ ValidationReport.Builder<TypeElement> report =
+ ValidationReport.about(rootComponent.typeElement());
+ reports.values().forEach(subreport -> report.addSubreport(subreport.build()));
+ return report.build();
+ }
+
+ /** Returns the report builder for a (sub)component. */
+ private ValidationReport.Builder<TypeElement> report(ComponentDescriptor component) {
+ return reentrantComputeIfAbsent(
+ reports, component, descriptor -> ValidationReport.about(descriptor.typeElement()));
+ }
+
+ private void reportComponentItem(
+ Diagnostic.Kind kind, ComponentDescriptor component, String message) {
+ report(component)
+ .addItem(message, kind, component.typeElement(), component.annotation().annotation());
+ }
+
+ private void reportComponentError(ComponentDescriptor component, String error) {
+ reportComponentItem(ERROR, component, error);
+ }
+
+ void visitComponent(ComponentDescriptor component) {
+ validateDependencyScopes(component);
+ validateComponentDependencyHierarchy(component);
+ validateModules(component);
+ validateCreators(component);
+ component.childComponents().forEach(this::visitComponent);
+ }
+
+ /** Validates that component dependencies do not form a cycle. */
+ private void validateComponentDependencyHierarchy(ComponentDescriptor component) {
+ validateComponentDependencyHierarchy(component, component.typeElement(), new ArrayDeque<>());
+ }
+
+ /** Recursive method to validate that component dependencies do not form a cycle. */
+ private void validateComponentDependencyHierarchy(
+ ComponentDescriptor component, TypeElement dependency, Deque<TypeElement> dependencyStack) {
+ if (dependencyStack.contains(dependency)) {
+ // Current component has already appeared in the component chain.
+ StringBuilder message = new StringBuilder();
+ message.append(component.typeElement().getQualifiedName());
+ message.append(" contains a cycle in its component dependencies:\n");
+ dependencyStack.push(dependency);
+ appendIndentedComponentsList(message, dependencyStack);
+ dependencyStack.pop();
+ reportComponentItem(
+ compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
+ component,
+ message.toString());
+ } else {
+ rootComponentAnnotation(dependency)
+ .ifPresent(
+ componentAnnotation -> {
+ dependencyStack.push(dependency);
+
+ for (TypeElement nextDependency : componentAnnotation.dependencies()) {
+ validateComponentDependencyHierarchy(
+ component, nextDependency, dependencyStack);
+ }
+
+ dependencyStack.pop();
+ });
+ }
+ }
+
+ /**
+ * Validates that among the dependencies are at most one scoped dependency, that there are no
+ * cycles within the scoping chain, and that singleton components have no scoped dependencies.
+ */
+ private void validateDependencyScopes(ComponentDescriptor component) {
+ ImmutableSet<Scope> scopes = component.scopes();
+ ImmutableSet<TypeElement> scopedDependencies =
+ scopedTypesIn(
+ component
+ .dependencies()
+ .stream()
+ .map(ComponentRequirement::typeElement)
+ .collect(toImmutableSet()));
+ if (!scopes.isEmpty()) {
+ Scope singletonScope = singletonScope(elements);
+ // Dagger 1.x scope compatibility requires this be suppress-able.
+ if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()
+ && scopes.contains(singletonScope)) {
+ // Singleton is a special-case representing the longest lifetime, and therefore
+ // @Singleton components may not depend on scoped components
+ if (!scopedDependencies.isEmpty()) {
+ StringBuilder message =
+ new StringBuilder(
+ "This @Singleton component cannot depend on scoped components:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportComponentItem(
+ compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
+ component,
+ message.toString());
+ }
+ } else if (scopedDependencies.size() > 1) {
+ // Scoped components may depend on at most one scoped component.
+ StringBuilder message = new StringBuilder();
+ for (Scope scope : scopes) {
+ message.append(getReadableSource(scope)).append(' ');
+ }
+ message
+ .append(component.typeElement().getQualifiedName())
+ .append(" depends on more than one scoped component:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportComponentError(component, message.toString());
+ } else {
+ // Dagger 1.x scope compatibility requires this be suppress-able.
+ if (!compilerOptions.scopeCycleValidationType().equals(ValidationType.NONE)) {
+ validateDependencyScopeHierarchy(
+ component, component.typeElement(), new ArrayDeque<>(), new ArrayDeque<>());
+ }
+ }
+ } else {
+ // Scopeless components may not depend on scoped components.
+ if (!scopedDependencies.isEmpty()) {
+ StringBuilder message =
+ new StringBuilder(component.typeElement().getQualifiedName())
+ .append(" (unscoped) cannot depend on scoped components:\n");
+ appendIndentedComponentsList(message, scopedDependencies);
+ reportComponentError(component, message.toString());
+ }
+ }
+ }
+
+ private void validateModules(ComponentDescriptor component) {
+ for (ModuleDescriptor module : component.modules()) {
+ if (module.moduleElement().getModifiers().contains(Modifier.ABSTRACT)) {
+ for (ContributionBinding binding : module.bindings()) {
+ if (binding.requiresModuleInstance()) {
+ report(component).addError(abstractModuleHasInstanceBindingMethodsError(module));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private String abstractModuleHasInstanceBindingMethodsError(ModuleDescriptor module) {
+ String methodAnnotations;
+ switch (module.kind()) {
+ case MODULE:
+ methodAnnotations = "@Provides";
+ break;
+ case PRODUCER_MODULE:
+ methodAnnotations = "@Provides or @Produces";
+ break;
+ default:
+ throw new AssertionError(module.kind());
+ }
+ return String.format(
+ "%s is abstract and has instance %s methods. Consider making the methods static or "
+ + "including a non-abstract subclass of the module instead.",
+ module.moduleElement(), methodAnnotations);
+ }
+
+ private void validateCreators(ComponentDescriptor component) {
+ if (!component.creatorDescriptor().isPresent()) {
+ // If no builder, nothing to validate.
+ return;
+ }
+
+ ComponentCreatorDescriptor creator = component.creatorDescriptor().get();
+ ComponentCreatorMessages messages = ErrorMessages.creatorMessagesFor(creator.annotation());
+
+ // Requirements for modules and dependencies that the creator can set
+ Set<ComponentRequirement> creatorModuleAndDependencyRequirements =
+ creator.moduleAndDependencyRequirements();
+ // Modules and dependencies the component requires
+ Set<ComponentRequirement> componentModuleAndDependencyRequirements =
+ component.dependenciesAndConcreteModules();
+
+ // Requirements that the creator can set that don't match any requirements that the component
+ // actually has.
+ Set<ComponentRequirement> inapplicableRequirementsOnCreator =
+ Sets.difference(
+ creatorModuleAndDependencyRequirements, componentModuleAndDependencyRequirements);
+
+ DeclaredType container = asDeclared(creator.typeElement().asType());
+ if (!inapplicableRequirementsOnCreator.isEmpty()) {
+ Collection<Element> excessElements =
+ Multimaps.filterKeys(
+ creator.unvalidatedRequirementElements(), in(inapplicableRequirementsOnCreator))
+ .values();
+ String formatted =
+ excessElements.stream()
+ .map(element -> formatElement(element, container))
+ .collect(joining(", ", "[", "]"));
+ report(component)
+ .addError(String.format(messages.extraSetters(), formatted), creator.typeElement());
+ }
+
+ // Component requirements that the creator must be able to set
+ Set<ComponentRequirement> mustBePassed =
+ Sets.filter(
+ componentModuleAndDependencyRequirements,
+ input -> input.nullPolicy(elements, types).equals(NullPolicy.THROW));
+ // Component requirements that the creator must be able to set, but can't
+ Set<ComponentRequirement> missingRequirements =
+ Sets.difference(mustBePassed, creatorModuleAndDependencyRequirements);
+
+ if (!missingRequirements.isEmpty()) {
+ report(component)
+ .addError(
+ String.format(
+ messages.missingSetters(),
+ missingRequirements.stream().map(ComponentRequirement::type).collect(toList())),
+ creator.typeElement());
+ }
+
+ // Validate that declared creator requirements (modules, dependencies) have unique types.
+ ImmutableSetMultimap<Wrapper<TypeMirror>, Element> declaredRequirementsByType =
+ Multimaps.filterKeys(
+ creator.unvalidatedRequirementElements(),
+ creatorModuleAndDependencyRequirements::contains)
+ .entries().stream()
+ .collect(
+ toImmutableSetMultimap(entry -> entry.getKey().wrappedType(), Entry::getValue));
+ declaredRequirementsByType
+ .asMap()
+ .forEach(
+ (typeWrapper, elementsForType) -> {
+ if (elementsForType.size() > 1) {
+ TypeMirror type = typeWrapper.get();
+ // TODO(cgdecker): Attach this error message to the factory method rather than
+ // the component type if the elements are factory method parameters AND the
+ // factory method is defined by the factory type itself and not by a supertype.
+ report(component)
+ .addError(
+ String.format(
+ messages.multipleSettersForModuleOrDependencyType(),
+ type,
+ transform(
+ elementsForType, element -> formatElement(element, container))),
+ creator.typeElement());
+ }
+ });
+
+ // TODO(cgdecker): Duplicate binding validation should handle the case of multiple elements
+ // that set the same bound-instance Key, but validating that here would make it fail faster
+ // for subcomponents.
+ }
+
+ private String formatElement(Element element, DeclaredType container) {
+ // TODO(cgdecker): Extract some or all of this to another class?
+ // But note that it does different formatting for parameters than
+ // DaggerElements.elementToString(Element).
+ switch (element.getKind()) {
+ case METHOD:
+ return methodSignatureFormatter.format(
+ MoreElements.asExecutable(element), Optional.of(container));
+ case PARAMETER:
+ return formatParameter(MoreElements.asVariable(element), container);
+ default:
+ // This method shouldn't be called with any other type of element.
+ throw new AssertionError();
+ }
+ }
+
+ private String formatParameter(VariableElement parameter, DeclaredType container) {
+ // TODO(cgdecker): Possibly leave the type (and annotations?) off of the parameters here and
+ // just use their names, since the type will be redundant in the context of the error message.
+ StringJoiner joiner = new StringJoiner(" ");
+ parameter.getAnnotationMirrors().stream().map(Object::toString).forEach(joiner::add);
+ TypeMirror parameterType = resolveParameterType(parameter, container);
+ return joiner
+ .add(stripCommonTypePrefixes(parameterType.toString()))
+ .add(parameter.getSimpleName())
+ .toString();
+ }
+
+ private TypeMirror resolveParameterType(VariableElement parameter, DeclaredType container) {
+ ExecutableElement method =
+ MoreElements.asExecutable(parameter.getEnclosingElement());
+ int parameterIndex = method.getParameters().indexOf(parameter);
+
+ ExecutableType methodType = MoreTypes.asExecutable(types.asMemberOf(container, method));
+ return methodType.getParameterTypes().get(parameterIndex);
+ }
+
+ /**
+ * Validates that scopes do not participate in a scoping cycle - that is to say, scoped
+ * components are in a hierarchical relationship terminating with Singleton.
+ *
+ * <p>As a side-effect, this means scoped components cannot have a dependency cycle between
+ * themselves, since a component's presence within its own dependency path implies a cyclical
+ * relationship between scopes. However, cycles in component dependencies are explicitly checked
+ * in {@link #validateComponentDependencyHierarchy(ComponentDescriptor)}.
+ */
+ private void validateDependencyScopeHierarchy(
+ ComponentDescriptor component,
+ TypeElement dependency,
+ Deque<ImmutableSet<Scope>> scopeStack,
+ Deque<TypeElement> scopedDependencyStack) {
+ ImmutableSet<Scope> scopes = scopesOf(dependency);
+ if (stackOverlaps(scopeStack, scopes)) {
+ scopedDependencyStack.push(dependency);
+ // Current scope has already appeared in the component chain.
+ StringBuilder message = new StringBuilder();
+ message.append(component.typeElement().getQualifiedName());
+ message.append(" depends on scoped components in a non-hierarchical scope ordering:\n");
+ appendIndentedComponentsList(message, scopedDependencyStack);
+ if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()) {
+ reportComponentItem(
+ compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
+ component,
+ message.toString());
+ }
+ scopedDependencyStack.pop();
+ } else {
+ // TODO(beder): transitively check scopes of production components too.
+ rootComponentAnnotation(dependency)
+ .filter(componentAnnotation -> !componentAnnotation.isProduction())
+ .ifPresent(
+ componentAnnotation -> {
+ ImmutableSet<TypeElement> scopedDependencies =
+ scopedTypesIn(componentAnnotation.dependencies());
+ if (scopedDependencies.size() == 1) {
+ // empty can be ignored (base-case), and > 1 is a separately-reported error.
+ scopeStack.push(scopes);
+ scopedDependencyStack.push(dependency);
+ validateDependencyScopeHierarchy(
+ component,
+ getOnlyElement(scopedDependencies),
+ scopeStack,
+ scopedDependencyStack);
+ scopedDependencyStack.pop();
+ scopeStack.pop();
+ }
+ }); // else: we skip component dependencies which are not components
+ }
+ }
+
+ private <T> boolean stackOverlaps(Deque<ImmutableSet<T>> stack, ImmutableSet<T> set) {
+ for (ImmutableSet<T> entry : stack) {
+ if (!Sets.intersection(entry, set).isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Appends and formats a list of indented component types (with their scope annotations). */
+ private void appendIndentedComponentsList(StringBuilder message, Iterable<TypeElement> types) {
+ for (TypeElement scopedComponent : types) {
+ message.append(INDENT);
+ for (Scope scope : scopesOf(scopedComponent)) {
+ message.append(getReadableSource(scope)).append(' ');
+ }
+ message
+ .append(stripCommonTypePrefixes(scopedComponent.getQualifiedName().toString()))
+ .append('\n');
+ }
+ }
+
+ /**
+ * Returns a set of type elements containing only those found in the input set that have a
+ * scoping annotation.
+ */
+ private ImmutableSet<TypeElement> scopedTypesIn(Collection<TypeElement> types) {
+ return types.stream().filter(type -> !scopesOf(type).isEmpty()).collect(toImmutableSet());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentGenerator.java b/java/dagger/internal/codegen/ComponentGenerator.java
new file mode 100644
index 0000000..330ec2d
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentGenerator.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.SourceFiles.classFileName;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.Component;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Generates the implementation of the abstract types annotated with {@link Component}.
+ */
+final class ComponentGenerator extends SourceFileGenerator<BindingGraph> {
+ private final ComponentImplementationFactory componentImplementationFactory;
+
+ @Inject
+ ComponentGenerator(
+ Filer filer,
+ DaggerElements elements,
+ SourceVersion sourceVersion,
+ ComponentImplementationFactory componentImplementationFactory) {
+ super(filer, elements, sourceVersion);
+ this.componentImplementationFactory = componentImplementationFactory;
+ }
+
+ @Override
+ ClassName nameGeneratedType(BindingGraph input) {
+ return componentName(input.componentTypeElement());
+ }
+
+ static ClassName componentName(TypeElement componentDefinitionType) {
+ ClassName componentName = ClassName.get(componentDefinitionType);
+ return ClassName.get(componentName.packageName(), "Dagger" + classFileName(componentName));
+ }
+
+ @Override
+ Element originatingElement(BindingGraph input) {
+ return input.componentTypeElement();
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName componentName, BindingGraph bindingGraph) {
+ ComponentImplementation componentImplementation =
+ componentImplementationFactory.createComponentImplementation(bindingGraph);
+ verify(componentImplementation.name().equals(componentName));
+ return Optional.of(componentImplementation.generate());
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentHierarchyValidator.java b/java/dagger/internal/codegen/ComponentHierarchyValidator.java
new file mode 100644
index 0000000..d1e5333
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentHierarchyValidator.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Functions.constant;
+import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.base.Predicates.not;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.Scopes.getReadableSource;
+import static dagger.internal.codegen.Scopes.uniqueScopeOf;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.model.Scope;
+import java.util.Collection;
+import java.util.Formatter;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+
+/** Validates the relationships between parent components and subcomponents. */
+final class ComponentHierarchyValidator {
+ private static final Joiner COMMA_SEPARATED_JOINER = Joiner.on(", ");
+ private final CompilerOptions compilerOptions;
+
+ @Inject
+ ComponentHierarchyValidator(CompilerOptions compilerOptions) {
+ this.compilerOptions = compilerOptions;
+ }
+
+ ValidationReport<TypeElement> validate(ComponentDescriptor componentDescriptor) {
+ ValidationReport.Builder<TypeElement> report =
+ ValidationReport.about(componentDescriptor.typeElement());
+ validateSubcomponentMethods(
+ report,
+ componentDescriptor,
+ Maps.toMap(componentDescriptor.moduleTypes(), constant(componentDescriptor.typeElement())));
+ validateRepeatedScopedDeclarations(report, componentDescriptor, LinkedHashMultimap.create());
+
+ if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()) {
+ validateScopeHierarchy(
+ report, componentDescriptor, LinkedHashMultimap.<ComponentDescriptor, Scope>create());
+ }
+ validateProductionModuleUniqueness(report, componentDescriptor, LinkedHashMultimap.create());
+ return report.build();
+ }
+
+ private void validateSubcomponentMethods(
+ ValidationReport.Builder<?> report,
+ ComponentDescriptor componentDescriptor,
+ ImmutableMap<TypeElement, TypeElement> existingModuleToOwners) {
+ componentDescriptor
+ .childComponentsDeclaredByFactoryMethods()
+ .forEach(
+ (method, childComponent) -> {
+ if (childComponent.hasCreator()) {
+ report.addError(
+ "Components may not have factory methods for subcomponents that define a "
+ + "builder.",
+ method.methodElement());
+ } else {
+ validateFactoryMethodParameters(report, method, existingModuleToOwners);
+ }
+
+ validateSubcomponentMethods(
+ report,
+ childComponent,
+ new ImmutableMap.Builder<TypeElement, TypeElement>()
+ .putAll(existingModuleToOwners)
+ .putAll(
+ Maps.toMap(
+ Sets.difference(
+ childComponent.moduleTypes(), existingModuleToOwners.keySet()),
+ constant(childComponent.typeElement())))
+ .build());
+ });
+ }
+
+ private void validateFactoryMethodParameters(
+ ValidationReport.Builder<?> report,
+ ComponentMethodDescriptor subcomponentMethodDescriptor,
+ ImmutableMap<TypeElement, TypeElement> existingModuleToOwners) {
+ for (VariableElement factoryMethodParameter :
+ subcomponentMethodDescriptor.methodElement().getParameters()) {
+ TypeElement moduleType = MoreTypes.asTypeElement(factoryMethodParameter.asType());
+ TypeElement originatingComponent = existingModuleToOwners.get(moduleType);
+ if (originatingComponent != null) {
+ /* Factory method tries to pass a module that is already present in the parent.
+ * This is an error. */
+ report.addError(
+ String.format(
+ "%s is present in %s. A subcomponent cannot use an instance of a "
+ + "module that differs from its parent.",
+ moduleType.getSimpleName(), originatingComponent.getQualifiedName()),
+ factoryMethodParameter);
+ }
+ }
+ }
+
+ /**
+ * Checks that components do not have any scopes that are also applied on any of their ancestors.
+ */
+ private void validateScopeHierarchy(
+ ValidationReport.Builder<TypeElement> report,
+ ComponentDescriptor subject,
+ SetMultimap<ComponentDescriptor, Scope> scopesByComponent) {
+ scopesByComponent.putAll(subject, subject.scopes());
+
+ for (ComponentDescriptor childComponent : subject.childComponents()) {
+ validateScopeHierarchy(report, childComponent, scopesByComponent);
+ }
+
+ scopesByComponent.removeAll(subject);
+
+ Predicate<Scope> subjectScopes =
+ subject.isProduction()
+ // TODO(beder): validate that @ProductionScope is only applied on production components
+ ? and(in(subject.scopes()), not(Scope::isProductionScope))
+ : in(subject.scopes());
+ SetMultimap<ComponentDescriptor, Scope> overlappingScopes =
+ Multimaps.filterValues(scopesByComponent, subjectScopes);
+ if (!overlappingScopes.isEmpty()) {
+ StringBuilder error =
+ new StringBuilder()
+ .append(subject.typeElement().getQualifiedName())
+ .append(" has conflicting scopes:");
+ for (Map.Entry<ComponentDescriptor, Scope> entry : overlappingScopes.entries()) {
+ Scope scope = entry.getValue();
+ error
+ .append("\n ")
+ .append(entry.getKey().typeElement().getQualifiedName())
+ .append(" also has ")
+ .append(getReadableSource(scope));
+ }
+ report.addItem(
+ error.toString(),
+ compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
+ subject.typeElement());
+ }
+ }
+
+ private void validateProductionModuleUniqueness(
+ ValidationReport.Builder<TypeElement> report,
+ ComponentDescriptor componentDescriptor,
+ SetMultimap<ComponentDescriptor, ModuleDescriptor> producerModulesByComponent) {
+ ImmutableSet<ModuleDescriptor> producerModules =
+ componentDescriptor.modules().stream()
+ .filter(module -> module.kind().equals(ModuleKind.PRODUCER_MODULE))
+ .collect(toImmutableSet());
+
+ producerModulesByComponent.putAll(componentDescriptor, producerModules);
+ for (ComponentDescriptor childComponent : componentDescriptor.childComponents()) {
+ validateProductionModuleUniqueness(report, childComponent, producerModulesByComponent);
+ }
+ producerModulesByComponent.removeAll(componentDescriptor);
+
+ SetMultimap<ComponentDescriptor, ModuleDescriptor> repeatedModules =
+ Multimaps.filterValues(producerModulesByComponent, producerModules::contains);
+ if (repeatedModules.isEmpty()) {
+ return;
+ }
+
+ StringBuilder error = new StringBuilder();
+ Formatter formatter = new Formatter(error);
+
+ formatter.format("%s repeats @ProducerModules:", componentDescriptor.typeElement());
+
+ for (Map.Entry<ComponentDescriptor, Collection<ModuleDescriptor>> entry :
+ repeatedModules.asMap().entrySet()) {
+ formatter.format("\n %s also installs: ", entry.getKey().typeElement());
+ COMMA_SEPARATED_JOINER
+ .appendTo(error, Iterables.transform(entry.getValue(), m -> m.moduleElement()));
+ }
+
+ report.addError(error.toString());
+ }
+
+ private void validateRepeatedScopedDeclarations(
+ ValidationReport.Builder<TypeElement> report,
+ ComponentDescriptor component,
+ // TODO(ronshapiro): optimize ModuleDescriptor.hashCode()/equals. Otherwise this could be
+ // quite costly
+ SetMultimap<ComponentDescriptor, ModuleDescriptor> modulesWithScopes) {
+ ImmutableSet<ModuleDescriptor> modules =
+ component.modules().stream().filter(this::hasScopedDeclarations).collect(toImmutableSet());
+ modulesWithScopes.putAll(component, modules);
+ for (ComponentDescriptor childComponent : component.childComponents()) {
+ validateRepeatedScopedDeclarations(report, childComponent, modulesWithScopes);
+ }
+ modulesWithScopes.removeAll(component);
+
+ SetMultimap<ComponentDescriptor, ModuleDescriptor> repeatedModules =
+ Multimaps.filterValues(modulesWithScopes, modules::contains);
+ if (repeatedModules.isEmpty()) {
+ return;
+ }
+
+ report.addError(
+ repeatedModulesWithScopeError(component, ImmutableSetMultimap.copyOf(repeatedModules)));
+ }
+
+ private boolean hasScopedDeclarations(ModuleDescriptor module) {
+ return !moduleScopes(module).isEmpty();
+ }
+
+ private String repeatedModulesWithScopeError(
+ ComponentDescriptor component,
+ ImmutableSetMultimap<ComponentDescriptor, ModuleDescriptor> repeatedModules) {
+ StringBuilder error =
+ new StringBuilder()
+ .append(component.typeElement().getQualifiedName())
+ .append(" repeats modules with scoped bindings or declarations:");
+
+ repeatedModules
+ .asMap()
+ .forEach(
+ (conflictingComponent, conflictingModules) -> {
+ error
+ .append("\n - ")
+ .append(conflictingComponent.typeElement().getQualifiedName())
+ .append(" also includes:");
+ for (ModuleDescriptor conflictingModule : conflictingModules) {
+ error
+ .append("\n - ")
+ .append(conflictingModule.moduleElement().getQualifiedName())
+ .append(" with scopes: ")
+ .append(COMMA_SEPARATED_JOINER.join(moduleScopes(conflictingModule)));
+ }
+ });
+ return error.toString();
+ }
+
+ private ImmutableSet<Scope> moduleScopes(ModuleDescriptor module) {
+ return FluentIterable.concat(module.allBindingDeclarations())
+ .transform(declaration -> uniqueScopeOf(declaration.bindingElement().get()))
+ .filter(scope -> scope.isPresent() && !scope.get().isReusable())
+ .transform(scope -> scope.get())
+ .toSet();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentHjarProcessingStep.java b/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
index 260f65a..47857ca 100644
--- a/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
+++ b/java/dagger/internal/codegen/ComponentHjarProcessingStep.java
@@ -16,27 +16,47 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.common.collect.Sets.union;
-import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotations;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.rootComponentCreatorAnnotations;
-import static java.util.Collections.disjoint;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static dagger.internal.codegen.ComponentAnnotation.rootComponentAnnotations;
+import static dagger.internal.codegen.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.ComponentGenerator.componentName;
+import static dagger.internal.codegen.javapoet.TypeSpecs.addSupertype;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptorFactory;
-import dagger.internal.codegen.validation.ComponentCreatorValidator;
-import dagger.internal.codegen.validation.ComponentValidator;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.BindsInstance;
+import dagger.internal.codegen.ComponentValidator.ComponentValidationReport;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.producers.internal.CancellationListener;
import java.lang.annotation.Annotation;
+import java.util.Optional;
import java.util.Set;
+import java.util.stream.Stream;
+import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
/**
* A processing step that emits the API of a generated component, without any actual implementation.
@@ -52,57 +72,228 @@
* normal step. Method bodies are omitted as Turbine ignores them entirely.
*/
final class ComponentHjarProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
+ private final SourceVersion sourceVersion;
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final Filer filer;
private final Messager messager;
private final ComponentValidator componentValidator;
- private final ComponentCreatorValidator creatorValidator;
private final ComponentDescriptorFactory componentDescriptorFactory;
- private final SourceFileGenerator<ComponentDescriptor> componentGenerator;
@Inject
ComponentHjarProcessingStep(
+ SourceVersion sourceVersion,
+ DaggerElements elements,
+ DaggerTypes types,
+ Filer filer,
Messager messager,
ComponentValidator componentValidator,
- ComponentCreatorValidator creatorValidator,
- ComponentDescriptorFactory componentDescriptorFactory,
- SourceFileGenerator<ComponentDescriptor> componentGenerator) {
+ ComponentDescriptorFactory componentDescriptorFactory) {
super(MoreElements::asType);
+ this.sourceVersion = sourceVersion;
+ this.elements = elements;
+ this.types = types;
+ this.filer = filer;
this.messager = messager;
this.componentValidator = componentValidator;
- this.creatorValidator = creatorValidator;
this.componentDescriptorFactory = componentDescriptorFactory;
- this.componentGenerator = componentGenerator;
}
@Override
public Set<Class<? extends Annotation>> annotations() {
- return union(rootComponentAnnotations(), rootComponentCreatorAnnotations());
+ return rootComponentAnnotations();
}
- // TODO(ronshapiro): Validation might not even be necessary. We should measure it and figure out
- // if it's worth seeing if removing it will still work. We could potentially add a new catch
- // clause for any exception that's not TypeNotPresentException and ignore the component entirely
- // in that case.
@Override
protected void process(
- TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
- if (!disjoint(annotations, rootComponentAnnotations())) {
- processRootComponent(element);
- }
- if (!disjoint(annotations, rootComponentCreatorAnnotations())) {
- processRootCreator(element);
+ TypeElement componentTypeElement, ImmutableSet<Class<? extends Annotation>> annotations) {
+ // TODO(ronshapiro): component validation might not be necessary. We should measure it and
+ // figure out if it's worth seeing if removing it will still work. We could potentially add a
+ // new catch clause for any exception that's not TypeNotPresentException and ignore the
+ // component entirely in that case.
+ ComponentValidationReport validationReport =
+ componentValidator.validate(componentTypeElement, ImmutableSet.of(), ImmutableSet.of());
+ validationReport.report().printMessagesTo(messager);
+ if (validationReport.report().isClean()) {
+ new EmptyComponentGenerator(filer, elements, sourceVersion)
+ .generate(
+ componentDescriptorFactory.rootComponentDescriptor(componentTypeElement), messager);
}
}
- private void processRootComponent(TypeElement element) {
- ValidationReport<TypeElement> validationReport = componentValidator.validate(element);
- validationReport.printMessagesTo(messager);
- if (validationReport.isClean()) {
- componentGenerator.generate(
- componentDescriptorFactory.rootComponentDescriptor(element), messager);
+ private final class EmptyComponentGenerator extends SourceFileGenerator<ComponentDescriptor> {
+ EmptyComponentGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ }
+
+ @Override
+ ClassName nameGeneratedType(ComponentDescriptor input) {
+ return componentName(input.typeElement());
+ }
+
+ @Override
+ Element originatingElement(ComponentDescriptor input) {
+ return input.typeElement();
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(
+ ClassName generatedTypeName, ComponentDescriptor componentDescriptor) {
+ TypeSpec.Builder generatedComponent =
+ TypeSpec.classBuilder(generatedTypeName)
+ .addModifiers(FINAL)
+ .addMethod(privateConstructor());
+ if (componentDescriptor.typeElement().getModifiers().contains(PUBLIC)) {
+ generatedComponent.addModifiers(PUBLIC);
+ }
+
+ TypeElement componentElement = componentDescriptor.typeElement();
+ addSupertype(generatedComponent, componentElement);
+
+ TypeName builderMethodReturnType;
+ ComponentCreatorKind creatorKind;
+ boolean noArgFactoryMethod;
+ if (componentDescriptor.creatorDescriptor().isPresent()) {
+ ComponentCreatorDescriptor creatorDescriptor =
+ componentDescriptor.creatorDescriptor().get();
+ builderMethodReturnType = ClassName.get(creatorDescriptor.typeElement());
+ creatorKind = creatorDescriptor.kind();
+ noArgFactoryMethod = creatorDescriptor.factoryParameters().isEmpty();
+ } else {
+ TypeSpec.Builder builder =
+ TypeSpec.classBuilder("Builder")
+ .addModifiers(STATIC, FINAL)
+ .addMethod(privateConstructor());
+ if (componentDescriptor.typeElement().getModifiers().contains(PUBLIC)) {
+ builder.addModifiers(PUBLIC);
+ }
+
+ ClassName builderClassName = generatedTypeName.nestedClass("Builder");
+ builderMethodReturnType = builderClassName;
+ creatorKind = BUILDER;
+ noArgFactoryMethod = true;
+ componentRequirements(componentDescriptor)
+ .map(requirement -> builderSetterMethod(requirement.typeElement(), builderClassName))
+ .forEach(builder::addMethod);
+ builder.addMethod(builderBuildMethod(componentDescriptor));
+ generatedComponent.addType(builder.build());
+ }
+
+ generatedComponent.addMethod(staticCreatorMethod(builderMethodReturnType, creatorKind));
+
+ if (noArgFactoryMethod
+ && !hasBindsInstanceMethods(componentDescriptor)
+ && componentRequirements(componentDescriptor)
+ .noneMatch(requirement -> requirement.requiresAPassedInstance(elements, types))) {
+ generatedComponent.addMethod(createMethod(componentDescriptor));
+ }
+
+ DeclaredType componentType = MoreTypes.asDeclared(componentElement.asType());
+ // TODO(ronshapiro): unify with ComponentImplementationBuilder
+ Set<MethodSignature> methodSignatures =
+ Sets.newHashSetWithExpectedSize(componentDescriptor.componentMethods().size());
+ componentDescriptor
+ .componentMethods()
+ .stream()
+ .filter(
+ method -> {
+ return methodSignatures.add(
+ MethodSignature.forComponentMethod(method, componentType, types));
+ })
+ .forEach(
+ method ->
+ generatedComponent.addMethod(
+ emptyComponentMethod(componentElement, method.methodElement())));
+
+ if (componentDescriptor.isProduction()) {
+ generatedComponent
+ .addSuperinterface(ClassName.get(CancellationListener.class))
+ .addMethod(onProducerFutureCancelledMethod());
+ }
+
+ return Optional.of(generatedComponent);
}
}
- private void processRootCreator(TypeElement creator) {
- creatorValidator.validate(asType(creator)).printMessagesTo(messager);
+ private MethodSpec emptyComponentMethod(TypeElement typeElement, ExecutableElement baseMethod) {
+ return MethodSpec.overriding(baseMethod, MoreTypes.asDeclared(typeElement.asType()), types)
+ .build();
+ }
+
+ private MethodSpec privateConstructor() {
+ return constructorBuilder().addModifiers(PRIVATE).build();
+ }
+
+ /**
+ * Returns the {@link ComponentRequirement}s for a component that does not have a {@link
+ * ComponentDescriptor#creatorDescriptor()}.
+ */
+ private Stream<ComponentRequirement> componentRequirements(ComponentDescriptor component) {
+ checkArgument(!component.isSubcomponent());
+ return Stream.concat(
+ component.dependencies().stream(),
+ component.modules().stream()
+ .filter(module -> !module.moduleElement().getModifiers().contains(ABSTRACT))
+ .map(module -> ComponentRequirement.forModule(module.moduleElement().asType())));
+ }
+
+ private boolean hasBindsInstanceMethods(ComponentDescriptor componentDescriptor) {
+ return componentDescriptor.creatorDescriptor().isPresent()
+ && elements
+ .getUnimplementedMethods(componentDescriptor.creatorDescriptor().get().typeElement())
+ .stream()
+ .anyMatch(method -> isBindsInstance(method));
+ }
+
+ private static boolean isBindsInstance(ExecutableElement method) {
+ if (isAnnotationPresent(method, BindsInstance.class)) {
+ return true;
+ }
+
+ if (method.getParameters().size() == 1) {
+ return isAnnotationPresent(method.getParameters().get(0), BindsInstance.class);
+ }
+
+ return false;
+ }
+
+ private MethodSpec builderSetterMethod(
+ TypeElement componentRequirement, ClassName builderClass) {
+ String simpleName =
+ UPPER_CAMEL.to(LOWER_CAMEL, componentRequirement.getSimpleName().toString());
+ return MethodSpec.methodBuilder(simpleName)
+ .addModifiers(PUBLIC)
+ .addParameter(ClassName.get(componentRequirement), simpleName)
+ .returns(builderClass)
+ .build();
+ }
+
+ private MethodSpec builderBuildMethod(ComponentDescriptor component) {
+ return MethodSpec.methodBuilder("build")
+ .addModifiers(PUBLIC)
+ .returns(ClassName.get(component.typeElement()))
+ .build();
+ }
+
+ private MethodSpec staticCreatorMethod(
+ TypeName creatorMethodReturnType, ComponentCreatorKind creatorKind) {
+ return MethodSpec.methodBuilder(Ascii.toLowerCase(creatorKind.typeName()))
+ .addModifiers(PUBLIC, STATIC)
+ .returns(creatorMethodReturnType)
+ .build();
+ }
+
+ private MethodSpec createMethod(ComponentDescriptor componentDescriptor) {
+ return MethodSpec.methodBuilder("create")
+ .addModifiers(PUBLIC, STATIC)
+ .returns(ClassName.get(componentDescriptor.typeElement()))
+ .build();
+ }
+
+ private MethodSpec onProducerFutureCancelledMethod() {
+ return MethodSpec.methodBuilder("onProducerFutureCancelled")
+ .addModifiers(PUBLIC)
+ .addParameter(TypeName.BOOLEAN, "mayInterruptIfRunning")
+ .build();
}
}
diff --git a/java/dagger/internal/codegen/ComponentImplementation.java b/java/dagger/internal/codegen/ComponentImplementation.java
new file mode 100644
index 0000000..340da14
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentImplementation.java
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.internal.codegen.serialization.ProtoSerialization.toAnnotationValue;
+import static java.util.stream.Collectors.toList;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.MultimapBuilder;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.ConfigureInitializationParameters;
+import dagger.internal.ModifiableBinding;
+import dagger.internal.ModifiableModule;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.TypeSpecs;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/** The implementation of a component type. */
+final class ComponentImplementation {
+ /** A type of field that this component can contain. */
+ enum FieldSpecKind {
+
+ /** A field required by the component, e.g. module instances. */
+ COMPONENT_REQUIREMENT_FIELD,
+
+ /**
+ * A field for the lock and cached value for {@linkplain PrivateMethodBindingExpression
+ * private-method scoped bindings}.
+ */
+ PRIVATE_METHOD_SCOPED_FIELD,
+
+ /** A framework field for type T, e.g. {@code Provider<T>}. */
+ FRAMEWORK_FIELD,
+
+ /** A static field that always returns an absent {@code Optional} value for the binding. */
+ ABSENT_OPTIONAL_FIELD
+ }
+
+ /** A type of method that this component can contain. */
+ // TODO(user, dpb): Change the oder to constructor, initialize, component, then private
+ // (including MIM and AOM—why treat those separately?).
+ enum MethodSpecKind {
+ /** The component constructor. */
+ CONSTRUCTOR,
+
+ /**
+ * In ahead-of-time subcomponents, this method coordinates the invocation of {@link
+ * #INITIALIZE_METHOD initialization methods} instead of constructors.
+ */
+ // TODO(b/117833324): try to merge this with other initialize() methods so it looks more natural
+ CONFIGURE_INITIALIZATION_METHOD,
+
+ /** A builder method for the component. (Only used by the root component.) */
+ BUILDER_METHOD,
+
+ /** A private method that wraps dependency expressions. */
+ PRIVATE_METHOD,
+
+ /** An initialization method that initializes component requirements and framework types. */
+ INITIALIZE_METHOD,
+
+ /** An implementation of a component interface method. */
+ COMPONENT_METHOD,
+
+ /** A private method that encapsulates members injection logic for a binding. */
+ MEMBERS_INJECTION_METHOD,
+
+ /** A static method that always returns an absent {@code Optional} value for the binding. */
+ ABSENT_OPTIONAL_METHOD,
+
+ /**
+ * A method that encapsulates a modifiable binding. A binding is modifiable if it can change
+ * across implementations of a subcomponent. This is only relevant for ahead-of-time
+ * subcomponents.
+ */
+ MODIFIABLE_BINDING_METHOD,
+
+ /**
+ * The {@link dagger.producers.internal.CancellationListener#onProducerFutureCancelled(boolean)}
+ * method for a production component.
+ */
+ CANCELLATION_LISTENER_METHOD,
+ ;
+ }
+
+ /** A type of nested class that this component can contain. */
+ enum TypeSpecKind {
+ /** A factory class for a present optional binding. */
+ PRESENT_FACTORY,
+
+ /** A class for the component creator (only used by the root component.) */
+ COMPONENT_CREATOR,
+
+ /** A provider class for a component provision. */
+ COMPONENT_PROVISION_FACTORY,
+
+ /** A class for the subcomponent or subcomponent builder. */
+ SUBCOMPONENT
+ }
+
+ /**
+ * The method spec for a {@code configureInitialization} method plus details on the component
+ * requirements that its parameters are associated with.
+ */
+ @AutoValue
+ abstract static class ConfigureInitializationMethod {
+ /** Creates a new {@link ConfigureInitializationMethod}. */
+ static ConfigureInitializationMethod create(
+ MethodSpec spec, ImmutableSet<ComponentRequirement> parameters) {
+ return new AutoValue_ComponentImplementation_ConfigureInitializationMethod(spec, parameters);
+ }
+
+ /** The spec for the method. */
+ abstract MethodSpec spec();
+
+ /**
+ * The component requirements associated with the method's parameters, in the same order as the
+ * parameters.
+ */
+ abstract ImmutableSet<ComponentRequirement> parameters();
+ }
+
+ private final CompilerOptions compilerOptions;
+ private final ComponentDescriptor componentDescriptor;
+ private final Optional<BindingGraph> graph;
+ private final ClassName name;
+ private final NestingKind nestingKind;
+ private final boolean isAbstract;
+ private final Optional<ComponentImplementation> superclassImplementation;
+ private Optional<ComponentCreatorImplementation> creatorImplementation;
+ private final Map<TypeElement, ComponentImplementation> childImplementations = new HashMap<>();
+ private final TypeSpec.Builder component;
+ private final Optional<SubcomponentNames> subcomponentNames;
+ private final UniqueNameSet componentFieldNames = new UniqueNameSet();
+ private final UniqueNameSet componentMethodNames = new UniqueNameSet();
+ private final List<CodeBlock> initializations = new ArrayList<>();
+ private final Set<ComponentRequirement> componentRequirementParameters = new HashSet<>();
+ private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>();
+ private final Map<ComponentRequirement, String> componentRequirementParameterNames =
+ new HashMap<>();
+ private final Set<Key> cancellableProducerKeys = new LinkedHashSet<>();
+ private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap =
+ MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build();
+ private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap =
+ MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
+ private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
+ MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
+ private final List<Supplier<TypeSpec>> switchingProviderSupplier = new ArrayList<>();
+ private final ModifiableBindingMethods modifiableBindingMethods = new ModifiableBindingMethods();
+ private final SetMultimap<BindingRequest, Key> multibindingContributionsMade =
+ LinkedHashMultimap.create();
+ private Optional<ConfigureInitializationMethod> configureInitializationMethod = Optional.empty();
+ private final Map<ComponentRequirement, String> modifiableModuleMethods = new LinkedHashMap<>();
+
+ private ComponentImplementation(
+ ComponentDescriptor componentDescriptor,
+ Optional<BindingGraph> graph,
+ ClassName name,
+ NestingKind nestingKind,
+ Optional<ComponentImplementation> superclassImplementation,
+ Optional<SubcomponentNames> subcomponentNames,
+ CompilerOptions compilerOptions,
+ ImmutableSet<Modifier> modifiers) {
+ checkName(name, nestingKind);
+ this.compilerOptions = compilerOptions;
+ this.componentDescriptor = componentDescriptor;
+ this.graph = graph;
+ this.name = name;
+ this.nestingKind = nestingKind;
+ this.isAbstract = modifiers.contains(ABSTRACT);
+ this.superclassImplementation = superclassImplementation;
+ this.component = classBuilder(name);
+ modifiers.forEach(component::addModifiers);
+ this.subcomponentNames = subcomponentNames;
+ }
+
+ /** Returns a component implementation for a top-level component. */
+ static ComponentImplementation topLevelComponentImplementation(
+ BindingGraph graph,
+ ClassName name,
+ SubcomponentNames subcomponentNames,
+ CompilerOptions compilerOptions) {
+ return new ComponentImplementation(
+ graph.componentDescriptor(),
+ Optional.of(graph),
+ name,
+ NestingKind.TOP_LEVEL,
+ Optional.empty(), // superclass implementation
+ Optional.of(subcomponentNames),
+ compilerOptions,
+ topLevelComponentImplementationModifiers(graph));
+ }
+
+ private static ImmutableSet<Modifier> topLevelComponentImplementationModifiers(
+ BindingGraph graph) {
+ ImmutableSet.Builder<Modifier> modifiers = ImmutableSet.builder();
+ if (graph.componentTypeElement().getModifiers().contains(PUBLIC)
+ || graph.componentDescriptor().isSubcomponent()) {
+ // TODO(ronshapiro): perhaps all generated components should be non-public?
+ modifiers.add(PUBLIC);
+ }
+ return modifiers.add(graph.componentDescriptor().isSubcomponent() ? ABSTRACT : FINAL).build();
+ }
+
+ /** Returns a component implementation that is a child of the current implementation. */
+ ComponentImplementation childComponentImplementation(
+ BindingGraph graph,
+ Optional<ComponentImplementation> superclassImplementation,
+ Modifier... modifiers) {
+ return new ComponentImplementation(
+ graph.componentDescriptor(),
+ Optional.of(graph),
+ getSubcomponentName(graph.componentDescriptor()),
+ NestingKind.MEMBER,
+ superclassImplementation,
+ subcomponentNames,
+ compilerOptions,
+ ImmutableSet.copyOf(modifiers));
+ }
+
+ /**
+ * Returns a component implementation that models a previously compiled class. This {@link
+ * ComponentImplementation} is not used for code generation itself; it is used to determine what
+ * methods need to be implemented in a subclass implementation.
+ */
+ static ComponentImplementation forDeserializedComponent(
+ ComponentDescriptor componentDescriptor,
+ ClassName name,
+ NestingKind nestingKind,
+ Optional<ComponentImplementation> superclassImplementation,
+ CompilerOptions compilerOptions) {
+ return new ComponentImplementation(
+ componentDescriptor,
+ Optional.empty(),
+ name,
+ nestingKind,
+ superclassImplementation,
+ Optional.empty(),
+ compilerOptions,
+ ImmutableSet.of(PUBLIC, ABSTRACT));
+ }
+
+ // TODO(dpb): Just determine the nesting kind from the name.
+ private static void checkName(ClassName name, NestingKind nestingKind) {
+ switch (nestingKind) {
+ case TOP_LEVEL:
+ checkArgument(
+ name.enclosingClassName() == null, "must be a top-level class name: %s", name);
+ break;
+
+ case MEMBER:
+ checkNotNull(name.enclosingClassName(), "must not be a top-level class name: %s", name);
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ "nestingKind must be TOP_LEVEL or MEMBER: " + nestingKind);
+ }
+ }
+
+ /**
+ * Returns {@code true} if this component implementation represents a component that has already
+ * been compiled. If this returns true, the implementation will have no {@link #graph
+ * BindingGraph}.
+ */
+ boolean isDeserializedImplementation() {
+ return !graph.isPresent();
+ }
+
+ // TODO(ronshapiro): see if we can remove this method and instead inject it in the objects that
+ // need it.
+ /** Returns the binding graph for the component being generated. */
+ BindingGraph graph() {
+ checkState(!isDeserializedImplementation(),
+ "A BindingGraph is not available for deserialized component implementations.");
+ return graph.get();
+ }
+
+ /** Returns the descriptor for the component being generated. */
+ ComponentDescriptor componentDescriptor() {
+ return componentDescriptor;
+ }
+
+ /** Returns the name of the component. */
+ ClassName name() {
+ return name;
+ }
+
+ /** Returns whether or not the implementation is nested within another class. */
+ boolean isNested() {
+ return nestingKind.isNested();
+ }
+
+ /** Returns whether or not the implementation is abstract. */
+ boolean isAbstract() {
+ return isAbstract;
+ }
+
+ /** Returns the superclass implementation. */
+ Optional<ComponentImplementation> superclassImplementation() {
+ return superclassImplementation;
+ }
+
+ /**
+ * Returns the base implementation of this component in ahead-of-time subcomponents mode. If this
+ * is the base implementation, this returns {@link Optional#empty()}.
+ */
+ Optional<ComponentImplementation> baseImplementation() {
+ return superclassImplementation.isPresent()
+ ? Optional.of(Optionals.rootmostValue(this, c -> c.superclassImplementation))
+ : Optional.empty();
+ }
+
+ /**
+ * Returns the {@link #configureInitializationMethod()} of the nearest supertype that defines one,
+ * if any.
+ *
+ * <p>Only returns a present value in {@link CompilerOptions#aheadOfTimeSubcomponents()}.
+ */
+ Optional<ConfigureInitializationMethod> superConfigureInitializationMethod() {
+ for (Optional<ComponentImplementation> currentSuper = superclassImplementation;
+ currentSuper.isPresent();
+ currentSuper = currentSuper.get().superclassImplementation) {
+ if (currentSuper.get().configureInitializationMethod.isPresent()) {
+ return currentSuper.get().configureInitializationMethod;
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * The requirements for creating an instance of this component implementation type.
+ *
+ * <p>If this component implementation is concrete, these requirements will be in the order that
+ * the implementation's constructor takes them as parameters.
+ */
+ ImmutableSet<ComponentRequirement> requirements() {
+ // If the base implementation's creator is being generated in ahead-of-time-subcomponents
+ // mode, this uses the ComponentDescriptor's requirements() since Dagger doesn't know what
+ // modules may end being unused or owned by an ancestor component. Otherwise, we use the
+ // necessary component requirements.
+ // TODO(ronshapiro): can we remove the second condition here? Or, is it never going to be
+ // called, so we should enforce that invariant?
+ return isAbstract() && !superclassImplementation().isPresent()
+ ? componentDescriptor().requirements()
+ : graph().componentRequirements();
+ }
+
+ /**
+ * Returns the {@link MethodSpecKind#CONFIGURE_INITIALIZATION_METHOD} of this implementation if
+ * there is one.
+ *
+ * <p>Only returns a present value in {@link CompilerOptions#aheadOfTimeSubcomponents()}.
+ */
+ Optional<ConfigureInitializationMethod> configureInitializationMethod() {
+ return configureInitializationMethod;
+ }
+
+ /**
+ * Set's this component implementation's {@code configureInitialization()} method and {@linkplain
+ * #addMethod(MethodSpecKind, MethodSpec) adds the method}.
+ */
+ void setConfigureInitializationMethod(ConfigureInitializationMethod method) {
+ configureInitializationMethod = Optional.of(method);
+ addMethod(
+ MethodSpecKind.CONFIGURE_INITIALIZATION_METHOD,
+ addConfigureInitializationMetadata(method));
+ }
+
+ private MethodSpec addConfigureInitializationMetadata(ConfigureInitializationMethod method) {
+ if (!shouldEmitModifiableMetadataAnnotations()) {
+ return method.spec();
+ }
+ AnnotationSpec.Builder annotation =
+ AnnotationSpec.builder(ConfigureInitializationParameters.class);
+ for (ComponentRequirement parameter : method.parameters()) {
+ annotation.addMember("value", toAnnotationValue(parameter.toProto()));
+ }
+
+ return method.spec().toBuilder().addAnnotation(annotation.build()).build();
+ }
+
+ void setCreatorImplementation(Optional<ComponentCreatorImplementation> creatorImplementation) {
+ checkState(
+ this.creatorImplementation == null, "setCreatorImplementation has already been called");
+ this.creatorImplementation = creatorImplementation;
+ }
+
+ Optional<ComponentCreatorImplementation> creatorImplementation() {
+ checkState(creatorImplementation != null, "setCreatorImplementation has not been called yet");
+ return creatorImplementation;
+ }
+
+ /**
+ * Returns the {@link ComponentCreatorImplementation} defined in the base implementation for this
+ * component, if one exists.
+ */
+ Optional<ComponentCreatorImplementation> baseCreatorImplementation() {
+ return baseImplementation().flatMap(baseImpl -> baseImpl.creatorImplementation());
+ }
+
+ /**
+ * Returns the kind of this component's creator.
+ *
+ * @throws IllegalStateException if the component has no creator
+ */
+ private ComponentCreatorKind creatorKind() {
+ checkState(componentDescriptor().hasCreator());
+ return componentDescriptor()
+ .creatorDescriptor()
+ .map(ComponentCreatorDescriptor::kind)
+ .orElse(BUILDER);
+ }
+
+ /**
+ * Returns the name of the creator class for this component. It will be a sibling of this
+ * generated class unless this is a top-level component, in which case it will be nested.
+ */
+ ClassName getCreatorName() {
+ return isNested()
+ ? name.peerClass(subcomponentNames().getCreatorName(componentDescriptor()))
+ : name.nestedClass(creatorKind().typeName());
+ }
+
+ /** Returns the name of the nested implementation class for a child component. */
+ ClassName getSubcomponentName(ComponentDescriptor childDescriptor) {
+ checkArgument(
+ componentDescriptor().childComponents().contains(childDescriptor),
+ "%s is not a child component of %s",
+ childDescriptor.typeElement(),
+ componentDescriptor().typeElement());
+ return name.nestedClass(subcomponentNames().get(childDescriptor) + "Impl");
+ }
+
+ /**
+ * Returns the simple name of the creator implementation class for the given subcomponent creator
+ * {@link Key}.
+ */
+ String getSubcomponentCreatorSimpleName(Key key) {
+ return subcomponentNames().getCreatorName(key);
+ }
+
+ private SubcomponentNames subcomponentNames() {
+ checkState(
+ subcomponentNames.isPresent(),
+ "SubcomponentNames is not available for deserialized component implementations.");
+ return subcomponentNames.get();
+ }
+
+ /** Returns the child implementation. */
+ Optional<ComponentImplementation> childImplementation(ComponentDescriptor child) {
+ return Optional.ofNullable(childImplementations.get(child.typeElement()));
+ }
+
+ /** Returns {@code true} if {@code type} is accessible from the generated component. */
+ boolean isTypeAccessible(TypeMirror type) {
+ return isTypeAccessibleFrom(type, name.packageName());
+ }
+
+ /** Adds the given super type to the component. */
+ void addSupertype(TypeElement supertype) {
+ TypeSpecs.addSupertype(component, supertype);
+ }
+
+ /** Adds the given super class to the subcomponent. */
+ void addSuperclass(ClassName className) {
+ checkState(
+ superclassImplementation.isPresent(),
+ "Setting the superclass for component [%s] when there is no superclass implementation.",
+ name);
+ component.superclass(className);
+ }
+
+ // TODO(dpb): Consider taking FieldSpec, and returning identical FieldSpec with unique name?
+ /** Adds the given field to the component. */
+ void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) {
+ fieldSpecsMap.put(fieldKind, fieldSpec);
+ }
+
+ /** Adds the given fields to the component. */
+ void addFields(FieldSpecKind fieldKind, Iterable<FieldSpec> fieldSpecs) {
+ fieldSpecsMap.putAll(fieldKind, fieldSpecs);
+ }
+
+ // TODO(dpb): Consider taking MethodSpec, and returning identical MethodSpec with unique name?
+ /** Adds the given method to the component. */
+ void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) {
+ methodSpecsMap.put(methodKind, methodSpec);
+ }
+
+ /** Adds the given annotation to the component. */
+ void addAnnotation(AnnotationSpec annotation) {
+ component.addAnnotation(annotation);
+ }
+
+ /**
+ * Adds the given method to the component. In this case, the method represents an encapsulation of
+ * a modifiable binding between implementations of a subcomponent. This is only relevant for
+ * ahead-of-time subcomponents.
+ */
+ void addModifiableBindingMethod(
+ ModifiableBindingType type,
+ BindingRequest request,
+ TypeMirror returnType,
+ MethodSpec methodSpec,
+ boolean finalized) {
+ addModifiableMethod(
+ MethodSpecKind.MODIFIABLE_BINDING_METHOD, type, request, returnType, methodSpec, finalized);
+ }
+
+ /**
+ * Adds a component method that is modifiable to the component. In this case, the method
+ * represents an encapsulation of a modifiable binding between implementations of a subcomponent.
+ * This is only relevant for ahead-of-time subcomponents.
+ */
+ void addModifiableComponentMethod(
+ ModifiableBindingType type,
+ BindingRequest request,
+ TypeMirror returnType,
+ MethodSpec methodSpec,
+ boolean finalized) {
+ addModifiableMethod(
+ MethodSpecKind.COMPONENT_METHOD, type, request, returnType, methodSpec, finalized);
+ }
+
+ private void addModifiableMethod(
+ MethodSpecKind methodKind,
+ ModifiableBindingType type,
+ BindingRequest request,
+ TypeMirror returnType,
+ MethodSpec methodSpec,
+ boolean finalized) {
+ modifiableBindingMethods.addModifiableMethod(
+ type, request, returnType, methodSpec, finalized);
+ methodSpecsMap.put(methodKind, withModifiableBindingMetadata(methodSpec, type, request));
+ }
+
+ /** Adds the implementation for the given {@link ModifiableBindingMethod} to the component. */
+ void addImplementedModifiableBindingMethod(ModifiableBindingMethod method) {
+ modifiableBindingMethods.addReimplementedMethod(method);
+ methodSpecsMap.put(
+ MethodSpecKind.MODIFIABLE_BINDING_METHOD,
+ withModifiableBindingMetadata(method.methodSpec(), method.type(), method.request()));
+ }
+
+ private MethodSpec withModifiableBindingMetadata(
+ MethodSpec method, ModifiableBindingType type, BindingRequest request) {
+ if (!shouldEmitModifiableMetadataAnnotations()) {
+ return method;
+ }
+ AnnotationSpec.Builder metadata =
+ AnnotationSpec.builder(ModifiableBinding.class)
+ .addMember("modifiableBindingType", "$S", type.name())
+ .addMember("bindingRequest", toAnnotationValue(request.toProto()));
+ for (Key multibindingContribution : multibindingContributionsMade.get(request)) {
+ metadata.addMember(
+ "multibindingContributions",
+ toAnnotationValue(KeyFactory.toProto(multibindingContribution)));
+ }
+ return method.toBuilder().addAnnotation(metadata.build()).build();
+ }
+
+ /** Add's a modifiable module method to this implementation. */
+ void addModifiableModuleMethod(ComponentRequirement module, MethodSpec method) {
+ registerModifiableModuleMethod(module, method.name);
+ methodSpecsMap.put(
+ MethodSpecKind.MODIFIABLE_BINDING_METHOD, withModifiableModuleMetadata(module, method));
+ }
+
+ /** Registers a modifiable module method with {@code name} for {@code module}. */
+ void registerModifiableModuleMethod(ComponentRequirement module, String name) {
+ checkArgument(module.kind().isModule());
+ checkState(modifiableModuleMethods.put(module, name) == null);
+ }
+
+ private MethodSpec withModifiableModuleMetadata(ComponentRequirement module, MethodSpec method) {
+ if (!shouldEmitModifiableMetadataAnnotations()) {
+ return method;
+ }
+ return method
+ .toBuilder()
+ .addAnnotation(
+ AnnotationSpec.builder(ModifiableModule.class)
+ .addMember("value", toAnnotationValue(module.toProto()))
+ .build())
+ .build();
+ }
+
+ /**
+ * Returns {@code true} if the generated component should include metadata annotations with
+ * information to deserialize this {@link ComponentImplementation} in future compilations.
+ */
+ boolean shouldEmitModifiableMetadataAnnotations() {
+ return isAbstract && compilerOptions.emitModifiableMetadataAnnotations();
+ }
+
+ /** Adds the given type to the component. */
+ void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
+ typeSpecsMap.put(typeKind, typeSpec);
+ }
+
+ /** Adds the type generated from the given child implementation. */
+ void addChild(ComponentDescriptor child, ComponentImplementation childImplementation) {
+ childImplementations.put(child.typeElement(), childImplementation);
+ addType(TypeSpecKind.SUBCOMPONENT, childImplementation.generate().build());
+ }
+
+ /** Adds a {@link Supplier} for the SwitchingProvider for the component. */
+ void addSwitchingProvider(Supplier<TypeSpec> typeSpecSupplier) {
+ switchingProviderSupplier.add(typeSpecSupplier);
+ }
+
+ /** Adds the given code block to the initialize methods of the component. */
+ void addInitialization(CodeBlock codeBlock) {
+ initializations.add(codeBlock);
+ }
+
+ /**
+ * Adds the given component requirement as one that should have a parameter in the component's
+ * initialization methods.
+ */
+ void addComponentRequirementParameter(ComponentRequirement requirement) {
+ componentRequirementParameters.add(requirement);
+ }
+
+ /**
+ * The set of component requirements that have parameters in the component's initialization
+ * methods.
+ */
+ ImmutableSet<ComponentRequirement> getComponentRequirementParameters() {
+ return ImmutableSet.copyOf(componentRequirementParameters);
+ }
+
+ /** Adds the given code block that initializes a {@link ComponentRequirement}. */
+ void addComponentRequirementInitialization(CodeBlock codeBlock) {
+ componentRequirementInitializations.add(codeBlock);
+ }
+
+ /**
+ * Marks the given key of a producer as one that should have a cancellation statement in the
+ * cancellation listener method of the component.
+ */
+ void addCancellableProducerKey(Key key) {
+ cancellableProducerKeys.add(key);
+ }
+
+ /** Returns a new, unique field name for the component based on the given name. */
+ String getUniqueFieldName(String name) {
+ return componentFieldNames.getUniqueName(name);
+ }
+
+ /** Returns a new, unique method name for the component based on the given name. */
+ String getUniqueMethodName(String name) {
+ return componentMethodNames.getUniqueName(name);
+ }
+
+ /** Returns a new, unique method name for a getter method for the given request. */
+ String getUniqueMethodName(BindingRequest request) {
+ return uniqueMethodName(request, KeyVariableNamer.name(request.key()));
+ }
+
+ private String uniqueMethodName(BindingRequest request, String bindingName) {
+ String baseMethodName =
+ "get"
+ + LOWER_CAMEL.to(UPPER_CAMEL, bindingName)
+ + (request.isRequestKind(RequestKind.INSTANCE)
+ ? ""
+ : UPPER_UNDERSCORE.to(UPPER_CAMEL, request.kindName()));
+ return getUniqueMethodName(baseMethodName);
+ }
+
+ /** Gets the parameter name to use for the given requirement for this component. */
+ String getParameterName(ComponentRequirement requirement) {
+ return getParameterName(requirement, requirement.variableName());
+ }
+
+ /**
+ * Gets the parameter name to use for the given requirement for this component, starting with the
+ * given base name if no parameter name has already been selected for the requirement.
+ */
+ String getParameterName(ComponentRequirement requirement, String baseName) {
+ return componentRequirementParameterNames.computeIfAbsent(
+ requirement, r -> getUniqueFieldName(baseName));
+ }
+
+ /** Claims a new method name for the component. Does nothing if method name already exists. */
+ void claimMethodName(CharSequence name) {
+ componentMethodNames.claim(name);
+ }
+
+ /** Returns the list of {@link CodeBlock}s that need to go in the initialize method. */
+ ImmutableList<CodeBlock> getInitializations() {
+ return ImmutableList.copyOf(initializations);
+ }
+
+ /**
+ * Returns a list of {@link CodeBlock}s for initializing {@link ComponentRequirement}s.
+ *
+ * <p>These initializations are kept separate from {@link #getInitializations()} because they must
+ * be executed before the initializations of any framework instance initializations in a
+ * superclass implementation that may depend on the instances. We cannot use the same strategy
+ * that we use for framework instances (i.e. wrap in a {@link dagger.internal.DelegateFactory} or
+ * {@link dagger.producers.internal.DelegateProducer} since the types of these initialized fields
+ * have no interface type that we can write a proxy for.
+ */
+ ImmutableList<CodeBlock> getComponentRequirementInitializations() {
+ return ImmutableList.copyOf(componentRequirementInitializations);
+ }
+
+ /**
+ * Returns whether or not this component has any {@linkplain #getInitializations() initilizations}
+ * or {@linkplain #getComponentRequirementInitializations() component requirement
+ * initializations}.
+ */
+ boolean hasInitializations() {
+ return !initializations.isEmpty() || !componentRequirementInitializations.isEmpty();
+ }
+
+ /**
+ * Returns the list of producer {@link Key}s that need cancellation statements in the cancellation
+ * listener method.
+ */
+ ImmutableList<Key> getCancellableProducerKeys() {
+ Optional<ComponentImplementation> currentSuperImplementation = superclassImplementation;
+ Set<Key> cancelledKeysFromSuperclass = new HashSet<>();
+ while (currentSuperImplementation.isPresent()) {
+ cancelledKeysFromSuperclass.addAll(currentSuperImplementation.get().cancellableProducerKeys);
+ currentSuperImplementation = currentSuperImplementation.get().superclassImplementation;
+ }
+ return Sets.difference(cancellableProducerKeys, cancelledKeysFromSuperclass)
+ .immutableCopy()
+ .asList();
+ }
+
+ /**
+ * Returns the {@link ModifiableBindingMethod}s for this subcomponent implementation and its
+ * superclasses.
+ */
+ ImmutableMap<BindingRequest, ModifiableBindingMethod> getModifiableBindingMethods() {
+ Map<BindingRequest, ModifiableBindingMethod> modifiableBindingMethodsBuilder =
+ new LinkedHashMap<>();
+ if (superclassImplementation.isPresent()) {
+ modifiableBindingMethodsBuilder.putAll(
+ Maps.filterValues(
+ superclassImplementation.get().getModifiableBindingMethods(),
+ // filters the modifiable methods of a superclass that are finalized in this component
+ method -> !modifiableBindingMethods.finalized(method)));
+ }
+ // replace superclass modifiable binding methods with any that are defined in this component
+ // implementation
+ modifiableBindingMethodsBuilder.putAll(modifiableBindingMethods.getNonFinalizedMethods());
+ return ImmutableMap.copyOf(modifiableBindingMethodsBuilder);
+ }
+
+ /**
+ * Returns the names of every modifiable method of this implementation and any superclass
+ * implementations.
+ */
+ ImmutableSet<String> getAllModifiableMethodNames() {
+ ImmutableSet.Builder<String> names = ImmutableSet.builder();
+ modifiableBindingMethods.allMethods().forEach(method -> names.add(method.methodSpec().name));
+ names.addAll(modifiableModuleMethods.values());
+ superclassImplementation.ifPresent(
+ superclass -> names.addAll(superclass.getAllModifiableMethodNames()));
+ return names.build();
+ }
+
+ /**
+ * Returns the {@link ModifiableBindingMethod} for this subcomponent for the given binding, if it
+ * exists.
+ */
+ Optional<ModifiableBindingMethod> getModifiableBindingMethod(BindingRequest request) {
+ Optional<ModifiableBindingMethod> method = modifiableBindingMethods.getMethod(request);
+ if (!method.isPresent() && superclassImplementation.isPresent()) {
+ return superclassImplementation.get().getModifiableBindingMethod(request);
+ }
+ return method;
+ }
+
+ /**
+ * Returns the {@link ModifiableBindingMethod} of a supertype for this method's {@code request},
+ * if one exists.
+ */
+ Optional<ModifiableBindingMethod> supertypeModifiableBindingMethod(BindingRequest request) {
+ return superclassImplementation()
+ .flatMap(superImplementation -> superImplementation.getModifiableBindingMethod(request));
+ }
+
+ /**
+ * Returns the names of modifiable module methods for this implementation and all inherited
+ * implementations, keyed by the corresponding module's {@link ComponentRequirement}.
+ */
+ ImmutableMap<ComponentRequirement, String> getAllModifiableModuleMethods() {
+ ImmutableMap.Builder<ComponentRequirement, String> methods = ImmutableMap.builder();
+ methods.putAll(modifiableModuleMethods);
+ superclassImplementation.ifPresent(
+ superclass -> methods.putAll(superclass.getAllModifiableModuleMethods()));
+ return methods.build();
+ }
+
+ /**
+ * Returns the name of the modifiable module method for {@code module} that is inherited in this
+ * implementation, or empty if none has been defined.
+ */
+ Optional<String> supertypeModifiableModuleMethodName(ComponentRequirement module) {
+ checkArgument(module.kind().isModule());
+ if (!superclassImplementation.isPresent()) {
+ return Optional.empty();
+ }
+ String methodName = superclassImplementation.get().modifiableModuleMethods.get(module);
+ if (methodName == null) {
+ return superclassImplementation.get().supertypeModifiableModuleMethodName(module);
+ }
+ return Optional.of(methodName);
+ }
+
+ /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
+ TypeSpec.Builder generate() {
+ fieldSpecsMap.asMap().values().forEach(component::addFields);
+ methodSpecsMap.asMap().values().forEach(component::addMethods);
+ typeSpecsMap.asMap().values().forEach(component::addTypes);
+ switchingProviderSupplier.stream().map(Supplier::get).forEach(component::addType);
+ return component;
+ }
+
+ /**
+ * Registers a {@ProvisionBinding} representing a multibinding as having been implemented in this
+ * component. Multibindings are modifiable across subcomponent implementations and this allows us
+ * to know whether a contribution has been made by a superclass implementation. This is only
+ * relevant for ahead-of-time subcomponents.
+ */
+ void registerImplementedMultibinding(
+ ContributionBinding multibinding, BindingRequest bindingRequest) {
+ checkArgument(multibinding.isSyntheticMultibinding());
+ // We register a multibinding as implemented each time we request the multibinding expression,
+ // so only modify the set of contributions once.
+ if (!multibindingContributionsMade.containsKey(bindingRequest)) {
+ registerImplementedMultibindingKeys(
+ bindingRequest,
+ multibinding.dependencies().stream().map(DependencyRequest::key).collect(toList()));
+ }
+ }
+
+ /**
+ * Registers the multibinding contributions represented by {@code keys} as having been implemented
+ * in this component. Multibindings are modifiable across subcomponent implementations and this
+ * allows us to know whether a contribution has been made by a superclass implementation. This is
+ * only relevant for ahead-of-time subcomponents.
+ */
+ void registerImplementedMultibindingKeys(BindingRequest bindingRequest, Iterable<Key> keys) {
+ multibindingContributionsMade.putAll(bindingRequest, keys);
+ }
+
+ /**
+ * Returns the set of multibinding contributions associated with all superclass implementations of
+ * a multibinding.
+ */
+ ImmutableSet<Key> superclassContributionsMade(BindingRequest bindingRequest) {
+ return superclassImplementation
+ .map(s -> s.getAllMultibindingContributions(bindingRequest))
+ .orElse(ImmutableSet.of());
+ }
+
+ /**
+ * Returns the set of multibinding contributions associated with all implementations of a
+ * multibinding.
+ */
+ private ImmutableSet<Key> getAllMultibindingContributions(BindingRequest bindingRequest) {
+ return ImmutableSet.copyOf(
+ Sets.union(
+ multibindingContributionsMade.get(bindingRequest),
+ superclassContributionsMade(bindingRequest)));
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentImplementationBuilder.java b/java/dagger/internal/codegen/ComponentImplementationBuilder.java
new file mode 100644
index 0000000..7579ac9
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentImplementationBuilder.java
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
+import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Predicates.in;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.BUILDER_METHOD;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.CANCELLATION_LISTENER_METHOD;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.COMPONENT_METHOD;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.CONSTRUCTOR;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.INITIALIZE_METHOD;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.MODIFIABLE_BINDING_METHOD;
+import static dagger.internal.codegen.ComponentImplementation.TypeSpecKind.COMPONENT_CREATOR;
+import static dagger.internal.codegen.ComponentImplementation.TypeSpecKind.SUBCOMPONENT;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.producers.CancellationPolicy.Propagation.PROPAGATE;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.ComponentDefinitionType;
+import dagger.internal.Preconditions;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ComponentImplementation.ConfigureInitializationMethod;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.AnnotationSpecs;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import dagger.producers.internal.CancellationListener;
+import dagger.producers.internal.Producers;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+
+/** A builder of {@link ComponentImplementation}s. */
+abstract class ComponentImplementationBuilder {
+ private static final String MAY_INTERRUPT_IF_RUNNING = "mayInterruptIfRunning";
+
+ /**
+ * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method
+ * before they get partitioned.
+ */
+ private static final int STATEMENTS_PER_METHOD = 100;
+
+ private static final String CANCELLATION_LISTENER_METHOD_NAME = "onProducerFutureCancelled";
+
+ // TODO(ronshapiro): replace this with composition instead of inheritance so we don't have
+ // non-final fields
+ @Inject BindingGraph graph;
+ @Inject ComponentBindingExpressions bindingExpressions;
+ @Inject ComponentRequirementExpressions componentRequirementExpressions;
+ @Inject ComponentImplementation componentImplementation;
+ @Inject ComponentCreatorImplementationFactory componentCreatorImplementationFactory;
+ @Inject DaggerTypes types;
+ @Inject DaggerElements elements;
+ @Inject CompilerOptions compilerOptions;
+ @Inject ComponentImplementationFactory componentImplementationFactory;
+ @Inject TopLevelImplementationComponent topLevelImplementationComponent;
+ private boolean done;
+
+ /**
+ * Returns a {@link ComponentImplementation} for this component. This is only intended to be
+ * called once (and will throw on successive invocations). If the component must be regenerated,
+ * use a new instance.
+ */
+ final ComponentImplementation build() {
+ checkState(
+ !done,
+ "ComponentImplementationBuilder has already built the ComponentImplementation for [%s].",
+ componentImplementation.name());
+ setSupertype();
+ componentImplementation.setCreatorImplementation(
+ componentCreatorImplementationFactory.create(
+ componentImplementation, Optional.of(componentImplementation.graph())));
+ componentImplementation
+ .creatorImplementation()
+ .map(ComponentCreatorImplementation::spec)
+ .ifPresent(this::addCreatorClass);
+
+ getLocalAndInheritedMethods(graph.componentTypeElement(), types, elements)
+ .forEach(method -> componentImplementation.claimMethodName(method.getSimpleName()));
+ componentImplementation
+ .superclassImplementation()
+ .ifPresent(
+ superclassImplementation -> {
+ superclassImplementation
+ .getAllModifiableMethodNames()
+ .forEach(componentImplementation::claimMethodName);
+ });
+
+ addFactoryMethods();
+ addInterfaceMethods();
+ addChildComponents();
+ implementModifiableModuleMethods();
+
+ addConstructorAndInitializationMethods();
+
+ if (graph.componentDescriptor().isProduction()) {
+ addCancellationListenerImplementation();
+ }
+
+ if (componentImplementation.isAbstract()
+ && !componentImplementation.baseImplementation().isPresent()) {
+ componentImplementation.addAnnotation(compilerOptions.toGenerationOptionsAnnotation());
+ }
+
+ if (componentImplementation.shouldEmitModifiableMetadataAnnotations()) {
+ componentImplementation.addAnnotation(
+ AnnotationSpec.builder(ComponentDefinitionType.class)
+ .addMember("value", "$T.class", graph.componentTypeElement())
+ .build());
+ }
+
+ done = true;
+ return componentImplementation;
+ }
+
+ /** Set the supertype for this generated class. */
+ private void setSupertype() {
+ if (componentImplementation.superclassImplementation().isPresent()) {
+ componentImplementation.addSuperclass(
+ componentImplementation.superclassImplementation().get().name());
+ } else {
+ componentImplementation.addSupertype(graph.componentTypeElement());
+ }
+ }
+
+ /**
+ * Adds {@code creator} as a nested creator class. Root components and subcomponents will nest
+ * this in different classes.
+ */
+ protected abstract void addCreatorClass(TypeSpec creator);
+
+ /** Adds component factory methods. */
+ protected abstract void addFactoryMethods();
+
+ protected void addInterfaceMethods() {
+ // Each component method may have been declared by several supertypes. We want to implement
+ // only one method for each distinct signature.
+ ImmutableListMultimap<MethodSignature, ComponentMethodDescriptor> componentMethodsBySignature =
+ Multimaps.index(graph.componentDescriptor().entryPointMethods(), this::getMethodSignature);
+ for (List<ComponentMethodDescriptor> methodsWithSameSignature :
+ Multimaps.asMap(componentMethodsBySignature).values()) {
+ ComponentMethodDescriptor anyOneMethod = methodsWithSameSignature.stream().findAny().get();
+ MethodSpec methodSpec = bindingExpressions.getComponentMethod(anyOneMethod);
+
+ if (compilerOptions.aheadOfTimeSubcomponents()) {
+ addPossiblyModifiableInterfaceMethod(anyOneMethod, methodSpec);
+ } else {
+ componentImplementation.addMethod(COMPONENT_METHOD, methodSpec);
+ }
+ }
+ }
+
+ /**
+ * Adds a component interface method in ahead-of-time subcomponents mode. If the binding that
+ * implements the method is modifiable, registers the method.
+ */
+ private void addPossiblyModifiableInterfaceMethod(
+ ComponentMethodDescriptor methodDescriptor, MethodSpec implementedComponentMethod) {
+ if (methodDescriptor.dependencyRequest().isPresent()
+ && componentImplementation
+ .getModifiableBindingMethod(bindingRequest(methodDescriptor.dependencyRequest().get()))
+ .isPresent()) {
+ // If there are multiple component methods that are modifiable and for the same binding
+ // request, implement all but one in the base implementation to delegate to the one that
+ // will remain (and be registered) modifiable
+ checkState(componentImplementation.isAbstract() && !componentImplementation.isNested());
+ componentImplementation.addMethod(
+ COMPONENT_METHOD, implementedComponentMethod.toBuilder().addModifiers(FINAL).build());
+ } else {
+ // TODO(b/117833324): Can this class be the one to interface with ComponentImplementation
+ // instead of having it go through ModifiableBindingExpressions?
+ bindingExpressions
+ .modifiableBindingExpressions()
+ .addPossiblyModifiableComponentMethod(methodDescriptor, implementedComponentMethod);
+ }
+ }
+
+ private void addCancellationListenerImplementation() {
+ componentImplementation.addSupertype(elements.getTypeElement(CancellationListener.class));
+ componentImplementation.claimMethodName(CANCELLATION_LISTENER_METHOD_NAME);
+
+ ImmutableList<ParameterSpec> parameters =
+ ImmutableList.of(ParameterSpec.builder(boolean.class, MAY_INTERRUPT_IF_RUNNING).build());
+
+ MethodSpec.Builder methodBuilder =
+ methodBuilder(CANCELLATION_LISTENER_METHOD_NAME)
+ .addModifiers(PUBLIC)
+ .addAnnotation(Override.class)
+ .addParameters(parameters);
+ if (componentImplementation.superclassImplementation().isPresent()) {
+ methodBuilder.addStatement(
+ "super.$L($L)", CANCELLATION_LISTENER_METHOD_NAME, MAY_INTERRUPT_IF_RUNNING);
+ }
+
+ ImmutableList<CodeBlock> cancellationStatements = cancellationStatements();
+
+ if (cancellationStatements.size() < STATEMENTS_PER_METHOD) {
+ methodBuilder.addCode(CodeBlocks.concat(cancellationStatements)).build();
+ } else {
+ ImmutableList<MethodSpec> cancelProducersMethods =
+ createPartitionedMethods(
+ "cancelProducers",
+ parameters,
+ cancellationStatements,
+ methodName -> methodBuilder(methodName).addModifiers(PRIVATE));
+ for (MethodSpec cancelProducersMethod : cancelProducersMethods) {
+ methodBuilder.addStatement("$N($L)", cancelProducersMethod, MAY_INTERRUPT_IF_RUNNING);
+ componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, cancelProducersMethod);
+ }
+ }
+
+ Optional<CodeBlock> cancelParentStatement = cancelParentStatement();
+ cancelParentStatement.ifPresent(methodBuilder::addCode);
+
+ if (cancellationStatements.isEmpty()
+ && !cancelParentStatement.isPresent()
+ && componentImplementation.superclassImplementation().isPresent()) {
+ // Partial child implementations that have no new cancellations don't need to override
+ // the method just to call super().
+ return;
+ }
+
+ componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, methodBuilder.build());
+ }
+
+ private ImmutableList<CodeBlock> cancellationStatements() {
+ // Reversing should order cancellations starting from entry points and going down to leaves
+ // rather than the other way around. This shouldn't really matter but seems *slightly*
+ // preferable because:
+ // When a future that another future depends on is cancelled, that cancellation will propagate
+ // up the future graph toward the entry point. Cancelling in reverse order should ensure that
+ // everything that depends on a particular node has already been cancelled when that node is
+ // cancelled, so there's no need to propagate. Otherwise, when we cancel a leaf node, it might
+ // propagate through most of the graph, making most of the cancel calls that follow in the
+ // onProducerFutureCancelled method do nothing.
+ ImmutableList<Key> cancellationKeys =
+ componentImplementation.getCancellableProducerKeys().reverse();
+
+ ImmutableList.Builder<CodeBlock> cancellationStatements = ImmutableList.builder();
+ for (Key cancellationKey : cancellationKeys) {
+ cancellationStatements.add(
+ CodeBlock.of(
+ "$T.cancel($L, $N);",
+ Producers.class,
+ bindingExpressions
+ .getDependencyExpression(
+ bindingRequest(cancellationKey, FrameworkType.PRODUCER_NODE),
+ componentImplementation.name())
+ .codeBlock(),
+ MAY_INTERRUPT_IF_RUNNING));
+ }
+ return cancellationStatements.build();
+ }
+
+ protected Optional<CodeBlock> cancelParentStatement() {
+ // Returns empty by default. Overridden in subclass(es) to add a statement if and only if the
+ // component being generated is a concrete subcomponent implementation with a parent that
+ // allows cancellation to propagate to it from subcomponents.
+ return Optional.empty();
+ }
+
+ /**
+ * For final components, reimplements all modifiable module methods that may have been modified.
+ */
+ private void implementModifiableModuleMethods() {
+ if (componentImplementation.isAbstract()) {
+ return;
+ }
+ componentImplementation
+ .getAllModifiableModuleMethods()
+ .forEach(this::implementModifiableModuleMethod);
+ }
+
+ private void implementModifiableModuleMethod(ComponentRequirement module, String methodName) {
+ // TODO(b/117833324): only reimplement methods for modules that were abstract or were repeated
+ // by an ancestor component.
+ componentImplementation.addMethod(
+ MODIFIABLE_BINDING_METHOD,
+ methodBuilder(methodName)
+ .addAnnotation(Override.class)
+ .addModifiers(PROTECTED)
+ .returns(TypeName.get(module.type()))
+ .addStatement(
+ componentRequirementExpressions
+ .getExpression(module)
+ .getModifiableModuleMethodExpression(componentImplementation.name()))
+ .build());
+ }
+
+ private MethodSignature getMethodSignature(ComponentMethodDescriptor method) {
+ return MethodSignature.forComponentMethod(
+ method, MoreTypes.asDeclared(graph.componentTypeElement().asType()), types);
+ }
+
+ private void addChildComponents() {
+ for (BindingGraph subgraph : graph.subgraphs()) {
+ // TODO(b/117833324): Can an abstract inner subcomponent implementation be elided if it's
+ // totally empty?
+ componentImplementation.addChild(
+ subgraph.componentDescriptor(), buildChildImplementation(subgraph));
+ }
+ }
+
+ private ComponentImplementation buildChildImplementation(BindingGraph childGraph) {
+ ComponentImplementation childImplementation =
+ compilerOptions.aheadOfTimeSubcomponents()
+ ? abstractInnerSubcomponent(childGraph)
+ : concreteSubcomponent(childGraph);
+ return topLevelImplementationComponent
+ .currentImplementationSubcomponentBuilder()
+ .componentImplementation(childImplementation)
+ .bindingGraph(childGraph)
+ .parentBuilder(Optional.of(this))
+ .parentBindingExpressions(Optional.of(bindingExpressions))
+ .parentRequirementExpressions(Optional.of(componentRequirementExpressions))
+ .build()
+ .subcomponentBuilder()
+ .build();
+ }
+
+ /** Creates an inner abstract subcomponent implementation. */
+ private ComponentImplementation abstractInnerSubcomponent(BindingGraph childGraph) {
+ return componentImplementation.childComponentImplementation(
+ childGraph,
+ Optional.of(
+ componentImplementationFactory.findChildSuperclassImplementation(
+ childGraph.componentDescriptor(), componentImplementation)),
+ PROTECTED,
+ componentImplementation.isAbstract() ? ABSTRACT : FINAL);
+ }
+
+ /** Creates a concrete inner subcomponent implementation. */
+ private ComponentImplementation concreteSubcomponent(BindingGraph childGraph) {
+ return componentImplementation.childComponentImplementation(
+ childGraph,
+ Optional.empty(), // superclassImplementation
+ PRIVATE,
+ FINAL);
+ }
+
+ /** Creates and adds the constructor and methods needed for initializing the component. */
+ private void addConstructorAndInitializationMethods() {
+ MethodSpec.Builder constructor = componentConstructorBuilder();
+ if (!componentImplementation.isAbstract()) {
+ implementInitializationMethod(constructor, initializationParameters());
+ } else if (componentImplementation.hasInitializations()) {
+ addConfigureInitializationMethod();
+ }
+ componentImplementation.addMethod(CONSTRUCTOR, constructor.build());
+ }
+
+ /** Returns a builder for the component's constructor. */
+ private MethodSpec.Builder componentConstructorBuilder() {
+ return constructorBuilder()
+ .addModifiers(componentImplementation.isAbstract() ? PROTECTED : PRIVATE);
+ }
+
+ /** Adds parameters and code to the given {@code initializationMethod}. */
+ private void implementInitializationMethod(
+ MethodSpec.Builder initializationMethod,
+ ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters) {
+ initializationMethod.addParameters(initializationParameters.values());
+ initializationMethod.addCode(
+ CodeBlocks.concat(componentImplementation.getComponentRequirementInitializations()));
+ componentImplementation
+ .superConfigureInitializationMethod()
+ .ifPresent(
+ superConfigureInitializationMethod ->
+ addSuperConfigureInitializationCall(
+ initializationMethod,
+ initializationParameters,
+ superConfigureInitializationMethod));
+ addInitializeMethods(initializationMethod, initializationParameters.values().asList());
+ }
+
+ /** Creates and adds a {@code configureInitializatoin} method to the component. */
+ private void addConfigureInitializationMethod() {
+ MethodSpec.Builder method = configureInitializationMethodBuilder();
+ ImmutableMap<ComponentRequirement, ParameterSpec> parameters = initializationParameters();
+ implementInitializationMethod(method, parameters);
+ componentImplementation.setConfigureInitializationMethod(
+ ConfigureInitializationMethod.create(method.build(), parameters.keySet()));
+ }
+
+ /** Returns a builder for the component's {@code configureInitialization} method. */
+ private MethodSpec.Builder configureInitializationMethodBuilder() {
+ String methodName = componentImplementation.getUniqueMethodName("configureInitialization");
+ MethodSpec.Builder configureInitialization = methodBuilder(methodName).addModifiers(PROTECTED);
+ if (overridesSuperclassConfigureInitialization(configureInitialization.build())) {
+ configureInitialization.addAnnotation(Override.class);
+ }
+ return configureInitialization;
+ }
+
+ /**
+ * Returns whether or not the given method overrides a configureInitialization method from a
+ * superclass.
+ */
+ private boolean overridesSuperclassConfigureInitialization(MethodSpec method) {
+ for (Optional<ComponentImplementation> currentSuperImplementation =
+ componentImplementation.superclassImplementation();
+ currentSuperImplementation.isPresent();
+ currentSuperImplementation = currentSuperImplementation.get().superclassImplementation()) {
+ Optional<MethodSpec> superConfigureInitializationMethod =
+ currentSuperImplementation.get().configureInitializationMethod().map(m -> m.spec());
+ if (superConfigureInitializationMethod
+ .filter(superMethod -> haveSameSignature(method, superMethod))
+ .isPresent()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /** Returns whether or not methods {@code a} and {@code b} have the same signature. */
+ private boolean haveSameSignature(MethodSpec a, MethodSpec b) {
+ return a.name.equals(b.name) && types(a.parameters).equals(types(b.parameters));
+ }
+
+ private ImmutableList<TypeName> types(List<ParameterSpec> parameters) {
+ return parameters.stream().map(parameter -> parameter.type).collect(toImmutableList());
+ }
+
+ /**
+ * Adds a call to the superclass's {@code configureInitialization} method to the given {@code
+ * callingMethod}.
+ */
+ private void addSuperConfigureInitializationCall(
+ MethodSpec.Builder callingMethod,
+ ImmutableMap<ComponentRequirement, ParameterSpec> parameters,
+ ConfigureInitializationMethod superConfigureInitializationMethod) {
+ // This component's constructor may not have all of the parameters that the superclass's
+ // configureInitialization method takes, because the superclass configureInitialization method
+ // necessarily accepts things that it can't know whether will be needed or not. If they aren't
+ // needed (as is the case when the constructor doesn't have a parameter for the module), just
+ // pass null to super.configureInitialization for that parameter; it won't be used.
+ CodeBlock args =
+ superConfigureInitializationMethod.parameters().stream()
+ .map(
+ requirement ->
+ parameters.containsKey(requirement)
+ ? CodeBlock.of("$N", parameters.get(requirement))
+ : CodeBlock.of("null"))
+ .collect(toParametersCodeBlock());
+
+ String qualifier =
+ haveSameSignature(callingMethod.build(), superConfigureInitializationMethod.spec())
+ ? "super."
+ : "";
+ callingMethod.addStatement(
+ qualifier + "$N($L)", superConfigureInitializationMethod.spec(), args);
+ }
+
+ /**
+ * Adds any necessary {@code initialize} methods to the component and adds calls to them to the
+ * given {@code callingMethod}.
+ */
+ private void addInitializeMethods(
+ MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters) {
+ // TODO(cgdecker): It's not the case that each initialize() method has need for all of the
+ // given parameters. In some cases, those parameters may have already been assigned to fields
+ // which could be referenced instead. In other cases, an initialize method may just not need
+ // some of the parameters because the set of initializations in that partition does not
+ // include any reference to them. Right now, the Dagger code has no way of getting that
+ // information because, among other things, componentImplementation.getImplementations() just
+ // returns a bunch of CodeBlocks with no semantic information. Additionally, we may not know
+ // yet whether a field will end up needing to be created for a specific requirement, and we
+ // don't want to create a field that ends up only being used during initialization.
+ CodeBlock args = parameterNames(parameters);
+ ImmutableList<MethodSpec> methods =
+ createPartitionedMethods(
+ "initialize",
+ makeFinal(parameters),
+ componentImplementation.getInitializations(),
+ methodName ->
+ methodBuilder(methodName)
+ .addModifiers(PRIVATE)
+ /* TODO(gak): Strictly speaking, we only need the suppression here if we are
+ * also initializing a raw field in this method, but the structure of this
+ * code makes it awkward to pass that bit through. This will be cleaned up
+ * when we no longer separate fields and initialization as we do now. */
+ .addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED)));
+ for (MethodSpec method : methods) {
+ callingMethod.addStatement("$N($L)", method, args);
+ componentImplementation.addMethod(INITIALIZE_METHOD, method);
+ }
+ }
+
+ /**
+ * Creates one or more methods, all taking the given {@code parameters}, which partition the given
+ * list of {@code statements} among themselves such that no method has more than {@code
+ * STATEMENTS_PER_METHOD} statements in it and such that the returned methods, if called in order,
+ * will execute the {@code statements} in the given order.
+ */
+ private ImmutableList<MethodSpec> createPartitionedMethods(
+ String methodName,
+ Iterable<ParameterSpec> parameters,
+ List<CodeBlock> statements,
+ Function<String, MethodSpec.Builder> methodBuilderCreator) {
+ return Lists.partition(statements, STATEMENTS_PER_METHOD).stream()
+ .map(
+ partition ->
+ methodBuilderCreator
+ .apply(componentImplementation.getUniqueMethodName(methodName))
+ .addParameters(parameters)
+ .addCode(CodeBlocks.concat(partition))
+ .build())
+ .collect(toImmutableList());
+ }
+
+ /** Returns the given parameters with a final modifier added. */
+ private final ImmutableList<ParameterSpec> makeFinal(Collection<ParameterSpec> parameters) {
+ return parameters.stream()
+ .map(param -> param.toBuilder().addModifiers(FINAL).build())
+ .collect(toImmutableList());
+ }
+
+ /**
+ * Returns the parameters for the constructor or {@code configureInitilization} method as a map
+ * from the requirement the parameter fulfills to the spec for the parameter.
+ */
+ private final ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters() {
+ Map<ComponentRequirement, ParameterSpec> parameters;
+ if (componentImplementation.componentDescriptor().hasCreator()) {
+ parameters =
+ Maps.toMap(componentImplementation.requirements(), ComponentRequirement::toParameterSpec);
+ } else if (componentImplementation.isAbstract() && componentImplementation.isNested()) {
+ // If we're generating an abstract inner subcomponent, then we are not implementing module
+ // instance bindings and have no need for factory method parameters.
+ parameters = ImmutableMap.of();
+ } else if (graph.factoryMethod().isPresent()) {
+ parameters = getFactoryMethodParameters(graph);
+ } else if (componentImplementation.isAbstract()) {
+ // If we're generating an abstract base implementation of a subcomponent it's acceptable to
+ // have neither a creator nor factory method.
+ parameters = ImmutableMap.of();
+ } else {
+ throw new AssertionError(
+ "Expected either a component creator or factory method but found neither.");
+ }
+
+ if (componentImplementation.isAbstract()) {
+ parameters = Maps.filterKeys(parameters, in(configureInitializationRequirements()));
+ }
+ return renameParameters(parameters);
+ }
+
+ /**
+ * Returns the set of requirements for the configureInitialization method: the parameters that are
+ * needed either for initializing a component requirement field or for calling the superclass's
+ * {@code configureInitialization} method.
+ */
+ private ImmutableSet<ComponentRequirement> configureInitializationRequirements() {
+ ImmutableSet<ComponentRequirement> initializationParameters =
+ componentImplementation.getComponentRequirementParameters();
+ ImmutableSet<ComponentRequirement> superConfigureInitializationRequirements =
+ componentImplementation
+ .superConfigureInitializationMethod()
+ .map(ConfigureInitializationMethod::parameters)
+ .orElse(ImmutableSet.of());
+ return Sets.union(initializationParameters, superConfigureInitializationRequirements)
+ .immutableCopy();
+ }
+
+ /**
+ * Renames the given parameters to guarantee their names do not conflict with fields in the
+ * component to ensure that a parameter is never referenced where a reference to a field was
+ * intended.
+ */
+ // TODO(cgdecker): This is a bit kludgy; it would be preferable to either qualify the field
+ // references with "this." or "super." when needed to disambiguate between field and parameter,
+ // but that would require more context than is currently available when the code referencing a
+ // field is generated.
+ private ImmutableMap<ComponentRequirement, ParameterSpec> renameParameters(
+ Map<ComponentRequirement, ParameterSpec> parameters) {
+ return ImmutableMap.copyOf(
+ Maps.transformEntries(
+ parameters,
+ (requirement, parameter) ->
+ renameParameter(
+ parameter,
+ componentImplementation.getParameterName(requirement, parameter.name))));
+ }
+
+ private ParameterSpec renameParameter(ParameterSpec parameter, String newName) {
+ return ParameterSpec.builder(parameter.type, newName)
+ .addAnnotations(parameter.annotations)
+ .addModifiers(parameter.modifiers)
+ .build();
+ }
+
+ /** Builds a root component implementation. */
+ static final class RootComponentImplementationBuilder extends ComponentImplementationBuilder {
+ @Inject
+ RootComponentImplementationBuilder(ComponentImplementation componentImplementation) {
+ checkArgument(!componentImplementation.superclassImplementation().isPresent());
+ }
+
+ @Override
+ protected void addCreatorClass(TypeSpec creator) {
+ componentImplementation.addType(COMPONENT_CREATOR, creator);
+ }
+
+ @Override
+ protected void addFactoryMethods() {
+ // Top-level components have a static method that returns a builder or factory for the
+ // component. If the user defined a @Component.Builder or @Component.Factory, an
+ // implementation of their type is returned. Otherwise, an autogenerated Builder type is
+ // returned.
+ // TODO(cgdecker): Replace this abomination with a small class?
+ // Better yet, change things so that an autogenerated builder type has a descriptor of sorts
+ // just like a user-defined creator type.
+ ComponentCreatorKind creatorKind;
+ ClassName creatorType;
+ String factoryMethodName;
+ boolean noArgFactoryMethod;
+ if (creatorDescriptor().isPresent()) {
+ ComponentCreatorDescriptor descriptor = creatorDescriptor().get();
+ creatorKind = descriptor.kind();
+ creatorType = ClassName.get(descriptor.typeElement());
+ factoryMethodName = descriptor.factoryMethod().getSimpleName().toString();
+ noArgFactoryMethod = descriptor.factoryParameters().isEmpty();
+ } else {
+ creatorKind = BUILDER;
+ creatorType = componentCreatorName();
+ factoryMethodName = "build";
+ noArgFactoryMethod = true;
+ }
+
+ MethodSpec creatorFactoryMethod =
+ methodBuilder(creatorKind.methodName())
+ .addModifiers(PUBLIC, STATIC)
+ .returns(creatorType)
+ .addStatement("return new $T()", componentCreatorName())
+ .build();
+ componentImplementation.addMethod(BUILDER_METHOD, creatorFactoryMethod);
+ if (noArgFactoryMethod && canInstantiateAllRequirements()) {
+ componentImplementation.addMethod(
+ BUILDER_METHOD,
+ methodBuilder("create")
+ .returns(ClassName.get(super.graph.componentTypeElement()))
+ .addModifiers(PUBLIC, STATIC)
+ .addStatement(
+ "return new $L().$L()", creatorKind.typeName(), factoryMethodName)
+ .build());
+ }
+ }
+
+ private Optional<ComponentCreatorDescriptor> creatorDescriptor() {
+ return graph.componentDescriptor().creatorDescriptor();
+ }
+
+ /** {@code true} if all of the graph's required dependencies can be automatically constructed */
+ private boolean canInstantiateAllRequirements() {
+ return !Iterables.any(
+ graph.componentRequirements(),
+ dependency -> dependency.requiresAPassedInstance(elements, types));
+ }
+
+ private ClassName componentCreatorName() {
+ return componentImplementation.creatorImplementation().get().name();
+ }
+ }
+
+ /**
+ * Builds a subcomponent implementation. If generating ahead-of-time subcomponents, this may be an
+ * abstract base class implementation, an abstract inner implementation, or a concrete
+ * implementation that extends an abstract base implementation. Otherwise it represents a private,
+ * inner, concrete, final implementation of a subcomponent which extends a user defined type.
+ */
+ static final class SubcomponentImplementationBuilder extends ComponentImplementationBuilder {
+ final Optional<ComponentImplementationBuilder> parent;
+
+ @Inject
+ SubcomponentImplementationBuilder(
+ @ParentComponent Optional<ComponentImplementationBuilder> parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ protected void addCreatorClass(TypeSpec creator) {
+ if (parent.isPresent()) {
+ // In an inner implementation of a subcomponent the creator is a peer class.
+ parent.get().componentImplementation.addType(SUBCOMPONENT, creator);
+ } else {
+ componentImplementation.addType(SUBCOMPONENT, creator);
+ }
+ }
+
+ @Override
+ protected void addFactoryMethods() {
+ // Only construct instances of subcomponents that have concrete implementations.
+ if (!componentImplementation.isAbstract()) {
+ // Use the parent's factory method to create this subcomponent if the
+ // subcomponent was not added via {@link dagger.Module#subcomponents()}.
+ graph.factoryMethod().ifPresent(this::createSubcomponentFactoryMethod);
+ }
+ }
+
+ private void createSubcomponentFactoryMethod(ExecutableElement factoryMethod) {
+ checkState(parent.isPresent());
+
+ Collection<ParameterSpec> params = getFactoryMethodParameters(graph).values();
+ MethodSpec.Builder method = MethodSpec.overriding(factoryMethod, parentType(), types);
+ params.forEach(
+ param -> method.addStatement("$T.checkNotNull($N)", Preconditions.class, param));
+ method.addStatement(
+ "return new $T($L)", componentImplementation.name(), parameterNames(params));
+
+ parent.get().componentImplementation.addMethod(COMPONENT_METHOD, method.build());
+ }
+
+ private DeclaredType parentType() {
+ return asDeclared(parent.get().graph.componentTypeElement().asType());
+ }
+
+ @Override
+ protected void addInterfaceMethods() {
+ if (componentImplementation.superclassImplementation().isPresent()) {
+ // Since we're overriding a subcomponent implementation we add to its implementation given
+ // an expanded binding graph.
+
+ ComponentImplementation superclassImplementation =
+ componentImplementation.superclassImplementation().get();
+ for (ModifiableBindingMethod superclassModifiableBindingMethod :
+ superclassImplementation.getModifiableBindingMethods().values()) {
+ bindingExpressions
+ .modifiableBindingExpressions()
+ .possiblyReimplementedMethod(superclassModifiableBindingMethod)
+ .ifPresent(componentImplementation::addImplementedModifiableBindingMethod);
+ }
+ } else {
+ super.addInterfaceMethods();
+ }
+ }
+
+ @Override
+ protected Optional<CodeBlock> cancelParentStatement() {
+ if (!shouldPropagateCancellationToParent()) {
+ return Optional.empty();
+ }
+ return Optional.of(
+ CodeBlock.builder()
+ .addStatement(
+ "$T.this.$N($N)",
+ parent.get().componentImplementation.name(),
+ CANCELLATION_LISTENER_METHOD_NAME,
+ MAY_INTERRUPT_IF_RUNNING)
+ .build());
+ }
+
+ private boolean shouldPropagateCancellationToParent() {
+ return parent.isPresent()
+ && parent
+ .get()
+ .componentImplementation
+ .componentDescriptor()
+ .cancellationPolicy()
+ .map(policy -> policy.fromSubcomponents().equals(PROPAGATE))
+ .orElse(false);
+ }
+ }
+
+ /**
+ * Returns the map of {@link ComponentRequirement}s to {@link ParameterSpec}s for the
+ * given graph's factory method.
+ */
+ private static Map<ComponentRequirement, ParameterSpec> getFactoryMethodParameters(
+ BindingGraph graph) {
+ return Maps.transformValues(graph.factoryMethodParameters(), ParameterSpec::get);
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentImplementationFactory.java b/java/dagger/internal/codegen/ComponentImplementationFactory.java
new file mode 100644
index 0000000..9578ece
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentImplementationFactory.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ComponentGenerator.componentName;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.serialization.ProtoSerialization.InconsistentSerializedProtoException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.lang.model.element.TypeElement;
+
+/** Factory for {@link ComponentImplementation}s. */
+@Singleton
+final class ComponentImplementationFactory implements ClearableCache {
+ private final Map<TypeElement, ComponentImplementation> topLevelComponentCache = new HashMap<>();
+ private final KeyFactory keyFactory;
+ private final CompilerOptions compilerOptions;
+ private final BindingGraphFactory bindingGraphFactory;
+ private final TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder;
+ private final DeserializedComponentImplementationBuilder
+ deserializedComponentImplementationBuilder;
+ private final DaggerElements elements;
+ private final Messager messager;
+
+ @Inject
+ ComponentImplementationFactory(
+ KeyFactory keyFactory,
+ CompilerOptions compilerOptions,
+ BindingGraphFactory bindingGraphFactory,
+ TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder,
+ DeserializedComponentImplementationBuilder deserializedComponentImplementationBuilder,
+ DaggerElements elements,
+ Messager messager) {
+ this.keyFactory = keyFactory;
+ this.compilerOptions = compilerOptions;
+ this.bindingGraphFactory = bindingGraphFactory;
+ this.topLevelImplementationComponentBuilder = topLevelImplementationComponentBuilder;
+ this.deserializedComponentImplementationBuilder = deserializedComponentImplementationBuilder;
+ this.elements = elements;
+ this.messager = messager;
+ }
+
+ /**
+ * Returns a top-level (non-nested) component implementation for a binding graph.
+ *
+ * @throws IllegalStateException if the binding graph is for a subcomponent and
+ * ahead-of-time-subcomponents mode is not enabled
+ */
+ ComponentImplementation createComponentImplementation(BindingGraph bindingGraph) {
+ return reentrantComputeIfAbsent(
+ topLevelComponentCache,
+ bindingGraph.componentTypeElement(),
+ component -> createComponentImplementationUncached(bindingGraph));
+ }
+
+ private ComponentImplementation createComponentImplementationUncached(BindingGraph bindingGraph) {
+ ComponentImplementation componentImplementation =
+ ComponentImplementation.topLevelComponentImplementation(
+ bindingGraph,
+ componentName(bindingGraph.componentTypeElement()),
+ new SubcomponentNames(bindingGraph, keyFactory),
+ compilerOptions);
+
+ // TODO(dpb): explore using optional bindings for the "parent" bindings
+ CurrentImplementationSubcomponent currentImplementationSubcomponent =
+ topLevelImplementationComponentBuilder
+ .topLevelComponent(componentImplementation)
+ .build()
+ .currentImplementationSubcomponentBuilder()
+ .componentImplementation(componentImplementation)
+ .bindingGraph(bindingGraph)
+ .parentBuilder(Optional.empty())
+ .parentBindingExpressions(Optional.empty())
+ .parentRequirementExpressions(Optional.empty())
+ .build();
+
+ if (componentImplementation.isAbstract()) {
+ checkState(
+ compilerOptions.aheadOfTimeSubcomponents(),
+ "Calling 'componentImplementation()' on %s when not generating ahead-of-time "
+ + "subcomponents.",
+ bindingGraph.componentTypeElement());
+ return currentImplementationSubcomponent.subcomponentBuilder().build();
+ } else {
+ return currentImplementationSubcomponent.rootComponentBuilder().build();
+ }
+ }
+
+ /** Returns the superclass of the child nested within a superclass of the parent component. */
+ ComponentImplementation findChildSuperclassImplementation(
+ ComponentDescriptor child, ComponentImplementation parentImplementation) {
+ // If the current component has superclass implementations, a superclass may contain a
+ // reference to the child. Traverse this component's superimplementation hierarchy looking for
+ // the child's implementation. The child superclass implementation may not be present in the
+ // direct superclass implementations if the subcomponent builder was previously a pruned
+ // binding.
+ for (Optional<ComponentImplementation> parent = parentImplementation.superclassImplementation();
+ parent.isPresent();
+ parent = parent.get().superclassImplementation()) {
+ Optional<ComponentImplementation> superclass = parent.get().childImplementation(child);
+ if (superclass.isPresent()) {
+ return superclass.get();
+ }
+ }
+
+ if (compilerOptions.emitModifiableMetadataAnnotations()) {
+ ClassName childSuperclassName = componentName(child.typeElement());
+ TypeElement generatedChildSuperclassImplementation =
+ elements.getTypeElement(childSuperclassName);
+ if (generatedChildSuperclassImplementation != null) {
+ try {
+ return deserializedComponentImplementationBuilder.create(
+ child, generatedChildSuperclassImplementation);
+ } catch (InconsistentSerializedProtoException e) {
+ messager.printMessage(
+ WARNING,
+ String.format(
+ "%s was compiled with a different version of Dagger than the version in this "
+ + "compilation. To ensure the validity of Dagger's generated code, compile "
+ + "all Dagger code with the same version.",
+ child.typeElement().getQualifiedName()));
+ }
+ } else if (compilerOptions.forceUseSerializedComponentImplementations()) {
+ throw new TypeNotPresentException(childSuperclassName.toString(), null);
+ }
+ }
+
+ // Otherwise, the superclass implementation is top-level, so we must recreate the
+ // implementation object for the base implementation of the child by truncating the binding
+ // graph at the child.
+ BindingGraph truncatedBindingGraph = bindingGraphFactory.create(child, false);
+ return createComponentImplementation(truncatedBindingGraph);
+ }
+
+ @Override
+ public void clearCache() {
+ topLevelComponentCache.clear();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentInstanceBindingExpression.java b/java/dagger/internal/codegen/ComponentInstanceBindingExpression.java
new file mode 100644
index 0000000..e98d595
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentInstanceBindingExpression.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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 com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.javapoet.Expression;
+
+/** A binding expression for the instance of the component itself, i.e. {@code this}. */
+final class ComponentInstanceBindingExpression extends SimpleInvocationBindingExpression {
+ private final ClassName componentName;
+ private final ContributionBinding binding;
+
+ ComponentInstanceBindingExpression(ResolvedBindings resolvedBindings, ClassName componentName) {
+ super(resolvedBindings);
+ this.componentName = componentName;
+ this.binding = resolvedBindings.contributionBinding();
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return Expression.create(
+ binding.key().type(),
+ componentName.equals(requestingClass)
+ ? CodeBlock.of("this")
+ : CodeBlock.of("$T.this", componentName));
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentKind.java b/java/dagger/internal/codegen/ComponentKind.java
new file mode 100644
index 0000000..8e5b9ba
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentKind.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.collect.Sets.immutableEnumSet;
+import static dagger.internal.codegen.DaggerStreams.stream;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.valuesOf;
+import static java.util.EnumSet.allOf;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.Component;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionComponent;
+import dagger.producers.ProductionSubcomponent;
+import java.lang.annotation.Annotation;
+import java.util.Optional;
+import javax.lang.model.element.TypeElement;
+
+/** Enumeration of the different kinds of components. */
+enum ComponentKind {
+ /** {@code @Component} */
+ COMPONENT(Component.class, true, false),
+
+ /** {@code @Subcomponent} */
+ SUBCOMPONENT(Subcomponent.class, false, false),
+
+ /** {@code @ProductionComponent} */
+ PRODUCTION_COMPONENT(ProductionComponent.class, true, true),
+
+ /** {@code @ProductionSubcomponent} */
+ PRODUCTION_SUBCOMPONENT(ProductionSubcomponent.class, false, true),
+
+ /**
+ * Kind for a descriptor that was generated from a {@link Module} instead of a component type in
+ * order to validate the module's bindings.
+ */
+ MODULE(Module.class, true, false),
+
+ /**
+ * Kind for a descriptor was generated from a {@link ProducerModule} instead of a component type
+ * in order to validate the module's bindings.
+ */
+ PRODUCER_MODULE(ProducerModule.class, true, true),
+ ;
+
+ private static final ImmutableSet<ComponentKind> ROOT_COMPONENT_KINDS =
+ valuesOf(ComponentKind.class)
+ .filter(kind -> !kind.isForModuleValidation())
+ .filter(kind -> kind.isRoot())
+ .collect(toImmutableSet());
+
+ private static final ImmutableSet<ComponentKind> SUBCOMPONENT_KINDS =
+ valuesOf(ComponentKind.class)
+ .filter(kind -> !kind.isForModuleValidation())
+ .filter(kind -> !kind.isRoot())
+ .collect(toImmutableSet());
+
+ /** Returns the set of kinds for root components. */
+ static ImmutableSet<ComponentKind> rootComponentKinds() {
+ return ROOT_COMPONENT_KINDS;
+ }
+
+ /** Returns the set of kinds for subcomponents. */
+ static ImmutableSet<ComponentKind> subcomponentKinds() {
+ return SUBCOMPONENT_KINDS;
+ }
+
+ /** Returns the annotations for components of the given kinds. */
+ static ImmutableSet<Class<? extends Annotation>> annotationsFor(Iterable<ComponentKind> kinds) {
+ return stream(kinds).map(ComponentKind::annotation).collect(toImmutableSet());
+ }
+
+ /** Returns the set of component kinds the given {@code element} has annotations for. */
+ static ImmutableSet<ComponentKind> getComponentKinds(TypeElement element) {
+ return valuesOf(ComponentKind.class)
+ .filter(kind -> isAnnotationPresent(element, kind.annotation()))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the kind of an annotated element if it is annotated with one of the {@linkplain
+ * #annotation() annotations}.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one of the
+ * annotations
+ */
+ static Optional<ComponentKind> forAnnotatedElement(TypeElement element) {
+ ImmutableSet<ComponentKind> kinds = getComponentKinds(element);
+ if (kinds.size() > 1) {
+ throw new IllegalArgumentException(
+ element + " cannot be annotated with more than one of " + annotationsFor(kinds));
+ }
+ return kinds.stream().findAny();
+ }
+
+ private final Class<? extends Annotation> annotation;
+ private final boolean isRoot;
+ private final boolean production;
+
+ ComponentKind(
+ Class<? extends Annotation> annotation,
+ boolean isRoot,
+ boolean production) {
+ this.annotation = annotation;
+ this.isRoot = isRoot;
+ this.production = production;
+ }
+
+ /** Returns the annotation that marks a component of this kind. */
+ Class<? extends Annotation> annotation() {
+ return annotation;
+ }
+
+ /** Returns the kinds of modules that can be used with a component of this kind. */
+ ImmutableSet<ModuleKind> legalModuleKinds() {
+ return isProducer()
+ ? immutableEnumSet(allOf(ModuleKind.class))
+ : immutableEnumSet(ModuleKind.MODULE);
+ }
+
+ /** Returns the kinds of subcomponents a component of this kind can have. */
+ ImmutableSet<ComponentKind> legalSubcomponentKinds() {
+ return isProducer()
+ ? immutableEnumSet(PRODUCTION_SUBCOMPONENT)
+ : immutableEnumSet(SUBCOMPONENT, PRODUCTION_SUBCOMPONENT);
+ }
+
+ /**
+ * Returns {@code true} if the descriptor is for a root component (not a subcomponent) or is for
+ * {@linkplain #isForModuleValidation() module-validation}.
+ */
+ boolean isRoot() {
+ return isRoot;
+ }
+
+ /** Returns true if this is a production component. */
+ boolean isProducer() {
+ return production;
+ }
+
+ /** Returns {@code true} if the descriptor is for a module in order to validate its bindings. */
+ boolean isForModuleValidation() {
+ switch (this) {
+ case MODULE:
+ case PRODUCER_MODULE:
+ return true;
+ default:
+ // fall through
+ }
+ return false;
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentMethodBindingExpression.java b/java/dagger/internal/codegen/ComponentMethodBindingExpression.java
new file mode 100644
index 0000000..7e7bbd8
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentMethodBindingExpression.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A binding expression that implements and uses a component method.
+ *
+ * <p>Dependents of this binding expression will just call the component method.
+ */
+final class ComponentMethodBindingExpression extends MethodBindingExpression {
+ private final ComponentImplementation componentImplementation;
+ private final ComponentMethodDescriptor componentMethod;
+
+ ComponentMethodBindingExpression(
+ BindingRequest request,
+ ResolvedBindings resolvedBindings,
+ MethodImplementationStrategy methodImplementationStrategy,
+ BindingExpression wrappedBindingExpression,
+ ComponentImplementation componentImplementation,
+ ComponentMethodDescriptor componentMethod,
+ DaggerTypes types) {
+ super(
+ request,
+ resolvedBindings,
+ methodImplementationStrategy,
+ wrappedBindingExpression,
+ componentImplementation,
+ types);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.componentMethod = checkNotNull(componentMethod);
+ }
+
+ @Override
+ protected CodeBlock getComponentMethodImplementation(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ // There could be several methods on the component for the same request key and kind.
+ // Only one should use the BindingMethodImplementation; the others can delegate that one. So
+ // use methodImplementation.body() only if componentMethod equals the method for this instance.
+
+ // Separately, the method might be defined on a supertype that is also a supertype of some
+ // parent component. In that case, the same ComponentMethodDescriptor will be used to add a CMBE
+ // for the parent and the child. Only the parent's should use the BindingMethodImplementation;
+ // the child's can delegate to the parent. So use methodImplementation.body() only if
+ // componentName equals the component for this instance.
+ return componentMethod.equals(this.componentMethod) && component.equals(componentImplementation)
+ ? methodBodyForComponentMethod(componentMethod)
+ : super.getComponentMethodImplementation(componentMethod, component);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ // If a component method returns a primitive, update the expression's type which might be boxed.
+ Expression expression = super.getDependencyExpression(requestingClass);
+ TypeMirror methodReturnType = componentMethod.methodElement().getReturnType();
+ return methodReturnType.getKind().isPrimitive()
+ ? Expression.create(methodReturnType, expression.codeBlock())
+ : expression;
+ }
+
+ @Override
+ protected void addMethod() {}
+
+ @Override
+ protected String methodName() {
+ return componentMethod.methodElement().getSimpleName().toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentNodeImpl.java b/java/dagger/internal/codegen/ComponentNodeImpl.java
new file mode 100644
index 0000000..3a31ec7
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentNodeImpl.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.model.ComponentPath;
+import dagger.model.DependencyRequest;
+import dagger.model.Scope;
+
+/** An implementation of {@link ComponentNode} that also exposes the {@link ComponentDescriptor}. */
+@AutoValue
+abstract class ComponentNodeImpl implements ComponentNode {
+ static ComponentNode create(
+ ComponentPath componentPath, ComponentDescriptor componentDescriptor) {
+ return new AutoValue_ComponentNodeImpl(componentPath, componentDescriptor);
+ }
+
+ @Override
+ public final boolean isSubcomponent() {
+ return componentDescriptor().isSubcomponent();
+ }
+
+ @Override
+ public boolean isRealComponent() {
+ return componentDescriptor().isRealComponent();
+ }
+
+ @Override
+ public final ImmutableSet<DependencyRequest> entryPoints() {
+ return componentDescriptor().entryPointMethods().stream()
+ .map(method -> method.dependencyRequest().get())
+ .collect(toImmutableSet());
+ }
+
+ @Override
+ public ImmutableSet<Scope> scopes() {
+ return componentDescriptor().scopes();
+ }
+
+ abstract ComponentDescriptor componentDescriptor();
+
+ @Override
+ public final String toString() {
+ return componentPath().toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentProcessingStep.java b/java/dagger/internal/codegen/ComponentProcessingStep.java
index 3125ce7..645c94f 100644
--- a/java/dagger/internal/codegen/ComponentProcessingStep.java
+++ b/java/dagger/internal/codegen/ComponentProcessingStep.java
@@ -16,30 +16,27 @@
package dagger.internal.codegen;
-import static com.google.auto.common.MoreElements.asType;
import static com.google.common.collect.Sets.union;
-import static dagger.internal.codegen.base.ComponentAnnotation.allComponentAnnotations;
-import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotations;
-import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotations;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.allCreatorAnnotations;
+import static dagger.internal.codegen.ComponentAnnotation.allComponentAnnotations;
+import static dagger.internal.codegen.ComponentAnnotation.rootComponentAnnotations;
+import static dagger.internal.codegen.ComponentAnnotation.subcomponentAnnotations;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.allCreatorAnnotations;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.rootComponentCreatorAnnotations;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
+import static dagger.internal.codegen.ValidationType.NONE;
import static java.util.Collections.disjoint;
import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
import com.google.auto.common.MoreElements;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.BindingGraphFactory;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptorFactory;
-import dagger.internal.codegen.validation.BindingGraphValidator;
-import dagger.internal.codegen.validation.ComponentCreatorValidator;
-import dagger.internal.codegen.validation.ComponentDescriptorValidator;
-import dagger.internal.codegen.validation.ComponentValidator;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import dagger.internal.codegen.ComponentValidator.ComponentValidationReport;
import java.lang.annotation.Annotation;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import javax.annotation.processing.Messager;
import javax.inject.Inject;
@@ -58,7 +55,14 @@
private final ComponentDescriptorFactory componentDescriptorFactory;
private final BindingGraphFactory bindingGraphFactory;
private final SourceFileGenerator<BindingGraph> componentGenerator;
+ private final BindingGraphConverter bindingGraphConverter;
private final BindingGraphValidator bindingGraphValidator;
+ private final CompilerOptions compilerOptions;
+ private ImmutableSet<Element> subcomponentElements;
+ private ImmutableSet<Element> subcomponentCreatorElements;
+ private ImmutableMap<Element, ValidationReport<TypeElement>> creatorReportsByComponent;
+ private ImmutableMap<Element, ValidationReport<TypeElement>> creatorReportsBySubcomponent;
+ private ImmutableMap<Element, ValidationReport<TypeElement>> reportsBySubcomponent;
@Inject
ComponentProcessingStep(
@@ -69,7 +73,9 @@
ComponentDescriptorFactory componentDescriptorFactory,
BindingGraphFactory bindingGraphFactory,
SourceFileGenerator<BindingGraph> componentGenerator,
- BindingGraphValidator bindingGraphValidator) {
+ BindingGraphConverter bindingGraphConverter,
+ BindingGraphValidator bindingGraphValidator,
+ CompilerOptions compilerOptions) {
super(MoreElements::asType);
this.messager = messager;
this.componentValidator = componentValidator;
@@ -78,7 +84,9 @@
this.componentDescriptorFactory = componentDescriptorFactory;
this.bindingGraphFactory = bindingGraphFactory;
this.componentGenerator = componentGenerator;
+ this.bindingGraphConverter = bindingGraphConverter;
this.bindingGraphValidator = bindingGraphValidator;
+ this.compilerOptions = compilerOptions;
}
@Override
@@ -87,6 +95,27 @@
}
@Override
+ public ImmutableSet<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ subcomponentElements =
+ getElementsFromAnnotations(elementsByAnnotation, subcomponentAnnotations());
+ subcomponentCreatorElements =
+ getElementsFromAnnotations(elementsByAnnotation, subcomponentCreatorAnnotations());
+
+ ImmutableSet.Builder<Element> rejectedElements = ImmutableSet.builder();
+
+ creatorReportsByComponent =
+ processCreators(
+ getElementsFromAnnotations(elementsByAnnotation, rootComponentCreatorAnnotations()),
+ rejectedElements);
+ creatorReportsBySubcomponent = processCreators(subcomponentCreatorElements, rejectedElements);
+ reportsBySubcomponent =
+ processSubcomponents(subcomponentElements, subcomponentCreatorElements, rejectedElements);
+
+ return rejectedElements.addAll(super.process(elementsByAnnotation)).build();
+ }
+
+ @Override
protected void process(
TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
if (!disjoint(annotations, rootComponentAnnotations())) {
@@ -95,13 +124,10 @@
if (!disjoint(annotations, subcomponentAnnotations())) {
processSubcomponent(element);
}
- if (!disjoint(annotations, allCreatorAnnotations())) {
- processCreator(element);
- }
}
private void processRootComponent(TypeElement component) {
- if (!isComponentValid(component)) {
+ if (!isRootComponentValid(component)) {
return;
}
ComponentDescriptor componentDescriptor =
@@ -109,47 +135,112 @@
if (!isValid(componentDescriptor)) {
return;
}
- if (!validateFullBindingGraph(componentDescriptor)) {
+ if (!isFullBindingGraphValid(componentDescriptor)) {
return;
}
BindingGraph bindingGraph = bindingGraphFactory.create(componentDescriptor, false);
- if (bindingGraphValidator.isValid(bindingGraph.topLevelBindingGraph())) {
+ if (isValid(bindingGraph)) {
generateComponent(bindingGraph);
}
}
private void processSubcomponent(TypeElement subcomponent) {
- if (!isComponentValid(subcomponent)) {
+ if (!compilerOptions.aheadOfTimeSubcomponents()
+ && compilerOptions.fullBindingGraphValidationType(subcomponent).equals(NONE)) {
+ return;
+ }
+ if (!isSubcomponentValid(subcomponent)) {
return;
}
ComponentDescriptor subcomponentDescriptor =
componentDescriptorFactory.subcomponentDescriptor(subcomponent);
// TODO(dpb): ComponentDescriptorValidator for subcomponents, as we do for root components.
- validateFullBindingGraph(subcomponentDescriptor);
+ if (!isFullBindingGraphValid(subcomponentDescriptor)) {
+ return;
+ }
+ if (compilerOptions.aheadOfTimeSubcomponents()) {
+ BindingGraph bindingGraph = bindingGraphFactory.create(subcomponentDescriptor, false);
+ if (isValid(bindingGraph)) {
+ generateComponent(bindingGraph);
+ }
+ }
}
private void generateComponent(BindingGraph bindingGraph) {
componentGenerator.generate(bindingGraph, messager);
}
- private void processCreator(Element creator) {
- creatorValidator.validate(MoreElements.asType(creator)).printMessagesTo(messager);
+ static ImmutableSet<Element> getElementsFromAnnotations(
+ final SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation,
+ Set<Class<? extends Annotation>> annotations) {
+ return ImmutableSet.copyOf(
+ Multimaps.filterKeys(elementsByAnnotation, Predicates.in(annotations)).values());
}
- private boolean isComponentValid(Element component) {
- ValidationReport<?> report = componentValidator.validate(asType(component));
- report.printMessagesTo(messager);
- return report.isClean();
+ private ImmutableMap<Element, ValidationReport<TypeElement>> processCreators(
+ Set<? extends Element> builderElements, ImmutableSet.Builder<Element> rejectedElements) {
+ // Can't use an ImmutableMap.Builder here because a component may have (invalidly) more than one
+ // builder type, and that would make ImmutableMap.Builder throw.
+ Map<Element, ValidationReport<TypeElement>> reports = new HashMap<>();
+ for (Element element : builderElements) {
+ try {
+ ValidationReport<TypeElement> report =
+ creatorValidator.validate(MoreElements.asType(element));
+ report.printMessagesTo(messager);
+ reports.put(element.getEnclosingElement(), report);
+ } catch (TypeNotPresentException e) {
+ rejectedElements.add(element);
+ }
+ }
+ return ImmutableMap.copyOf(reports);
}
- @CanIgnoreReturnValue
- private boolean validateFullBindingGraph(ComponentDescriptor componentDescriptor) {
- TypeElement component = componentDescriptor.typeElement();
- if (!bindingGraphValidator.shouldDoFullBindingGraphValidation(component)) {
+ private ImmutableMap<Element, ValidationReport<TypeElement>> processSubcomponents(
+ Set<? extends Element> subcomponentElements,
+ Set<? extends Element> subcomponentBuilderElements,
+ ImmutableSet.Builder<Element> rejectedElements) {
+ ImmutableMap.Builder<Element, ValidationReport<TypeElement>> reports = ImmutableMap.builder();
+ for (Element element : subcomponentElements) {
+ try {
+ ComponentValidationReport report =
+ componentValidator.validate(
+ MoreElements.asType(element), subcomponentElements, subcomponentBuilderElements);
+ report.report().printMessagesTo(messager);
+ reports.put(element, report.report());
+ } catch (TypeNotPresentException e) {
+ rejectedElements.add(element);
+ }
+ }
+ return reports.build();
+ }
+
+ private boolean isRootComponentValid(TypeElement rootComponent) {
+ ComponentValidationReport validationReport =
+ componentValidator.validate(
+ rootComponent, subcomponentElements, subcomponentCreatorElements);
+ validationReport.report().printMessagesTo(messager);
+ return isClean(validationReport);
+ }
+
+ // TODO(dpb): Clean up generics so this can take TypeElement.
+ private boolean isSubcomponentValid(Element subcomponentElement) {
+ ValidationReport<?> subcomponentCreatorReport =
+ creatorReportsBySubcomponent.get(subcomponentElement);
+ if (subcomponentCreatorReport != null && !subcomponentCreatorReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> subcomponentReport = reportsBySubcomponent.get(subcomponentElement);
+ return subcomponentReport == null || subcomponentReport.isClean();
+ }
+
+ private boolean isFullBindingGraphValid(ComponentDescriptor componentDescriptor) {
+ if (compilerOptions
+ .fullBindingGraphValidationType(componentDescriptor.typeElement())
+ .equals(NONE)) {
return true;
}
BindingGraph fullBindingGraph = bindingGraphFactory.create(componentDescriptor, true);
- return bindingGraphValidator.isValid(fullBindingGraph.topLevelBindingGraph());
+ return isValid(fullBindingGraph);
}
private boolean isValid(ComponentDescriptor componentDescriptor) {
@@ -158,4 +249,30 @@
componentDescriptorReport.printMessagesTo(messager);
return componentDescriptorReport.isClean();
}
+
+ private boolean isValid(BindingGraph bindingGraph) {
+ return bindingGraphValidator.isValid(bindingGraphConverter.convert(bindingGraph));
+ }
+
+ /**
+ * Returns true if the component's report is clean, its builder report is clean, and all
+ * referenced subcomponent reports and subcomponent builder reports are clean.
+ */
+ private boolean isClean(ComponentValidationReport report) {
+ Element component = report.report().subject();
+ ValidationReport<?> componentReport = report.report();
+ if (!componentReport.isClean()) {
+ return false;
+ }
+ ValidationReport<?> builderReport = creatorReportsByComponent.get(component);
+ if (builderReport != null && !builderReport.isClean()) {
+ return false;
+ }
+ for (Element element : report.referencedSubcomponents()) {
+ if (!isSubcomponentValid(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/java/dagger/internal/codegen/ComponentProcessor.java b/java/dagger/internal/codegen/ComponentProcessor.java
index e392252..541a4ab 100644
--- a/java/dagger/internal/codegen/ComponentProcessor.java
+++ b/java/dagger/internal/codegen/ComponentProcessor.java
@@ -16,42 +16,25 @@
package dagger.internal.codegen;
-import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
+import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.DYNAMIC;
import com.google.auto.common.BasicAnnotationProcessor;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
+import com.google.common.collect.Iterables;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import dagger.BindsInstance;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import dagger.internal.codegen.SpiModule.TestingPlugins;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.base.SourceFileGenerationException;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.InjectBindingRegistry;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions;
-import dagger.internal.codegen.componentgenerator.ComponentGeneratorModule;
-import dagger.internal.codegen.validation.BindingGraphPlugins;
-import dagger.internal.codegen.validation.BindingMethodProcessingStep;
-import dagger.internal.codegen.validation.BindingMethodValidatorsModule;
-import dagger.internal.codegen.validation.BindsInstanceProcessingStep;
-import dagger.internal.codegen.validation.InjectBindingRegistryModule;
-import dagger.internal.codegen.validation.MonitoringModuleProcessingStep;
-import dagger.internal.codegen.validation.MultibindingAnnotationsProcessingStep;
import dagger.spi.BindingGraphPlugin;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.inject.Inject;
@@ -65,7 +48,7 @@
*
* <p>TODO(gak): give this some better documentation
*/
-@IncrementalAnnotationProcessor(ISOLATING)
+@IncrementalAnnotationProcessor(DYNAMIC)
@AutoService(Processor.class)
public class ComponentProcessor extends BasicAnnotationProcessor {
private final Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins;
@@ -75,6 +58,8 @@
@Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator;
@Inject ImmutableList<ProcessingStep> processingSteps;
@Inject BindingGraphPlugins bindingGraphPlugins;
+ @Inject CompilerOptions compilerOptions;
+ @Inject DaggerStatisticsCollector statisticsCollector;
@Inject Set<ClearableCache> clearableCaches;
public ComponentProcessor() {
@@ -110,19 +95,28 @@
@Override
public Set<String> getSupportedOptions() {
- return Sets.union(
- ProcessingEnvironmentCompilerOptions.supportedOptions(),
- bindingGraphPlugins.allSupportedOptions())
- .immutableCopy();
+ ImmutableSet.Builder<String> options = ImmutableSet.builder();
+ options.addAll(ProcessingEnvironmentCompilerOptions.supportedOptions());
+ options.addAll(bindingGraphPlugins.allSupportedOptions());
+ if (compilerOptions.useGradleIncrementalProcessing()) {
+ options.add("org.gradle.annotation.processing.isolating");
+ }
+ return options.build();
}
@Override
protected Iterable<? extends ProcessingStep> initSteps() {
- ProcessorComponent.factory().create(processingEnv, testingPlugins).inject(this);
+ ProcessorComponent.builder()
+ .processingEnvironmentModule(new ProcessingEnvironmentModule(processingEnv))
+ .testingPlugins(testingPlugins)
+ .build()
+ .inject(this);
+ statisticsCollector.processingStarted();
bindingGraphPlugins.initializePlugins();
-
- return processingSteps;
+ return Iterables.transform(
+ processingSteps,
+ step -> new DaggerStatisticsCollectingProcessingStep(step, statisticsCollector));
}
@Singleton
@@ -130,27 +124,32 @@
modules = {
BindingGraphValidationModule.class,
BindingMethodValidatorsModule.class,
- ComponentGeneratorModule.class,
InjectBindingRegistryModule.class,
ProcessingEnvironmentModule.class,
ProcessingRoundCacheModule.class,
ProcessingStepsModule.class,
SourceFileGeneratorsModule.class,
- SpiModule.class
+ SpiModule.class,
+ SystemComponentsModule.class,
+ TopLevelImplementationComponent.InstallationModule.class,
})
interface ProcessorComponent {
void inject(ComponentProcessor processor);
- static Factory factory() {
- return DaggerComponentProcessor_ProcessorComponent.factory();
+ static Builder builder() {
+ return DaggerComponentProcessor_ProcessorComponent.builder();
}
- @Component.Factory
- interface Factory {
- @CheckReturnValue
- ProcessorComponent create(
- @BindsInstance ProcessingEnvironment processingEnv,
- @BindsInstance @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins);
+ @CanIgnoreReturnValue
+ @Component.Builder
+ interface Builder {
+ Builder processingEnvironmentModule(ProcessingEnvironmentModule module);
+
+ @BindsInstance
+ Builder testingPlugins(
+ @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins);
+
+ @CheckReturnValue ProcessorComponent build();
}
}
@@ -160,9 +159,6 @@
static ImmutableList<ProcessingStep> processingSteps(
MapKeyProcessingStep mapKeyProcessingStep,
InjectProcessingStep injectProcessingStep,
- AssistedInjectProcessingStep assistedInjectProcessingStep,
- AssistedFactoryProcessingStep assistedFactoryProcessingStep,
- AssistedProcessingStep assistedProcessingStep,
MonitoringModuleProcessingStep monitoringModuleProcessingStep,
MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep,
BindsInstanceProcessingStep bindsInstanceProcessingStep,
@@ -174,14 +170,15 @@
return ImmutableList.of(
mapKeyProcessingStep,
injectProcessingStep,
- assistedInjectProcessingStep,
- assistedFactoryProcessingStep,
- assistedProcessingStep,
monitoringModuleProcessingStep,
multibindingAnnotationsProcessingStep,
bindsInstanceProcessingStep,
moduleProcessingStep,
compilerOptions.headerCompilation()
+ // Ahead Of Time subcomponents use the regular hjar filtering in
+ // HjarSourceFileGenerator since they must retain protected implementation methods
+ // between subcomponents
+ && !compilerOptions.aheadOfTimeSubcomponents()
? componentHjarProcessingStep
: componentProcessingStep,
bindingMethodProcessingStep);
@@ -190,7 +187,10 @@
@Override
protected void postRound(RoundEnvironment roundEnv) {
- if (!roundEnv.processingOver()) {
+ statisticsCollector.roundFinished();
+ if (roundEnv.processingOver()) {
+ statisticsCollector.processingStopped();
+ } else {
try {
injectBindingRegistry.generateSourcesForRequiredBindings(
factoryGenerator, membersInjectorGenerator);
diff --git a/java/dagger/internal/codegen/ComponentProvisionBindingExpression.java b/java/dagger/internal/codegen/ComponentProvisionBindingExpression.java
new file mode 100644
index 0000000..b8c6049
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentProvisionBindingExpression.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.Preconditions;
+import dagger.internal.codegen.javapoet.Expression;
+
+/** A binding expression for component provision methods. */
+final class ComponentProvisionBindingExpression extends SimpleInvocationBindingExpression {
+ private final ProvisionBinding binding;
+ private final BindingGraph bindingGraph;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final CompilerOptions compilerOptions;
+
+ ComponentProvisionBindingExpression(
+ ResolvedBindings resolvedBindings,
+ BindingGraph bindingGraph,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ CompilerOptions compilerOptions) {
+ super(resolvedBindings);
+ this.binding = (ProvisionBinding) resolvedBindings.contributionBinding();
+ this.bindingGraph = checkNotNull(bindingGraph);
+ this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
+ this.compilerOptions = checkNotNull(compilerOptions);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ CodeBlock invocation =
+ CodeBlock.of(
+ "$L.$L()",
+ componentRequirementExpressions.getExpression(componentRequirement(), requestingClass),
+ binding.bindingElement().get().getSimpleName());
+ return Expression.create(
+ binding.contributedPrimitiveType().orElse(binding.key().type()),
+ maybeCheckForNull(binding, compilerOptions, invocation));
+ }
+
+ private ComponentRequirement componentRequirement() {
+ return bindingGraph
+ .componentDescriptor()
+ .getDependencyThatDefinesMethod(binding.bindingElement().get());
+ }
+
+ static CodeBlock maybeCheckForNull(
+ ProvisionBinding binding, CompilerOptions compilerOptions, CodeBlock invocation) {
+ return binding.shouldCheckForNull(compilerOptions)
+ ? CodeBlock.of(
+ "$T.checkNotNull($L, $S)",
+ Preconditions.class,
+ invocation,
+ "Cannot return null from a non-@Nullable component method")
+ : invocation;
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentRequirement.java b/java/dagger/internal/codegen/ComponentRequirement.java
new file mode 100644
index 0000000..3bed5da
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentRequirement.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2016 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.auto.common.MoreElements.getLocalAndInheritedMethods;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.SourceFiles.simpleVariableName;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.Binds;
+import dagger.BindsOptionalOf;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.serialization.ComponentRequirementProto;
+import dagger.internal.codegen.serialization.ComponentRequirementProto.BoundInstanceRequirement;
+import dagger.model.BindingKind;
+import dagger.model.Key;
+import dagger.multibindings.Multibinds;
+import dagger.producers.Produces;
+import java.util.Optional;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/** A type that a component needs an instance of. */
+@AutoValue
+abstract class ComponentRequirement {
+ enum Kind {
+ /** A type listed in the component's {@code dependencies} attribute. */
+ DEPENDENCY,
+
+ /** A type listed in the component or subcomponent's {@code modules} attribute. */
+ MODULE,
+
+ /**
+ * An object that is passed to a builder's {@link dagger.BindsInstance @BindsInstance} method.
+ */
+ BOUND_INSTANCE,
+ ;
+
+ boolean isBoundInstance() {
+ return equals(BOUND_INSTANCE);
+ }
+
+ boolean isModule() {
+ return equals(MODULE);
+ }
+ }
+
+ /** The kind of requirement. */
+ abstract Kind kind();
+
+ /** Returns true if this is a {@link Kind#BOUND_INSTANCE} requirement. */
+ // TODO(ronshapiro): consider removing this and inlining the usages
+ final boolean isBoundInstance() {
+ return kind().isBoundInstance();
+ }
+
+ /**
+ * The type of the instance the component must have, wrapped so that requirements can be used as
+ * value types.
+ */
+ abstract Equivalence.Wrapper<TypeMirror> wrappedType();
+
+ /** The type of the instance the component must have. */
+ TypeMirror type() {
+ return wrappedType().get();
+ }
+
+ /** The element associated with the type of this requirement. */
+ TypeElement typeElement() {
+ return MoreTypes.asTypeElement(type());
+ }
+
+ /** The action a component builder should take if it {@code null} is passed. */
+ enum NullPolicy {
+ /** Make a new instance. */
+ NEW,
+ /** Throw an exception. */
+ THROW,
+ /** Allow use of null values. */
+ ALLOW,
+ }
+
+ /**
+ * An override for the requirement's null policy. If set, this is used as the null policy instead
+ * of the default behavior in {@link #nullPolicy}.
+ *
+ * <p>Some implementations' null policy can be determined upon construction (e.g., for binding
+ * instances), but others' require Elements and Types, which must wait until {@link #nullPolicy}
+ * is called.
+ */
+ abstract Optional<NullPolicy> overrideNullPolicy();
+
+ /** The requirement's null policy. */
+ NullPolicy nullPolicy(DaggerElements elements, DaggerTypes types) {
+ if (overrideNullPolicy().isPresent()) {
+ return overrideNullPolicy().get();
+ }
+ switch (kind()) {
+ case MODULE:
+ return componentCanMakeNewInstances(typeElement())
+ ? NullPolicy.NEW
+ : requiresAPassedInstance(elements, types) ? NullPolicy.THROW : NullPolicy.ALLOW;
+ case DEPENDENCY:
+ case BOUND_INSTANCE:
+ return NullPolicy.THROW;
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns true if the passed {@link ComponentRequirement} requires a passed instance in order to
+ * be used within a component.
+ */
+ boolean requiresAPassedInstance(DaggerElements elements, DaggerTypes types) {
+ if (!kind().isModule()) {
+ // Bound instances and dependencies always require the user to provide an instance.
+ return true;
+ }
+ return requiresModuleInstance(elements, types) && !componentCanMakeNewInstances(typeElement());
+ }
+
+ /**
+ * Returns {@code true} if an instance is needed for this (module) requirement.
+ *
+ * <p>An instance is only needed if there is a binding method on the module that is neither {@code
+ * abstract} nor {@code static}; if all bindings are one of those, then there should be no
+ * possible dependency on instance state in the module's bindings.
+ */
+ private boolean requiresModuleInstance(DaggerElements elements, DaggerTypes types) {
+ ImmutableSet<ExecutableElement> methods =
+ getLocalAndInheritedMethods(typeElement(), types, elements);
+ return methods.stream()
+ .filter(this::isBindingMethod)
+ .map(ExecutableElement::getModifiers)
+ .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC));
+ }
+
+ private boolean isBindingMethod(ExecutableElement method) {
+ // TODO(cgdecker): At the very least, we should have utility methods to consolidate this stuff
+ // in one place; listing individual annotations all over the place is brittle.
+ return isAnyAnnotationPresent(
+ method,
+ Provides.class,
+ Produces.class,
+ // TODO(ronshapiro): it would be cool to have internal meta-annotations that could describe
+ // these, like @AbstractBindingMethod
+ Binds.class,
+ Multibinds.class,
+ BindsOptionalOf.class);
+ }
+
+ /** The key for this requirement, if one is available. */
+ abstract Optional<Key> key();
+
+ /** Returns the name for this requirement that could be used as a variable. */
+ abstract String variableName();
+
+ /** Returns a parameter spec for this requirement. */
+ ParameterSpec toParameterSpec() {
+ return ParameterSpec.builder(TypeName.get(type()), variableName()).build();
+ }
+
+ /** Creates a proto representation of this requirement. */
+ ComponentRequirementProto toProto() {
+ switch (kind()) {
+ case DEPENDENCY:
+ return ComponentRequirementProto.newBuilder()
+ .setDependency(TypeProtoConverter.toProto(type()))
+ .build();
+ case MODULE:
+ return ComponentRequirementProto.newBuilder()
+ .setModule(TypeProtoConverter.toProto(type()))
+ .build();
+ case BOUND_INSTANCE:
+ return ComponentRequirementProto.newBuilder()
+ .setBoundInstance(
+ BoundInstanceRequirement.newBuilder()
+ .setKey(KeyFactory.toProto(key().get()))
+ .setNullable(overrideNullPolicy().equals(Optional.of(NullPolicy.ALLOW)))
+ .setVariableName(variableName()))
+ .build();
+ }
+ throw new AssertionError(this);
+ }
+
+ static ComponentRequirement forDependency(TypeMirror type) {
+ return new AutoValue_ComponentRequirement(
+ Kind.DEPENDENCY,
+ MoreTypes.equivalence().wrap(checkNotNull(type)),
+ Optional.empty(),
+ Optional.empty(),
+ simpleVariableName(MoreTypes.asTypeElement(type)));
+ }
+
+ static ComponentRequirement forModule(TypeMirror type) {
+ return new AutoValue_ComponentRequirement(
+ Kind.MODULE,
+ MoreTypes.equivalence().wrap(checkNotNull(type)),
+ Optional.empty(),
+ Optional.empty(),
+ simpleVariableName(MoreTypes.asTypeElement(type)));
+ }
+
+ static ComponentRequirement forBoundInstance(Key key, boolean nullable, String variableName) {
+ return new AutoValue_ComponentRequirement(
+ Kind.BOUND_INSTANCE,
+ MoreTypes.equivalence().wrap(key.type()),
+ nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(),
+ Optional.of(key),
+ variableName);
+ }
+
+ static ComponentRequirement forBoundInstance(ContributionBinding binding) {
+ checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE));
+ return forBoundInstance(
+ binding.key(),
+ binding.nullableType().isPresent(),
+ binding.bindingElement().get().getSimpleName().toString());
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentRequirementBindingExpression.java b/java/dagger/internal/codegen/ComponentRequirementBindingExpression.java
new file mode 100644
index 0000000..d6aa053
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentRequirementBindingExpression.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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 com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.Expression;
+
+/**
+ * A binding expression for instances bound with {@link dagger.BindsInstance} and instances of
+ * {@linkplain dagger.Component#dependencies() component} and {@linkplain
+ * dagger.producers.ProductionComponent#dependencies() production component dependencies}.
+ */
+final class ComponentRequirementBindingExpression extends SimpleInvocationBindingExpression {
+ private final ComponentRequirement componentRequirement;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+
+ ComponentRequirementBindingExpression(
+ ResolvedBindings resolvedBindings,
+ ComponentRequirement componentRequirement,
+ ComponentRequirementExpressions componentRequirementExpressions) {
+ super(resolvedBindings);
+ this.componentRequirement = componentRequirement;
+ this.componentRequirementExpressions = componentRequirementExpressions;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return Expression.create(
+ componentRequirement.type(),
+ componentRequirementExpressions.getExpression(componentRequirement, requestingClass));
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentRequirementExpression.java b/java/dagger/internal/codegen/ComponentRequirementExpression.java
new file mode 100644
index 0000000..b25c01b
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentRequirementExpression.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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 com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+
+/**
+ * A factory for expressions of {@link ComponentRequirement}s in the generated component. This is
+ * <em>not</em> a {@link BindingExpression}, since {@link ComponentRequirement}s do not have a
+ * {@link dagger.model.Key}. See {@link ComponentRequirementBindingExpression} for binding
+ * expressions that are themselves a component requirement.
+ */
+interface ComponentRequirementExpression {
+ /**
+ * Returns an expression for the {@link ComponentRequirement} to be used when implementing a
+ * component method. This may add a field or method to the component in order to reference the
+ * component requirement outside of the {@code initialize()} methods.
+ */
+ CodeBlock getExpression(ClassName requestingClass);
+
+ /**
+ * Returns an expression for the {@link ComponentRequirement} to be used only within {@code
+ * initialize()} methods, where the constructor parameters are available.
+ *
+ * <p>When accessing this expression from a subcomponent, this may cause a field to be initialized
+ * or a method to be added in the component that owns this {@link ComponentRequirement}.
+ */
+ default CodeBlock getExpressionDuringInitialization(ClassName requestingClass) {
+ return getExpression(requestingClass);
+ }
+
+ /**
+ * Returns the expression for the {@link ComponentRequirement} to be used when reimplementing a
+ * modifiable module method.
+ */
+ default CodeBlock getModifiableModuleMethodExpression(ClassName requestingClass) {
+ return CodeBlock.of("return $L", getExpression(requestingClass));
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentRequirementExpressions.java b/java/dagger/internal/codegen/ComponentRequirementExpressions.java
new file mode 100644
index 0000000..4ab58c9
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentRequirementExpressions.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Suppliers.memoize;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.ComponentImplementation.FieldSpecKind.COMPONENT_REQUIREMENT_FIELD;
+import static dagger.internal.codegen.ModuleProxies.newModuleInstance;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A central repository of expressions used to access any {@link ComponentRequirement} available to
+ * a component.
+ */
+@PerComponentImplementation
+final class ComponentRequirementExpressions {
+
+ // TODO(dpb,ronshapiro): refactor this and ComponentBindingExpressions into a
+ // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
+ // parents? If so, maybe make ComponentRequirementExpression.Factory create it.
+
+ private final Optional<ComponentRequirementExpressions> parent;
+ private final Map<ComponentRequirement, ComponentRequirementExpression>
+ componentRequirementExpressions = new HashMap<>();
+ private final BindingGraph graph;
+ private final ComponentImplementation componentImplementation;
+ private final CompilerOptions compilerOptions;
+ private final DaggerElements elements;
+
+ // TODO(ronshapiro): give ComponentImplementation a graph() method
+ @Inject
+ ComponentRequirementExpressions(
+ @ParentComponent Optional<ComponentRequirementExpressions> parent,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ CompilerOptions compilerOptions,
+ DaggerElements elements) {
+ this.parent = parent;
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.compilerOptions = compilerOptions;
+ this.elements = elements;
+ }
+
+ /**
+ * Returns an expression for the {@code componentRequirement} to be used when implementing a
+ * component method. This may add a field or method to the component in order to reference the
+ * component requirement outside of the {@code initialize()} methods.
+ */
+ CodeBlock getExpression(ComponentRequirement componentRequirement, ClassName requestingClass) {
+ return getExpression(componentRequirement).getExpression(requestingClass);
+ }
+
+ /**
+ * Returns an expression for the {@code componentRequirement} to be used only within {@code
+ * initialize()} methods, where the component constructor parameters are available.
+ *
+ * <p>When accessing this expression from a subcomponent, this may cause a field to be initialized
+ * or a method to be added in the component that owns this {@link ComponentRequirement}.
+ */
+ CodeBlock getExpressionDuringInitialization(
+ ComponentRequirement componentRequirement, ClassName requestingClass) {
+ return getExpression(componentRequirement).getExpressionDuringInitialization(requestingClass);
+ }
+
+ ComponentRequirementExpression getExpression(ComponentRequirement componentRequirement) {
+ if (graph.componentRequirements().contains(componentRequirement)) {
+ return componentRequirementExpressions.computeIfAbsent(
+ componentRequirement, this::createMethodOrField);
+ }
+ if (parent.isPresent()) {
+ return parent.get().getExpression(componentRequirement);
+ }
+
+ if (componentRequirement.kind().isModule() && compilerOptions.aheadOfTimeSubcomponents()) {
+ return new PrunedModifiableModule(componentRequirement);
+ }
+
+ throw new IllegalStateException(
+ "no component requirement expression found for " + componentRequirement);
+ }
+
+ /**
+ * If {@code requirement} is a module that may be owned by a future ancestor component, returns a
+ * modifiable module method. Otherwise, returns a field for {@code requirement}.
+ */
+ private ComponentRequirementExpression createMethodOrField(ComponentRequirement requirement) {
+ if (componentImplementation.isAbstract() && requirement.kind().isModule()) {
+ return new ModifiableModule(requirement);
+ }
+ return createField(requirement);
+ }
+
+ /** Returns a field for a {@link ComponentRequirement}. */
+ private ComponentRequirementExpression createField(ComponentRequirement requirement) {
+ if (componentImplementation.componentDescriptor().hasCreator()) {
+ return new ComponentParameterField(requirement, componentImplementation, Optional.empty());
+ } else if (graph.factoryMethod().isPresent()
+ && graph.factoryMethodParameters().containsKey(requirement)) {
+ String parameterName =
+ graph.factoryMethodParameters().get(requirement).getSimpleName().toString();
+ return new ComponentParameterField(
+ requirement, componentImplementation, Optional.of(parameterName));
+ } else if (requirement.kind().isModule()) {
+ return new InstantiableModuleField(requirement, componentImplementation);
+ } else {
+ throw new AssertionError(
+ String.format("Can't create %s in %s", requirement, componentImplementation.name()));
+ }
+ }
+
+ private abstract static class AbstractField implements ComponentRequirementExpression {
+ final ComponentRequirement componentRequirement;
+ final ComponentImplementation componentImplementation;
+ final String fieldName;
+ private final Supplier<MemberSelect> field = memoize(this::addField);
+
+ private AbstractField(
+ ComponentRequirement componentRequirement,
+ ComponentImplementation componentImplementation) {
+ this.componentRequirement = checkNotNull(componentRequirement);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ // Note: The field name is being claimed eagerly here even though we don't know at this point
+ // whether or not the requirement will even need a field. This is done because:
+ // A) ComponentParameterField wants to ensure that it doesn't give the parameter the same name
+ // as any field in the component, which requires that it claim a "field name" for itself
+ // when naming the parameter.
+ // B) The parameter name may be needed before the field name is.
+ // C) We want to prefer giving the best name to the field rather than the parameter given its
+ // wider scope.
+ this.fieldName =
+ componentImplementation.getUniqueFieldName(componentRequirement.variableName());
+ }
+
+ @Override
+ public CodeBlock getExpression(ClassName requestingClass) {
+ return field.get().getExpressionFor(requestingClass);
+ }
+
+ private MemberSelect addField() {
+ FieldSpec field = createField();
+ componentImplementation.addField(COMPONENT_REQUIREMENT_FIELD, field);
+ componentImplementation.addComponentRequirementInitialization(fieldInitialization(field));
+ return MemberSelect.localField(componentImplementation.name(), fieldName);
+ }
+
+ private FieldSpec createField() {
+ FieldSpec.Builder field =
+ FieldSpec.builder(TypeName.get(componentRequirement.type()), fieldName, PRIVATE);
+ if (!componentImplementation.isAbstract()) {
+ field.addModifiers(FINAL);
+ }
+ return field.build();
+ }
+
+ /** Returns the {@link CodeBlock} that initializes the component field during construction. */
+ abstract CodeBlock fieldInitialization(FieldSpec componentField);
+ }
+
+ /**
+ * A {@link ComponentRequirementExpression} for {@link ComponentRequirement}s that can be
+ * instantiated by the component (i.e. a static class with a no-arg constructor).
+ */
+ private final class InstantiableModuleField extends AbstractField {
+ private final TypeElement moduleElement;
+
+ private InstantiableModuleField(
+ ComponentRequirement module, ComponentImplementation componentImplementation) {
+ super(module, componentImplementation);
+ checkArgument(module.kind().isModule());
+ this.moduleElement = module.typeElement();
+ }
+
+ @Override
+ CodeBlock fieldInitialization(FieldSpec componentField) {
+ return CodeBlock.of(
+ "this.$N = $L;",
+ componentField,
+ newModuleInstance(moduleElement, componentImplementation.name(), elements));
+ }
+ }
+
+ /**
+ * A {@link ComponentRequirementExpression} for {@link ComponentRequirement}s that are passed in
+ * as parameters to the component's constructor.
+ */
+ private static final class ComponentParameterField extends AbstractField {
+ private final String parameterName;
+
+ private ComponentParameterField(
+ ComponentRequirement componentRequirement,
+ ComponentImplementation componentImplementation,
+ Optional<String> name) {
+ super(componentRequirement, componentImplementation);
+ componentImplementation.addComponentRequirementParameter(componentRequirement);
+ // Get the name that the component implementation will use for its parameter for the
+ // requirement. If the given name is different than the name of the field created for the
+ // requirement (as may be the case when the parameter name is derived from a user-written
+ // factory method parameter), just use that as the base name for the parameter. Otherwise,
+ // append "Param" to the end of the name to differentiate.
+ // In either case, componentImplementation.getParameterName() will ensure that the final name
+ // that is used is not the same name as any field in the component even if there's something
+ // weird where the component actually has fields named, say, "foo" and "fooParam".
+ String baseName = name.filter(n -> !n.equals(fieldName)).orElse(fieldName + "Param");
+ this.parameterName = componentImplementation.getParameterName(componentRequirement, baseName);
+ }
+
+ @Override
+ public CodeBlock getExpressionDuringInitialization(ClassName requestingClass) {
+ if (componentImplementation.name().equals(requestingClass)) {
+ return CodeBlock.of("$L", parameterName);
+ } else {
+ // requesting this component requirement during initialization of a child component requires
+ // it to be accessed from a field and not the parameter (since it is no longer available)
+ return getExpression(requestingClass);
+ }
+ }
+
+ @Override
+ CodeBlock fieldInitialization(FieldSpec componentField) {
+ // Don't checkNotNull here because the parameter may be nullable; if it isn't, the caller
+ // should handle checking that before passing the parameter.
+ return CodeBlock.of("this.$N = $L;", componentField, parameterName);
+ }
+ }
+
+ private final class ModifiableModule implements ComponentRequirementExpression {
+ private final ComponentRequirement module;
+ private final Supplier<MemberSelect> method = Suppliers.memoize(this::methodSelect);
+
+ private ModifiableModule(ComponentRequirement module) {
+ checkArgument(module.kind().isModule());
+ this.module = module;
+ }
+
+ @Override
+ public CodeBlock getExpression(ClassName requestingClass) {
+ return method.get().getExpressionFor(requestingClass);
+ }
+
+ private MemberSelect methodSelect() {
+ String methodName =
+ componentImplementation
+ .supertypeModifiableModuleMethodName(module)
+ .orElseGet(this::createMethod);
+ return MemberSelect.localMethod(componentImplementation.name(), methodName);
+ }
+
+ private String createMethod() {
+ String methodName =
+ UPPER_CAMEL.to(
+ LOWER_CAMEL,
+ componentImplementation.getUniqueMethodName(
+ module.typeElement().getSimpleName().toString()));
+ MethodSpec.Builder methodBuilder =
+ methodBuilder(methodName)
+ .addModifiers(PROTECTED)
+ .returns(TypeName.get(module.type()));
+ // TODO(b/117833324): if the module is instantiable, we could provide an implementation here
+ // too. Then, if no ancestor ever repeats the module, there's nothing to do in subclasses.
+ if (graph.componentDescriptor().creatorDescriptor().isPresent()) {
+ methodBuilder.addStatement(
+ "return $L",
+ createField(module).getExpression(componentImplementation.name()));
+ } else {
+ methodBuilder.addModifiers(ABSTRACT);
+ }
+ componentImplementation.addModifiableModuleMethod(module, methodBuilder.build());
+ return methodName;
+ }
+ }
+
+ private static final class PrunedModifiableModule implements ComponentRequirementExpression {
+ private final ComponentRequirement module;
+
+ private PrunedModifiableModule(ComponentRequirement module) {
+ checkArgument(module.kind().isModule());
+ this.module = module;
+ }
+
+ @Override
+ public CodeBlock getExpression(ClassName requestingClass) {
+ throw new UnsupportedOperationException(module + " is pruned - it cannot be requested");
+ }
+
+ @Override
+ public CodeBlock getModifiableModuleMethodExpression(ClassName requestingClass) {
+ return CodeBlock.builder()
+ .add(
+ "// $L has been pruned from the final resolved binding graph. The result of this "
+ + "method should never be used, but it may be called in an initialize() method "
+ + "when creating a framework instance of a now-pruned binding. Those framework "
+ + "instances should never be used.\n",
+ module.typeElement())
+ .add("return null")
+ .build();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentTreeTraverser.java b/java/dagger/internal/codegen/ComponentTreeTraverser.java
new file mode 100644
index 0000000..cc1efd2
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentTreeTraverser.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterators;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.model.ComponentPath;
+import dagger.model.DependencyRequest;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * An object that traverses the entire component hierarchy, starting from the root component.
+ *
+ * <p>Subclasses can override {@link #visitComponent(BindingGraph)} to perform custom logic at each
+ * component in the tree, and {@link #visitSubcomponentFactoryMethod(BindingGraph, BindingGraph,
+ * ExecutableElement)} to perform custom logic at each subcomponent factory method.
+ */
+public class ComponentTreeTraverser {
+
+ /** The path from the root graph to the currently visited graph. */
+ private final Deque<BindingGraph> bindingGraphPath = new ArrayDeque<>();
+
+ /** The {@link ComponentPath} for each component in {@link #bindingGraphPath}. */
+ private final Deque<ComponentPath> componentPaths = new ArrayDeque<>();
+
+ /** Constructs a traverser for a root (component, not subcomponent) binding graph. */
+ public ComponentTreeTraverser(BindingGraph rootGraph) {
+ bindingGraphPath.add(rootGraph);
+ componentPaths.add(ComponentPath.create(ImmutableList.of(rootGraph.componentTypeElement())));
+ }
+
+ /**
+ * Calls {@link #visitComponent(BindingGraph)} for the root component.
+ *
+ * @throws IllegalStateException if a traversal is in progress
+ */
+ public final void traverseComponents() {
+ checkState(bindingGraphPath.size() == 1);
+ checkState(componentPaths.size() == 1);
+ visitComponent(bindingGraphPath.getFirst());
+ }
+
+ /**
+ * Called once for each component in a component hierarchy.
+ *
+ * <p>Subclasses can override this method to perform whatever logic is required per component.
+ * They should call the {@code super} implementation if they want to continue the traversal in the
+ * standard order.
+ *
+ * <p>This implementation does the following:
+ *
+ * <ol>
+ * <li>If this component is installed in its parent by a subcomponent factory method, calls
+ * {@link #visitSubcomponentFactoryMethod(BindingGraph, BindingGraph, ExecutableElement)}.
+ * <li>For each entry point in the component, calls {@link #visitEntryPoint(DependencyRequest,
+ * BindingGraph)}.
+ * <li>For each child component, calls {@link #visitComponent(BindingGraph)}, updating the
+ * traversal state.
+ * </ol>
+ *
+ * @param graph the currently visited graph
+ */
+ protected void visitComponent(BindingGraph graph) {
+ if (bindingGraphPath.size() > 1) {
+ BindingGraph parent = Iterators.get(bindingGraphPath.descendingIterator(), 1);
+ parent
+ .componentDescriptor()
+ .getFactoryMethodForChildComponent(graph.componentDescriptor())
+ .ifPresent(
+ childFactoryMethod ->
+ visitSubcomponentFactoryMethod(
+ graph, parent, childFactoryMethod.methodElement()));
+ }
+
+ for (ComponentMethodDescriptor entryPointMethod :
+ graph.componentDescriptor().entryPointMethods()) {
+ visitEntryPoint(entryPointMethod.dependencyRequest().get(), graph);
+ }
+
+ for (BindingGraph child : graph.subgraphs()) {
+ bindingGraphPath.addLast(child);
+ ComponentPath childPath =
+ ComponentPath.create(
+ bindingGraphPath.stream()
+ .map(BindingGraph::componentTypeElement)
+ .collect(toImmutableList()));
+ componentPaths.addLast(childPath);
+ try {
+ visitComponent(child);
+ } finally {
+ verify(bindingGraphPath.removeLast().equals(child));
+ verify(componentPaths.removeLast().equals(childPath));
+ }
+ }
+ }
+
+ /**
+ * Called if this component was installed in its parent by a subcomponent factory method.
+ *
+ * <p>This implementation does nothing.
+ *
+ * @param graph the currently visited graph
+ * @param parent the parent graph
+ * @param factoryMethod the factory method in the parent component that declares that the current
+ * component is a child
+ */
+ protected void visitSubcomponentFactoryMethod(
+ BindingGraph graph, BindingGraph parent, ExecutableElement factoryMethod) {}
+
+ /**
+ * Called once for each entry point in a component.
+ *
+ * <p>Subclasses can override this method to perform whatever logic is required per entry point.
+ * They should call the {@code super} implementation if they want to continue the traversal in the
+ * standard order.
+ *
+ * <p>This implementation does nothing.
+ *
+ * @param graph the graph for the component that contains the entry point
+ */
+ protected void visitEntryPoint(DependencyRequest entryPoint, BindingGraph graph) {}
+
+ /**
+ * Returns an immutable snapshot of the path from the root component to the currently visited
+ * component.
+ */
+ protected final ComponentPath componentPath() {
+ return componentPaths.getLast();
+ }
+
+ /**
+ * Returns the subpath from the root component to the matching {@code ancestor} of the current
+ * component.
+ */
+ protected final ComponentPath pathFromRootToAncestor(TypeElement ancestor) {
+ for (ComponentPath componentPath : componentPaths) {
+ if (componentPath.currentComponent().equals(ancestor)) {
+ return componentPath;
+ }
+ }
+ throw new IllegalArgumentException(
+ String.format("%s is not in the current path: %s", ancestor.getQualifiedName(), this));
+ }
+
+ /**
+ * Returns the BindingGraph for {@code ancestor}, where {@code ancestor} is in the component path
+ * of the current traversal.
+ */
+ protected final BindingGraph graphForAncestor(TypeElement ancestor) {
+ for (BindingGraph graph : bindingGraphPath) {
+ if (graph.componentTypeElement().equals(ancestor)) {
+ return graph;
+ }
+ }
+ throw new IllegalArgumentException(
+ String.format("%s is not in the current path: %s", ancestor.getQualifiedName(), this));
+ }
+}
diff --git a/java/dagger/internal/codegen/ComponentValidator.java b/java/dagger/internal/codegen/ComponentValidator.java
new file mode 100644
index 0000000..7739915
--- /dev/null
+++ b/java/dagger/internal/codegen/ComponentValidator.java
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.asType;
+import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.auto.common.MoreTypes.asDeclared;
+import static com.google.auto.common.MoreTypes.asExecutable;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.collect.Multimaps.asMap;
+import static com.google.common.collect.Sets.intersection;
+import static dagger.internal.codegen.ComponentAnnotation.anyComponentAnnotation;
+import static dagger.internal.codegen.ComponentAnnotation.componentAnnotation;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.creatorAnnotationsFor;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.productionCreatorAnnotations;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
+import static dagger.internal.codegen.ComponentKind.annotationsFor;
+import static dagger.internal.codegen.ConfigurationAnnotations.enclosedAnnotatedTypes;
+import static dagger.internal.codegen.ConfigurationAnnotations.getTransitiveModules;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.ErrorMessages.ComponentCreatorMessages.builderMethodRequiresNoArgs;
+import static dagger.internal.codegen.ErrorMessages.ComponentCreatorMessages.moreThanOneRefToSubcomponent;
+import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
+import static java.util.Comparator.comparing;
+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.type.TypeKind.VOID;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import dagger.Component;
+import dagger.Reusable;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.producers.CancellationPolicy;
+import dagger.producers.ProductionComponent;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+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.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor6;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * Performs superficial validation of the contract of the {@link Component} and {@link
+ * ProductionComponent} annotations.
+ */
+final class ComponentValidator {
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final ModuleValidator moduleValidator;
+ private final ComponentCreatorValidator creatorValidator;
+ private final DependencyRequestValidator dependencyRequestValidator;
+ private final MembersInjectionValidator membersInjectionValidator;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+ private final DependencyRequestFactory dependencyRequestFactory;
+
+ @Inject
+ ComponentValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ ModuleValidator moduleValidator,
+ ComponentCreatorValidator creatorValidator,
+ DependencyRequestValidator dependencyRequestValidator,
+ MembersInjectionValidator membersInjectionValidator,
+ MethodSignatureFormatter methodSignatureFormatter,
+ DependencyRequestFactory dependencyRequestFactory) {
+ this.elements = elements;
+ this.types = types;
+ this.moduleValidator = moduleValidator;
+ this.creatorValidator = creatorValidator;
+ this.dependencyRequestValidator = dependencyRequestValidator;
+ this.membersInjectionValidator = membersInjectionValidator;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ @AutoValue
+ abstract static class ComponentValidationReport {
+ abstract ImmutableSet<Element> referencedSubcomponents();
+
+ abstract ValidationReport<TypeElement> report();
+ }
+
+ /**
+ * Validates the given component subject. Also validates any referenced subcomponents that aren't
+ * already included in the {@code validatedSubcomponents} set.
+ */
+ public ComponentValidationReport validate(
+ TypeElement subject,
+ Set<? extends Element> validatedSubcomponents,
+ Set<? extends Element> validatedSubcomponentCreators) {
+ ValidationReport.Builder<TypeElement> report = ValidationReport.about(subject);
+
+ ImmutableSet<ComponentKind> componentKinds = ComponentKind.getComponentKinds(subject);
+ ImmutableSet<Element> allSubcomponents;
+ if (componentKinds.size() > 1) {
+ String error =
+ "Components may not be annotated with more than one component annotation: found "
+ + annotationsFor(componentKinds);
+ report.addError(error, subject);
+ allSubcomponents = ImmutableSet.of();
+ } else {
+ ComponentKind componentKind = getOnlyElement(componentKinds);
+ ComponentAnnotation componentAnnotation = anyComponentAnnotation(subject).get();
+ allSubcomponents =
+ validate(
+ subject,
+ componentAnnotation,
+ componentKind,
+ validatedSubcomponents,
+ validatedSubcomponentCreators,
+ report);
+ }
+
+ return new AutoValue_ComponentValidator_ComponentValidationReport(
+ allSubcomponents, report.build());
+ }
+
+ private ImmutableSet<Element> validate(
+ TypeElement subject,
+ ComponentAnnotation componentAnnotation,
+ ComponentKind componentKind,
+ Set<? extends Element> validatedSubcomponents,
+ Set<? extends Element> validatedSubcomponentCreators,
+ ValidationReport.Builder<TypeElement> report) {
+ if (isAnnotationPresent(subject, CancellationPolicy.class) && !componentKind.isProducer()) {
+ report.addError(
+ "@CancellationPolicy may only be applied to production components and subcomponents",
+ subject);
+ }
+
+ if (!subject.getKind().equals(INTERFACE)
+ && !(subject.getKind().equals(CLASS) && subject.getModifiers().contains(ABSTRACT))) {
+ report.addError(
+ String.format(
+ "@%s may only be applied to an interface or abstract class",
+ componentKind.annotation().getSimpleName()),
+ subject);
+ }
+
+ ImmutableList<DeclaredType> creators =
+ creatorAnnotationsFor(componentAnnotation).stream()
+ .flatMap(annotation -> enclosedAnnotatedTypes(subject, annotation).stream())
+ .collect(toImmutableList());
+ if (creators.size() > 1) {
+ report.addError(
+ String.format(ErrorMessages.componentMessagesFor(componentKind).moreThanOne(), creators),
+ subject);
+ }
+
+ Optional<AnnotationMirror> reusableAnnotation = getAnnotationMirror(subject, Reusable.class);
+ if (reusableAnnotation.isPresent()) {
+ report.addError(
+ "@Reusable cannot be applied to components or subcomponents",
+ subject,
+ reusableAnnotation.get());
+ }
+
+ DeclaredType subjectType = MoreTypes.asDeclared(subject.asType());
+
+ SetMultimap<Element, ExecutableElement> referencedSubcomponents = LinkedHashMultimap.create();
+ getLocalAndInheritedMethods(subject, types, elements).stream()
+ .filter(method -> method.getModifiers().contains(ABSTRACT))
+ .forEachOrdered(
+ method -> {
+ ExecutableType resolvedMethod = asExecutable(types.asMemberOf(subjectType, method));
+ List<? extends TypeMirror> parameterTypes = resolvedMethod.getParameterTypes();
+ List<? extends VariableElement> parameters = method.getParameters();
+ TypeMirror returnType = resolvedMethod.getReturnType();
+
+ if (!resolvedMethod.getTypeVariables().isEmpty()) {
+ report.addError("Component methods cannot have type variables", method);
+ }
+
+ // abstract methods are ones we have to implement, so they each need to be validated
+ // first, check the return type. if it's a subcomponent, validate that method as such.
+ Optional<AnnotationMirror> subcomponentAnnotation =
+ checkForAnnotations(
+ returnType,
+ componentKind.legalSubcomponentKinds().stream()
+ .map(ComponentKind::annotation)
+ .collect(toImmutableSet()));
+ Optional<AnnotationMirror> subcomponentCreatorAnnotation =
+ checkForAnnotations(
+ returnType,
+ componentAnnotation.isProduction()
+ ? intersection(
+ subcomponentCreatorAnnotations(), productionCreatorAnnotations())
+ : subcomponentCreatorAnnotations());
+ if (subcomponentAnnotation.isPresent()) {
+ referencedSubcomponents.put(MoreTypes.asElement(returnType), method);
+ validateSubcomponentMethod(
+ report,
+ ComponentKind.forAnnotatedElement(MoreTypes.asTypeElement(returnType)).get(),
+ method,
+ parameters,
+ parameterTypes,
+ returnType,
+ subcomponentAnnotation);
+ } else if (subcomponentCreatorAnnotation.isPresent()) {
+ referencedSubcomponents.put(
+ MoreTypes.asElement(returnType).getEnclosingElement(), method);
+ validateSubcomponentCreatorMethod(
+ report, method, parameters, returnType, validatedSubcomponentCreators);
+ } else {
+ // if it's not a subcomponent...
+ switch (parameters.size()) {
+ case 0:
+ // no parameters means that it is a provision method
+ dependencyRequestValidator.validateDependencyRequest(
+ report, method, returnType);
+ break;
+ case 1:
+ // one parameter means that it's a members injection method
+ TypeMirror parameterType = Iterables.getOnlyElement(parameterTypes);
+ report.addSubreport(
+ membersInjectionValidator.validateMembersInjectionMethod(
+ method, parameterType));
+ if (!(returnType.getKind().equals(VOID)
+ || types.isSameType(returnType, parameterType))) {
+ report.addError(
+ "Members injection methods may only return the injected type or void.",
+ method);
+ }
+ break;
+ default:
+ // this isn't any method that we know how to implement...
+ report.addError(
+ "This method isn't a valid provision method, members injection method or "
+ + "subcomponent factory method. Dagger cannot implement this method",
+ method);
+ break;
+ }
+ }
+ });
+
+ checkConflictingEntryPoints(report);
+
+ Maps.filterValues(referencedSubcomponents.asMap(), methods -> methods.size() > 1)
+ .forEach(
+ (subcomponent, methods) ->
+ report.addError(
+ String.format(moreThanOneRefToSubcomponent(), subcomponent, methods), subject));
+
+ validateComponentDependencies(report, componentAnnotation.dependencyTypes());
+ report.addSubreport(
+ moduleValidator.validateReferencedModules(
+ subject,
+ componentAnnotation.annotation(),
+ componentKind.legalModuleKinds(),
+ new HashSet<>()));
+
+ // Make sure we validate any subcomponents we're referencing, unless we know we validated
+ // them already in this pass.
+ // TODO(sameb): If subcomponents refer to each other and both aren't in
+ // 'validatedSubcomponents' (e.g, both aren't compiled in this pass),
+ // then this can loop forever.
+ ImmutableSet.Builder<Element> allSubcomponents =
+ ImmutableSet.<Element>builder().addAll(referencedSubcomponents.keySet());
+ for (Element subcomponent :
+ Sets.difference(referencedSubcomponents.keySet(), validatedSubcomponents)) {
+ ComponentValidationReport subreport =
+ validate(asType(subcomponent), validatedSubcomponents, validatedSubcomponentCreators);
+ report.addItems(subreport.report().items());
+ allSubcomponents.addAll(subreport.referencedSubcomponents());
+ }
+ return allSubcomponents.build();
+ }
+
+ private void checkConflictingEntryPoints(ValidationReport.Builder<TypeElement> report) {
+ DeclaredType componentType = asDeclared(report.getSubject().asType());
+
+ // Collect entry point methods that are not overridden by others. If the "same" method is
+ // inherited from more than one supertype, each will be in the multimap.
+ SetMultimap<String, ExecutableElement> entryPointMethods = HashMultimap.create();
+
+ methodsIn(elements.getAllMembers(report.getSubject()))
+ .stream()
+ .filter(
+ method -> isEntryPoint(method, asExecutable(types.asMemberOf(componentType, method))))
+ .forEach(
+ method ->
+ addMethodUnlessOverridden(
+ method, entryPointMethods.get(method.getSimpleName().toString())));
+
+ for (Set<ExecutableElement> methods : asMap(entryPointMethods).values()) {
+ if (distinctKeys(methods, report.getSubject()).size() > 1) {
+ reportConflictingEntryPoints(methods, report);
+ }
+ }
+ }
+
+ private boolean isEntryPoint(ExecutableElement method, ExecutableType methodType) {
+ return method.getModifiers().contains(ABSTRACT)
+ && method.getParameters().isEmpty()
+ && !methodType.getReturnType().getKind().equals(VOID)
+ && methodType.getTypeVariables().isEmpty();
+ }
+
+ private ImmutableSet<Key> distinctKeys(Set<ExecutableElement> methods, TypeElement component) {
+ return methods
+ .stream()
+ .map(method -> dependencyRequest(method, component))
+ .map(DependencyRequest::key)
+ .collect(toImmutableSet());
+ }
+
+ private DependencyRequest dependencyRequest(ExecutableElement method, TypeElement component) {
+ ExecutableType methodType =
+ asExecutable(types.asMemberOf(asDeclared(component.asType()), method));
+ return ComponentKind.forAnnotatedElement(component).get().isProducer()
+ ? dependencyRequestFactory.forComponentProductionMethod(method, methodType)
+ : dependencyRequestFactory.forComponentProvisionMethod(method, methodType);
+ }
+
+ private void addMethodUnlessOverridden(ExecutableElement method, Set<ExecutableElement> methods) {
+ if (methods.stream().noneMatch(existingMethod -> overridesAsDeclared(existingMethod, method))) {
+ methods.removeIf(existingMethod -> overridesAsDeclared(method, existingMethod));
+ methods.add(method);
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code overrider} overrides {@code overridden} considered from within
+ * the type that declares {@code overrider}.
+ */
+ // TODO(dpb): Does this break for ECJ?
+ private boolean overridesAsDeclared(ExecutableElement overridder, ExecutableElement overridden) {
+ return elements.overrides(overridder, overridden, asType(overridder.getEnclosingElement()));
+ }
+
+ private void reportConflictingEntryPoints(
+ Collection<ExecutableElement> methods, ValidationReport.Builder<TypeElement> report) {
+ verify(
+ methods.stream().map(ExecutableElement::getEnclosingElement).distinct().count()
+ == methods.size(),
+ "expected each method to be declared on a different type: %s",
+ methods);
+ StringBuilder message = new StringBuilder("conflicting entry point declarations:");
+ methodSignatureFormatter
+ .typedFormatter(asDeclared(report.getSubject().asType()))
+ .formatIndentedList(
+ message,
+ ImmutableList.sortedCopyOf(
+ comparing(
+ method -> asType(method.getEnclosingElement()).getQualifiedName().toString()),
+ methods),
+ 1);
+ report.addError(message.toString());
+ }
+
+ private void validateSubcomponentMethod(
+ final ValidationReport.Builder<TypeElement> report,
+ final ComponentKind subcomponentKind,
+ ExecutableElement method,
+ List<? extends VariableElement> parameters,
+ List<? extends TypeMirror> parameterTypes,
+ TypeMirror returnType,
+ Optional<AnnotationMirror> subcomponentAnnotation) {
+ ImmutableSet<TypeElement> moduleTypes =
+ componentAnnotation(subcomponentAnnotation.get()).modules();
+
+ // TODO(gak): This logic maybe/probably shouldn't live here as it requires us to traverse
+ // subcomponents and their modules separately from how it is done in ComponentDescriptor and
+ // ModuleDescriptor
+ @SuppressWarnings("deprecation")
+ ImmutableSet<TypeElement> transitiveModules =
+ getTransitiveModules(types, elements, moduleTypes);
+
+ Set<TypeElement> variableTypes = Sets.newHashSet();
+
+ for (int i = 0; i < parameterTypes.size(); i++) {
+ VariableElement parameter = parameters.get(i);
+ TypeMirror parameterType = parameterTypes.get(i);
+ Optional<TypeElement> moduleType =
+ parameterType.accept(
+ new SimpleTypeVisitor6<Optional<TypeElement>, Void>() {
+ @Override
+ protected Optional<TypeElement> defaultAction(TypeMirror e, Void p) {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<TypeElement> visitDeclared(DeclaredType t, Void p) {
+ for (ModuleKind moduleKind : subcomponentKind.legalModuleKinds()) {
+ if (isAnnotationPresent(t.asElement(), moduleKind.annotation())) {
+ return Optional.of(MoreTypes.asTypeElement(t));
+ }
+ }
+ return Optional.empty();
+ }
+ },
+ null);
+ if (moduleType.isPresent()) {
+ if (variableTypes.contains(moduleType.get())) {
+ report.addError(
+ String.format(
+ "A module may only occur once an an argument in a Subcomponent factory "
+ + "method, but %s was already passed.",
+ moduleType.get().getQualifiedName()),
+ parameter);
+ }
+ if (!transitiveModules.contains(moduleType.get())) {
+ report.addError(
+ String.format(
+ "%s is present as an argument to the %s factory method, but is not one of the"
+ + " modules used to implement the subcomponent.",
+ moduleType.get().getQualifiedName(),
+ MoreTypes.asTypeElement(returnType).getQualifiedName()),
+ method);
+ }
+ variableTypes.add(moduleType.get());
+ } else {
+ report.addError(
+ String.format(
+ "Subcomponent factory methods may only accept modules, but %s is not.",
+ parameterType),
+ parameter);
+ }
+ }
+ }
+
+ private void validateSubcomponentCreatorMethod(
+ ValidationReport.Builder<TypeElement> report,
+ ExecutableElement method,
+ List<? extends VariableElement> parameters,
+ TypeMirror returnType,
+ Set<? extends Element> validatedSubcomponentCreators) {
+ if (!parameters.isEmpty()) {
+ report.addError(builderMethodRequiresNoArgs(), method);
+ }
+
+ // If we haven't already validated the subcomponent creator itself, validate it now.
+ TypeElement creatorElement = MoreTypes.asTypeElement(returnType);
+ if (!validatedSubcomponentCreators.contains(creatorElement)) {
+ // TODO(sameb): The creator validator right now assumes the element is being compiled
+ // in this pass, which isn't true here. We should change error messages to spit out
+ // this method as the subject and add the original subject to the message output.
+ report.addItems(creatorValidator.validate(creatorElement).items());
+ }
+ }
+
+ private static <T extends Element> void validateComponentDependencies(
+ ValidationReport.Builder<T> report, Iterable<TypeMirror> types) {
+ for (TypeMirror type : types) {
+ type.accept(CHECK_DEPENDENCY_TYPES, report);
+ }
+ }
+
+ private static final TypeVisitor<Void, ValidationReport.Builder<?>> CHECK_DEPENDENCY_TYPES =
+ new SimpleTypeVisitor8<Void, ValidationReport.Builder<?>>() {
+ @Override
+ protected Void defaultAction(TypeMirror type, ValidationReport.Builder<?> report) {
+ report.addError(type + " is not a valid component dependency type");
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType type, ValidationReport.Builder<?> report) {
+ if (moduleAnnotation(MoreTypes.asTypeElement(type)).isPresent()) {
+ report.addError(type + " is a module, which cannot be a component dependency");
+ }
+ return null;
+ }
+ };
+
+ private static Optional<AnnotationMirror> checkForAnnotations(
+ TypeMirror type, final Set<? extends Class<? extends Annotation>> annotations) {
+ return type.accept(
+ new SimpleTypeVisitor6<Optional<AnnotationMirror>, Void>(Optional.empty()) {
+ @Override
+ public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
+ return getAnyAnnotation(t.asElement(), annotations);
+ }
+ },
+ null);
+ }
+}
diff --git a/java/dagger/internal/codegen/ConfigurationAnnotations.java b/java/dagger/internal/codegen/ConfigurationAnnotations.java
new file mode 100644
index 0000000..a9bba29
--- /dev/null
+++ b/java/dagger/internal/codegen/ConfigurationAnnotations.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.consumingIterable;
+import static dagger.internal.codegen.ComponentAnnotation.subcomponentAnnotation;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
+import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
+import static dagger.internal.codegen.MoreAnnotationMirrors.getTypeListValue;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static javax.lang.model.util.ElementFilter.typesIn;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+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 dagger.Component;
+import dagger.Module;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.lang.annotation.Annotation;
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.Optional;
+import java.util.Queue;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Utility methods related to dagger configuration annotations (e.g.: {@link Component}
+ * and {@link Module}).
+ */
+final class ConfigurationAnnotations {
+
+ static Optional<TypeElement> getSubcomponentCreator(TypeElement subcomponent) {
+ checkArgument(subcomponentAnnotation(subcomponent).isPresent());
+ for (TypeElement nestedType : typesIn(subcomponent.getEnclosedElements())) {
+ if (isSubcomponentCreator(nestedType)) {
+ return Optional.of(nestedType);
+ }
+ }
+ return Optional.empty();
+ }
+
+ static boolean isSubcomponentCreator(Element element) {
+ return isAnyAnnotationPresent(element, subcomponentCreatorAnnotations());
+ }
+
+ // Dagger 1 support.
+ static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
+ checkNotNull(moduleAnnotation);
+ return getTypeListValue(moduleAnnotation, "injects");
+ }
+
+ /** Returns the first type that specifies this' nullability, or empty if none. */
+ static Optional<DeclaredType> getNullableType(Element element) {
+ List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
+ for (AnnotationMirror mirror : mirrors) {
+ if (mirror.getAnnotationType().asElement().getSimpleName().contentEquals("Nullable")) {
+ return Optional.of(mirror.getAnnotationType());
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Returns the full set of modules transitively {@linkplain Module#includes included} from the
+ * given seed modules. If a module is malformed and a type listed in {@link Module#includes} is
+ * not annotated with {@link Module}, it is ignored.
+ *
+ * @deprecated Use {@link ComponentDescriptor#modules()}.
+ */
+ @Deprecated
+ static ImmutableSet<TypeElement> getTransitiveModules(
+ DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules) {
+ TypeMirror objectType = elements.getTypeElement(Object.class).asType();
+ Queue<TypeElement> moduleQueue = new ArrayDeque<>();
+ Iterables.addAll(moduleQueue, seedModules);
+ Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
+ for (TypeElement moduleElement : consumingIterable(moduleQueue)) {
+ moduleAnnotation(moduleElement)
+ .ifPresent(
+ moduleAnnotation -> {
+ ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder =
+ ImmutableSet.builder();
+ moduleDependenciesBuilder.addAll(moduleAnnotation.includes());
+ // We don't recur on the parent class because we don't want the parent class as a
+ // root that the component depends on, and also because we want the dependencies
+ // rooted against this element, not the parent.
+ addIncludesFromSuperclasses(
+ types, moduleElement, moduleDependenciesBuilder, objectType);
+ ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build();
+ moduleElements.add(moduleElement);
+ for (TypeElement dependencyType : moduleDependencies) {
+ if (!moduleElements.contains(dependencyType)) {
+ moduleQueue.add(dependencyType);
+ }
+ }
+ });
+ }
+ return ImmutableSet.copyOf(moduleElements);
+ }
+
+ /** Returns the enclosed types annotated with the given annotation. */
+ static ImmutableList<DeclaredType> enclosedAnnotatedTypes(
+ TypeElement typeElement, Class<? extends Annotation> annotation) {
+ final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
+ for (TypeElement element : typesIn(typeElement.getEnclosedElements())) {
+ if (MoreElements.isAnnotationPresent(element, annotation)) {
+ builders.add(MoreTypes.asDeclared(element.asType()));
+ }
+ }
+ return builders.build();
+ }
+
+ /** Traverses includes from superclasses and adds them into the builder. */
+ private static void addIncludesFromSuperclasses(
+ DaggerTypes types,
+ TypeElement element,
+ ImmutableSet.Builder<TypeElement> builder,
+ TypeMirror objectType) {
+ // Also add the superclass to the queue, in case any @Module definitions were on that.
+ TypeMirror superclass = element.getSuperclass();
+ while (!types.isSameType(objectType, superclass)
+ && superclass.getKind().equals(TypeKind.DECLARED)) {
+ element = MoreElements.asType(types.asElement(superclass));
+ moduleAnnotation(element)
+ .ifPresent(moduleAnnotation -> builder.addAll(moduleAnnotation.includes()));
+ superclass = element.getSuperclass();
+ }
+ }
+
+ private ConfigurationAnnotations() {}
+}
diff --git a/java/dagger/internal/codegen/ContributionBinding.java b/java/dagger/internal/codegen/ContributionBinding.java
new file mode 100644
index 0000000..0958bc8
--- /dev/null
+++ b/java/dagger/internal/codegen/ContributionBinding.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.CLASS_CONSTRUCTOR;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.DELEGATE;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
+import static dagger.internal.codegen.MapKeys.unwrapValue;
+import static dagger.internal.codegen.MoreAnnotationMirrors.unwrapOptionalEquivalence;
+import static java.util.Arrays.asList;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.base.Equivalence;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CheckReturnValue;
+import dagger.internal.codegen.ContributionType.HasContributionType;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * An abstract class for a value object representing the mechanism by which a {@link Key} can be
+ * contributed to a dependency graph.
+ */
+abstract class ContributionBinding extends Binding implements HasContributionType {
+
+ /** Returns the type that specifies this' nullability, absent if not nullable. */
+ abstract Optional<DeclaredType> nullableType();
+
+ abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation();
+
+ final Optional<AnnotationMirror> mapKeyAnnotation() {
+ return unwrapOptionalEquivalence(wrappedMapKeyAnnotation());
+ }
+
+ /**
+ * If this is a map contribution, returns the key of its map entry.
+ *
+ * @throws IllegalStateException if {@link #mapKeyAnnotation()} returns an empty value.
+ */
+ final Object mapKey() {
+ checkState(mapKeyAnnotation().isPresent());
+ AnnotationMirror mapKeyAnnotation = mapKeyAnnotation().get();
+ return unwrapValue(mapKeyAnnotation).map(AnnotationValue::getValue).orElse(mapKeyAnnotation);
+ }
+
+ /** If {@link #bindingElement()} is a method that returns a primitive type, returns that type. */
+ final Optional<TypeMirror> contributedPrimitiveType() {
+ return bindingElement()
+ .filter(bindingElement -> bindingElement instanceof ExecutableElement)
+ .map(bindingElement -> MoreElements.asExecutable(bindingElement).getReturnType())
+ .filter(type -> type.getKind().isPrimitive());
+ }
+
+ @Override
+ public final boolean isNullable() {
+ return nullableType().isPresent();
+ }
+
+ /**
+ * The strategy for getting an instance of a factory for a {@link ContributionBinding}.
+ */
+ enum FactoryCreationStrategy {
+ /** The factory class is a single instance. */
+ SINGLETON_INSTANCE,
+ /** The factory must be created by calling the constructor. */
+ CLASS_CONSTRUCTOR,
+ /** The factory is simply delegated to another. */
+ DELEGATE,
+ }
+
+ /**
+ * Returns the {@link FactoryCreationStrategy} appropriate for a binding.
+ *
+ * <p>Delegate bindings use the {@link FactoryCreationStrategy#DELEGATE} strategy.
+ *
+ * <p>Bindings without dependencies that don't require a module instance use the {@link
+ * FactoryCreationStrategy#SINGLETON_INSTANCE} strategy.
+ *
+ * <p>All other bindings use the {@link FactoryCreationStrategy#CLASS_CONSTRUCTOR} strategy.
+ */
+ final FactoryCreationStrategy factoryCreationStrategy() {
+ switch (kind()) {
+ case DELEGATE:
+ return DELEGATE;
+ case PROVISION:
+ return dependencies().isEmpty() && !requiresModuleInstance()
+ ? SINGLETON_INSTANCE
+ : CLASS_CONSTRUCTOR;
+ case INJECTION:
+ case MULTIBOUND_SET:
+ case MULTIBOUND_MAP:
+ return dependencies().isEmpty() ? SINGLETON_INSTANCE : CLASS_CONSTRUCTOR;
+ default:
+ return CLASS_CONSTRUCTOR;
+ }
+ }
+
+ /**
+ * The {@link TypeMirror type} for the {@code Factory<T>} or {@code Producer<T>} which is created
+ * for this binding. Uses the binding's key, V in the case of {@code Map<K, FrameworkClass<V>>>},
+ * and E {@code Set<E>} for {@link dagger.multibindings.IntoSet @IntoSet} methods.
+ */
+ final TypeMirror contributedType() {
+ switch (contributionType()) {
+ case MAP:
+ return MapType.from(key()).unwrappedFrameworkValueType();
+ case SET:
+ return SetType.from(key()).elementType();
+ case SET_VALUES:
+ case UNIQUE:
+ return key().type();
+ }
+ throw new AssertionError();
+ }
+
+ final boolean isSyntheticMultibinding() {
+ switch (kind()) {
+ case MULTIBOUND_SET:
+ case MULTIBOUND_MAP:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Whether the bound type has a generated implementation. */
+ final boolean requiresGeneratedInstance() {
+ switch (kind()) {
+ case COMPONENT:
+ case SUBCOMPONENT_CREATOR:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns {@link BindingKind#MULTIBOUND_SET} or {@link
+ * BindingKind#MULTIBOUND_MAP} if the key is a set or map.
+ *
+ * @throws IllegalArgumentException if {@code key} is neither a set nor a map
+ */
+ static BindingKind bindingKindForMultibindingKey(Key key) {
+ if (SetType.isSet(key)) {
+ return BindingKind.MULTIBOUND_SET;
+ } else if (MapType.isMap(key)) {
+ return BindingKind.MULTIBOUND_MAP;
+ } else {
+ throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
+ }
+ }
+
+ /**
+ * Base builder for {@link com.google.auto.value.AutoValue @AutoValue} subclasses of {@link
+ * ContributionBinding}.
+ */
+ @CanIgnoreReturnValue
+ abstract static class Builder<C extends ContributionBinding, B extends Builder<C, B>> {
+ abstract B dependencies(Iterable<DependencyRequest> dependencies);
+
+ B dependencies(DependencyRequest... dependencies) {
+ return dependencies(asList(dependencies));
+ }
+
+ abstract B unresolved(C unresolved);
+
+ abstract B contributionType(ContributionType contributionType);
+
+ abstract B bindingElement(Element bindingElement);
+
+ abstract B contributingModule(TypeElement contributingModule);
+
+ abstract B key(Key key);
+
+ abstract B nullableType(Optional<DeclaredType> nullableType);
+
+ abstract B wrappedMapKeyAnnotation(
+ Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation);
+
+ abstract B kind(BindingKind kind);
+
+ @CheckReturnValue
+ abstract C build();
+ }
+}
diff --git a/java/dagger/internal/codegen/ContributionType.java b/java/dagger/internal/codegen/ContributionType.java
new file mode 100644
index 0000000..66b5289
--- /dev/null
+++ b/java/dagger/internal/codegen/ContributionType.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.IntoSet;
+import javax.lang.model.element.Element;
+
+/** Whether a binding or declaration is for a unique contribution or a map or set multibinding. */
+enum ContributionType {
+ /** Represents map bindings. */
+ MAP,
+ /** Represents set bindings. */
+ SET,
+ /** Represents set values bindings. */
+ SET_VALUES,
+ /** Represents a valid non-collection binding. */
+ UNIQUE,
+ ;
+
+ /** An object that is associated with a {@link ContributionType}. */
+ interface HasContributionType {
+
+ /** The contribution type of this object. */
+ ContributionType contributionType();
+ }
+
+ /** {@code true} if this is for a multibinding. */
+ boolean isMultibinding() {
+ return !this.equals(UNIQUE);
+ }
+
+ /**
+ * The contribution type from a binding element's annotations. Presumes a well-formed binding
+ * element (at most one of @IntoSet, @IntoMap, @ElementsIntoSet and @Provides.type). {@link
+ * BindingMethodValidator} and {@link BindsInstanceProcessingStep} validate correctness on their
+ * own.
+ */
+ static ContributionType fromBindingElement(Element element) {
+ if (isAnnotationPresent(element, IntoMap.class)) {
+ return ContributionType.MAP;
+ } else if (isAnnotationPresent(element, IntoSet.class)) {
+ return ContributionType.SET;
+ } else if (isAnnotationPresent(element, ElementsIntoSet.class)) {
+ return ContributionType.SET_VALUES;
+ }
+ return ContributionType.UNIQUE;
+ }
+}
diff --git a/java/dagger/internal/codegen/CurrentImplementationSubcomponent.java b/java/dagger/internal/codegen/CurrentImplementationSubcomponent.java
new file mode 100644
index 0000000..c78d60d
--- /dev/null
+++ b/java/dagger/internal/codegen/CurrentImplementationSubcomponent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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 dagger.BindsInstance;
+import dagger.Subcomponent;
+import dagger.internal.codegen.ComponentImplementationBuilder.RootComponentImplementationBuilder;
+import dagger.internal.codegen.ComponentImplementationBuilder.SubcomponentImplementationBuilder;
+import java.util.Optional;
+
+/**
+ * A subcomponent that injects all objects that are responsible for creating a single {@link
+ * ComponentImplementation} instance. Each child {@link ComponentImplementation} will have its own
+ * instance of {@link CurrentImplementationSubcomponent}.
+ */
+@Subcomponent(modules = GenerationOptionsModule.class)
+@PerComponentImplementation
+interface CurrentImplementationSubcomponent {
+ RootComponentImplementationBuilder rootComponentBuilder();
+
+ SubcomponentImplementationBuilder subcomponentBuilder();
+
+ @Subcomponent.Builder
+ interface Builder {
+ @BindsInstance
+ Builder componentImplementation(ComponentImplementation componentImplementation);
+
+ @BindsInstance
+ Builder bindingGraph(BindingGraph bindingGraph);
+
+ @BindsInstance
+ Builder parentBuilder(@ParentComponent Optional<ComponentImplementationBuilder> parentBuilder);
+
+ @BindsInstance
+ Builder parentBindingExpressions(
+ @ParentComponent Optional<ComponentBindingExpressions> parentBindingExpressions);
+
+ @BindsInstance
+ Builder parentRequirementExpressions(
+ @ParentComponent Optional<ComponentRequirementExpressions> parentRequirementExpressions);
+
+ CurrentImplementationSubcomponent build();
+ }
+}
diff --git a/java/dagger/internal/codegen/DaggerGraphs.java b/java/dagger/internal/codegen/DaggerGraphs.java
new file mode 100644
index 0000000..dda6c11
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerGraphs.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 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.collect.Sets.difference;
+import static com.google.common.graph.Graphs.reachableNodes;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.graph.Graph;
+import com.google.common.graph.SuccessorsFunction;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+/** Utility methods for {@link com.google.common.graph} types. */
+public final class DaggerGraphs {
+ /**
+ * Returns a shortest path from {@code nodeU} to {@code nodeV} in {@code graph} as a list of the
+ * nodes visited in sequence, including both {@code nodeU} and {@code nodeV}. (Note that there may
+ * be many possible shortest paths.)
+ *
+ * <p>If {@code nodeV} is not {@link
+ * com.google.common.graph.Graphs#reachableNodes(com.google.common.graph.Graph, Object) reachable}
+ * from {@code nodeU}, the list returned is empty.
+ *
+ * @throws IllegalArgumentException if {@code nodeU} or {@code nodeV} is not present in {@code
+ * graph}
+ */
+ public static <N> ImmutableList<N> shortestPath(SuccessorsFunction<N> graph, N nodeU, N nodeV) {
+ if (nodeU.equals(nodeV)) {
+ return ImmutableList.of(nodeU);
+ }
+ Set<N> successors = ImmutableSet.copyOf(graph.successors(nodeU));
+ if (successors.contains(nodeV)) {
+ return ImmutableList.of(nodeU, nodeV);
+ }
+
+ Map<N, N> visitedNodeToPathPredecessor = new HashMap<>(); // encodes shortest path tree
+ for (N node : successors) {
+ visitedNodeToPathPredecessor.put(node, nodeU);
+ }
+ Queue<N> currentNodes = new ArrayDeque<N>(successors);
+ Queue<N> nextNodes = new ArrayDeque<N>();
+
+ // Perform a breadth-first traversal starting with the successors of nodeU.
+ while (!currentNodes.isEmpty()) {
+ while (!currentNodes.isEmpty()) {
+ N currentNode = currentNodes.remove();
+ for (N nextNode : graph.successors(currentNode)) {
+ if (visitedNodeToPathPredecessor.containsKey(nextNode)) {
+ continue; // we already have a shortest path to nextNode
+ }
+ visitedNodeToPathPredecessor.put(nextNode, currentNode);
+ if (nextNode.equals(nodeV)) {
+ ImmutableList.Builder<N> builder = ImmutableList.builder();
+ N node = nodeV;
+ builder.add(node);
+ while (!node.equals(nodeU)) {
+ node = visitedNodeToPathPredecessor.get(node);
+ builder.add(node);
+ }
+ return builder.build().reverse();
+ }
+ nextNodes.add(nextNode);
+ }
+ }
+ Queue<N> emptyQueue = currentNodes;
+ currentNodes = nextNodes;
+ nextNodes = emptyQueue; // reusing empty queue faster than allocating new one
+ }
+
+ return ImmutableList.of();
+ }
+
+ /** Returns the nodes in a graph that are not reachable from a node. */
+ public static <N> ImmutableSet<N> unreachableNodes(Graph<N> graph, N node) {
+ return ImmutableSet.copyOf(difference(graph.nodes(), reachableNodes(graph, node)));
+ }
+
+ private DaggerGraphs() {}
+}
diff --git a/java/dagger/internal/codegen/DaggerKythePlugin.java b/java/dagger/internal/codegen/DaggerKythePlugin.java
new file mode 100644
index 0000000..5a685ef
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerKythePlugin.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// This must be in the dagger.internal.codegen package since Dagger doesn't expose its APIs publicly
+// https://github.com/google/dagger/issues/773 could present an opportunity to put this somewhere in
+// the regular kythe/java tree.
+package dagger.internal.codegen;
+
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Iterables;
+import com.google.devtools.kythe.analyzers.base.EntrySet;
+import com.google.devtools.kythe.analyzers.base.FactEmitter;
+import com.google.devtools.kythe.analyzers.base.KytheEntrySets;
+import com.google.devtools.kythe.analyzers.java.Plugin;
+import com.google.devtools.kythe.proto.Storage.VName;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.util.Context;
+import dagger.BindsInstance;
+import dagger.Component;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.producers.ProductionComponent;
+import java.util.Optional;
+import java.util.logging.Logger;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.lang.model.element.Element;
+
+/**
+ * A plugin which emits nodes and edges for <a href="https://github.com/google/dagger">Dagger</a>
+ * specific code.
+ */
+@AutoService(Plugin.class)
+public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
+ // TODO(ronshapiro): use flogger
+ private static final Logger logger = Logger.getLogger(DaggerKythePlugin.class.getCanonicalName());
+ private FactEmitter emitter;
+ @Inject ComponentDescriptorFactory componentDescriptorFactory;
+ @Inject BindingGraphFactory bindingGraphFactory;
+
+ @Override
+ public Void visitClassDef(JCClassDecl tree, Void p) {
+ if (tree.sym != null
+ && isAnyAnnotationPresent(tree.sym, Component.class, ProductionComponent.class)) {
+ addNodesForGraph(
+ bindingGraphFactory.create(
+ componentDescriptorFactory.rootComponentDescriptor(tree.sym), false));
+ }
+ return super.visitClassDef(tree, p);
+ }
+
+ private void addNodesForGraph(BindingGraph graph) {
+ addDependencyEdges(graph);
+ addModuleEdges(graph);
+ addChildComponentEdges(graph);
+
+ graph.subgraphs().forEach(this::addNodesForGraph);
+ }
+
+ private void addDependencyEdges(BindingGraph graph) {
+ for (ResolvedBindings resolvedBinding : graph.resolvedBindings()) {
+ for (Binding binding : resolvedBinding.bindings()) {
+ for (DependencyRequest dependency : binding.explicitDependencies()) {
+ addEdgesForDependencyRequest(dependency, dependency.key(), graph);
+ }
+ }
+ }
+
+ for (ComponentDescriptor.ComponentMethodDescriptor componentMethod :
+ graph.componentDescriptor().componentMethods()) {
+ componentMethod
+ .dependencyRequest()
+ .ifPresent(request -> addEdgesForDependencyRequest(request, request.key(), graph));
+ }
+ }
+
+ /**
+ * Add {@code /inject/satisfiedby} edges from {@code dependency}'s {@link
+ * DependencyRequest#requestElement()} to any {@link BindingDeclaration#bindingElement() binding
+ * elements} that satisfy the request.
+ *
+ * <p>This collapses requests for synthetic bindings so that a request for a multibound key
+ * points to all of the contributions for the multibound object. It does so by recursively calling
+ * this method, with each dependency's key as the {@code targetKey}.
+ */
+ private void addEdgesForDependencyRequest(
+ DependencyRequest dependency, Key targetKey, BindingGraph graph) {
+ if (!dependency.requestElement().isPresent()) {
+ return;
+ }
+ BindingRequest request = bindingRequest(targetKey, dependency.kind());
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ for (Binding binding : resolvedBindings.bindings()) {
+ if (binding.bindingElement().isPresent()) {
+ addDependencyEdge(dependency, binding);
+ } else {
+ for (DependencyRequest subsequentDependency : binding.explicitDependencies()) {
+ addEdgesForDependencyRequest(dependency, subsequentDependency.key(), graph);
+ }
+ }
+ }
+ for (BindingDeclaration bindingDeclaration :
+ Iterables.concat(
+ resolvedBindings.multibindingDeclarations(),
+ resolvedBindings.optionalBindingDeclarations())) {
+ addDependencyEdge(dependency, bindingDeclaration);
+ }
+ }
+
+ private void addDependencyEdge(
+ DependencyRequest dependency, BindingDeclaration bindingDeclaration) {
+ Element requestElement = dependency.requestElement().get();
+ Element bindingElement = bindingDeclaration.bindingElement().get();
+ Optional<VName> requestElementNode = jvmNode(requestElement, "request element");
+ Optional<VName> bindingElementNode = jvmNode(bindingElement, "binding element");
+ emitEdge(requestElementNode, "/inject/satisfiedby", bindingElementNode);
+ // TODO(ronshapiro): emit facts about the component that satisfies the edge
+ }
+
+ private void addModuleEdges(BindingGraph graph) {
+ Optional<VName> componentNode = jvmNode(graph.componentTypeElement(), "component");
+ for (ModuleDescriptor module : graph.componentDescriptor().modules()) {
+ Optional<VName> moduleNode = jvmNode(module.moduleElement(), "module");
+ emitEdge(componentNode, "/inject/installsmodule", moduleNode);
+ }
+ }
+
+ private void addChildComponentEdges(BindingGraph graph) {
+ Optional<VName> componentNode = jvmNode(graph.componentTypeElement(), "component");
+ for (BindingGraph subgraph : graph.subgraphs()) {
+ Optional<VName> subcomponentNode =
+ jvmNode(subgraph.componentTypeElement(), "child component");
+ emitEdge(componentNode, "/inject/childcomponent", subcomponentNode);
+ }
+ }
+
+ private Optional<VName> jvmNode(Element element, String name) {
+ Optional<VName> jvmNode = kytheGraph.getJvmNode((Symbol) element).map(KytheNode::getVName);
+ if (!jvmNode.isPresent()) {
+ logger.warning(String.format("Missing JVM node for %s: %s", name, element));
+ }
+ return jvmNode;
+ }
+
+ private void emitEdge(Optional<VName> source, String edgeName, Optional<VName> target) {
+ source.ifPresent(
+ s -> target.ifPresent(t -> new EntrySet.Builder(s, edgeName, t).build().emit(emitter)));
+ }
+
+ @Override
+ public void run(
+ JCCompilationUnit compilationUnit, KytheEntrySets entrySets, KytheGraph kytheGraph) {
+ if (bindingGraphFactory == null) {
+ emitter = entrySets.getEmitter();
+ DaggerDaggerKythePlugin_PluginComponent.builder()
+ .context(kytheGraph.getJavaContext())
+ .build()
+ .inject(this);
+ }
+ super.run(compilationUnit, entrySets, kytheGraph);
+ }
+
+ @Singleton
+ @Component(modules = JavacPluginModule.class)
+ interface PluginComponent {
+ void inject(DaggerKythePlugin plugin);
+
+ @Component.Builder
+ interface Builder {
+ @BindsInstance
+ Builder context(Context context);
+
+ PluginComponent build();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DaggerStatistics.java b/java/dagger/internal/codegen/DaggerStatistics.java
new file mode 100644
index 0000000..790ec76
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerStatistics.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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 com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import java.time.Duration;
+
+/** Statistics collected over the course of Dagger annotation processing. */
+@AutoValue
+abstract class DaggerStatistics {
+ /** Returns a new {@link Builder}. */
+ static Builder builder() {
+ return new AutoValue_DaggerStatistics.Builder();
+ }
+
+ /** Returns a new {@link RoundStatistics} builder. */
+ static RoundStatistics.Builder roundBuilder() {
+ return new AutoValue_DaggerStatistics_RoundStatistics.Builder();
+ }
+
+ /** Total time spent in Dagger annotation processing. */
+ abstract Duration totalProcessingTime();
+
+ /** List of statistics for processing rounds that the Dagger processor handled. */
+ abstract ImmutableList<RoundStatistics> rounds();
+
+ /** Builder for {@link DaggerStatistics}. */
+ @AutoValue.Builder
+ abstract static class Builder {
+ /** Sets the given duration for the total time spent in Dagger processing. */
+ @CanIgnoreReturnValue
+ abstract Builder setTotalProcessingTime(Duration totalProcessingTime);
+
+ /** Returns a builder for adding processing round statistics. */
+ abstract ImmutableList.Builder<RoundStatistics> roundsBuilder();
+
+ /** Adds the given {@code round} statistics. */
+ @CanIgnoreReturnValue
+ final Builder addRound(RoundStatistics round) {
+ roundsBuilder().add(round);
+ return this;
+ }
+
+ /** Creates a new {@link DaggerStatistics} instance. */
+ abstract DaggerStatistics build();
+ }
+
+ /** Statistics for each processing step in a single processing round. */
+ @AutoValue
+ abstract static class RoundStatistics {
+ /** Map of processing step class to duration of that step for this round. */
+ abstract ImmutableMap<Class<? extends ProcessingStep>, Duration> stepDurations();
+
+ /** Builder for {@link RoundStatistics}. */
+ @AutoValue.Builder
+ abstract static class Builder {
+ /** Returns a builder for adding durations for each processing step for the round. */
+ abstract ImmutableMap.Builder<Class<? extends ProcessingStep>, Duration>
+ stepDurationsBuilder();
+
+ /** Adds the given {@code duration} for the given {@code step}. */
+ @CanIgnoreReturnValue
+ final Builder addStepDuration(ProcessingStep step, Duration duration) {
+ stepDurationsBuilder().put(step.getClass(), duration);
+ return this;
+ }
+
+ /** Creates a new {@link RoundStatistics} instance. */
+ abstract RoundStatistics build();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DaggerStatisticsCollectingProcessingStep.java b/java/dagger/internal/codegen/DaggerStatisticsCollectingProcessingStep.java
new file mode 100644
index 0000000..51f6fc3
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerStatisticsCollectingProcessingStep.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.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.common.collect.SetMultimap;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.lang.model.element.Element;
+
+/**
+ * {@link ProcessingStep} that delegates to another {@code ProcessingStep} and collects timing
+ * statistics for each processing round for that step.
+ */
+final class DaggerStatisticsCollectingProcessingStep implements ProcessingStep {
+
+ private final ProcessingStep delegate;
+ private final DaggerStatisticsCollector statisticsCollector;
+
+ DaggerStatisticsCollectingProcessingStep(
+ ProcessingStep delegate, DaggerStatisticsCollector statisticsCollector) {
+ this.delegate = checkNotNull(delegate);
+ this.statisticsCollector = checkNotNull(statisticsCollector);
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotations() {
+ return delegate.annotations();
+ }
+
+ @Override
+ public Set<? extends Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ statisticsCollector.stepStarted(delegate);
+ try {
+ return delegate.process(elementsByAnnotation);
+ } finally {
+ statisticsCollector.stepFinished(delegate);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DaggerStatisticsCollector.java b/java/dagger/internal/codegen/DaggerStatisticsCollector.java
new file mode 100644
index 0000000..e14fbb7
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerStatisticsCollector.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.common.base.Stopwatch;
+import com.google.common.base.Ticker;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Collects {@link DaggerStatistics} over the course of Dagger annotation processing. */
+@Singleton // for state sharing
+final class DaggerStatisticsCollector {
+
+ private final Ticker ticker;
+ private final Stopwatch totalRuntimeStopwatch;
+ private final Map<ProcessingStep, Stopwatch> stepStopwatches = new HashMap<>();
+
+ private final DaggerStatistics.Builder statisticsBuilder = DaggerStatistics.builder();
+ private DaggerStatistics.RoundStatistics.Builder roundBuilder = DaggerStatistics.roundBuilder();
+
+ private final Optional<DaggerStatisticsRecorder> statisticsRecorder;
+
+ @Inject
+ DaggerStatisticsCollector(Ticker ticker, Optional<DaggerStatisticsRecorder> statisticsRecorder) {
+ this.ticker = ticker;
+ this.totalRuntimeStopwatch = Stopwatch.createUnstarted(ticker);
+ this.statisticsRecorder = statisticsRecorder;
+ }
+
+ /** Called when Dagger annotation processing starts. */
+ void processingStarted() {
+ checkState(!totalRuntimeStopwatch.isRunning());
+ totalRuntimeStopwatch.start();
+ }
+
+ /** Called when the given {@code step} starts processing for a round. */
+ void stepStarted(ProcessingStep step) {
+ Stopwatch stopwatch =
+ stepStopwatches.computeIfAbsent(step, unused -> Stopwatch.createUnstarted(ticker));
+ stopwatch.start();
+ }
+
+ /** Called when the given {@code step} finishes processing for a round. */
+ void stepFinished(ProcessingStep step) {
+ Stopwatch stopwatch = stepStopwatches.get(step);
+ roundBuilder.addStepDuration(step, elapsedTime(stopwatch));
+ stopwatch.reset();
+ }
+
+ /** Called when Dagger finishes a processing round. */
+ void roundFinished() {
+ statisticsBuilder.addRound(roundBuilder.build());
+ roundBuilder = DaggerStatistics.roundBuilder();
+ }
+
+ /** Called when Dagger annotation processing completes. */
+ void processingStopped() {
+ checkState(totalRuntimeStopwatch.isRunning());
+ totalRuntimeStopwatch.stop();
+ statisticsBuilder.setTotalProcessingTime(elapsedTime(totalRuntimeStopwatch));
+
+ statisticsRecorder.ifPresent(
+ recorder -> recorder.recordStatistics(statisticsBuilder.build()));
+ }
+
+ @SuppressWarnings("StopwatchNanosToDuration") // intentional
+ private Duration elapsedTime(Stopwatch stopwatch) {
+ // Using the java 7 method here as opposed to the Duration-returning version to avoid issues
+ // when other annotation processors rely on java 7's guava
+ return Duration.ofNanos(stopwatch.elapsed(NANOSECONDS));
+ }
+}
diff --git a/java/dagger/internal/codegen/DaggerStatisticsRecorder.java b/java/dagger/internal/codegen/DaggerStatisticsRecorder.java
new file mode 100644
index 0000000..66f41d1
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerStatisticsRecorder.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 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;
+
+/** Records collected {@link DaggerStatistics}. */
+interface DaggerStatisticsRecorder {
+ /** Records the given {@code statistics}. */
+ void recordStatistics(DaggerStatistics statistics);
+}
diff --git a/java/dagger/internal/codegen/DaggerStreams.java b/java/dagger/internal/codegen/DaggerStreams.java
new file mode 100644
index 0000000..50d17a6
--- /dev/null
+++ b/java/dagger/internal/codegen/DaggerStreams.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 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 java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toList;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Maps;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/** Utilities for streams. */
+public final class DaggerStreams {
+
+ /**
+ * Returns a {@link Collector} that accumulates the input elements into a new {@link
+ * ImmutableList}, in encounter order.
+ */
+ // TODO(b/68008628): Use ImmutableList.toImmutableList().
+ public static <T> Collector<T, ?, ImmutableList<T>> toImmutableList() {
+ return collectingAndThen(toList(), ImmutableList::copyOf);
+ }
+
+ /**
+ * Returns a {@link Collector} that accumulates the input elements into a new {@link
+ * ImmutableSet}, in encounter order.
+ */
+ // TODO(b/68008628): Use ImmutableSet.toImmutableSet().
+ public static <T> Collector<T, ?, ImmutableSet<T>> toImmutableSet() {
+ return collectingAndThen(toList(), ImmutableSet::copyOf);
+ }
+
+ /**
+ * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys
+ * and values are the result of applying the provided mapping functions to the input elements.
+ * Entries appear in the result {@code ImmutableMap} in encounter order.
+ */
+ // TODO(b/68008628): Use ImmutableMap.toImmutableMap().
+ public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
+ Function<? super T, K> keyMapper, Function<? super T, V> valueMapper) {
+ return Collectors.mapping(
+ value -> Maps.immutableEntry(keyMapper.apply(value), valueMapper.apply(value)),
+ Collector.of(
+ ImmutableMap::builder,
+ (ImmutableMap.Builder<K, V> builder, Map.Entry<K, V> entry) -> builder.put(entry),
+ (left, right) -> left.putAll(right.build()),
+ ImmutableMap.Builder::build));
+ }
+
+ /**
+ * Returns a {@link Collector} that accumulates elements into an {@code ImmutableSetMultimap}
+ * whose keys and values are the result of applying the provided mapping functions to the input
+ * elements. Entries appear in the result {@code ImmutableSetMultimap} in encounter order.
+ */
+ // TODO(b/68008628): Use ImmutableSetMultimap.toImmutableSetMultimap().
+ public static <T, K, V> Collector<T, ?, ImmutableSetMultimap<K, V>> toImmutableSetMultimap(
+ Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends V> valueMapper) {
+ return Collectors.mapping(
+ value -> Maps.immutableEntry(keyMapper.apply(value), valueMapper.apply(value)),
+ Collector.of(
+ ImmutableSetMultimap::builder,
+ (ImmutableSetMultimap.Builder<K, V> builder, Map.Entry<K, V> entry) ->
+ builder.put(entry),
+ (left, right) -> left.putAll(right.build()),
+ ImmutableSetMultimap.Builder::build));
+ }
+
+ /**
+ * Returns a function from {@link Object} to {@code Stream<T>}, which returns a stream containing
+ * its input if its input is an instance of {@code T}.
+ *
+ * <p>Use as an argument to {@link Stream#flatMap(Function)}:
+ *
+ * <pre>{@code Stream<Bar>} barStream = fooStream.flatMap(instancesOf(Bar.class));</pre>
+ */
+ public static <T> Function<Object, Stream<T>> instancesOf(Class<T> to) {
+ return f -> to.isInstance(f) ? Stream.of(to.cast(f)) : Stream.empty();
+ }
+
+ /** Returns a stream of all values of the given {@code enumType}. */
+ public static <E extends Enum<E>> Stream<E> valuesOf(Class<E> enumType) {
+ return EnumSet.allOf(enumType).stream();
+ }
+
+ /**
+ * A function that you can use to extract the present values from a stream of {@link Optional}s.
+ *
+ * <pre>{@code
+ * Set<Foo> foos =
+ * optionalFoos()
+ * .flatMap(DaggerStreams.presentValues())
+ * .collect(toSet());
+ * }</pre>
+ */
+ public static <T> Function<Optional<T>, Stream<T>> presentValues() {
+ return optional -> optional.map(Stream::of).orElse(Stream.empty());
+ }
+
+ /**
+ * Returns a sequential {@link Stream} of the contents of {@code iterable}, delegating to {@link
+ * Collection#stream} if possible.
+ */
+ public static <T> Stream<T> stream(Iterable<T> iterable) {
+ return (iterable instanceof Collection)
+ ? ((Collection<T>) iterable).stream()
+ : StreamSupport.stream(iterable.spliterator(), false);
+ }
+
+ private DaggerStreams() {}
+}
diff --git a/java/dagger/internal/codegen/DeferredModifiableBindingExpression.java b/java/dagger/internal/codegen/DeferredModifiableBindingExpression.java
new file mode 100644
index 0000000..c41cf2c
--- /dev/null
+++ b/java/dagger/internal/codegen/DeferredModifiableBindingExpression.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A {@link ModifiableAbstractMethodBindingExpression} for a binding that exists but is not ready to
+ * be expressed in this compilation unit and should be deferred until a future compilation.
+ * Generates a method that will be implemented in the future compilation.
+ *
+ * <p>A deferred modifiable binding expression is used when:
+ *
+ * <ul>
+ * <li>The generated code for a binding requires an instance of a type that is generated in the
+ * root component compilation unit.
+ * <li>A {@linkplain ModifiableBindingType#BINDS_METHOD_WITH_MISSING_DEPENDENCY {@code @Binds}
+ * method's dependency is missing} in a subcomponent.
+ * </ul>
+ */
+final class DeferredModifiableBindingExpression extends ModifiableAbstractMethodBindingExpression {
+ private final ComponentImplementation componentImplementation;
+ private final ContributionBinding binding;
+ private final BindingRequest request;
+
+ DeferredModifiableBindingExpression(
+ ComponentImplementation componentImplementation,
+ ModifiableBindingType modifiableBindingType,
+ ContributionBinding binding,
+ BindingRequest request,
+ Optional<ModifiableBindingMethod> matchingModifiableBindingMethod,
+ Optional<ComponentMethodDescriptor> matchingComponentMethod,
+ DaggerTypes types) {
+ super(
+ componentImplementation,
+ modifiableBindingType,
+ request,
+ matchingModifiableBindingMethod,
+ matchingComponentMethod,
+ types);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.binding = checkNotNull(binding);
+ this.request = checkNotNull(request);
+ }
+
+ @Override
+ String chooseMethodName() {
+ return componentImplementation.getUniqueMethodName(request);
+ }
+
+ @Override
+ protected TypeMirror contributedType() {
+ return binding.contributedType();
+ }
+}
diff --git a/java/dagger/internal/codegen/DelegateBindingExpression.java b/java/dagger/internal/codegen/DelegateBindingExpression.java
new file mode 100644
index 0000000..8cdf6d1
--- /dev/null
+++ b/java/dagger/internal/codegen/DelegateBindingExpression.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.RequestKinds.requestType;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.model.BindingKind.DELEGATE;
+
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.RequestKind;
+import javax.lang.model.type.TypeMirror;
+
+/** A {@link BindingExpression} for {@code @Binds} methods. */
+final class DelegateBindingExpression extends BindingExpression {
+ private final ContributionBinding binding;
+ private final RequestKind requestKind;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+ private final BindsTypeChecker bindsTypeChecker;
+
+ DelegateBindingExpression(
+ ResolvedBindings resolvedBindings,
+ RequestKind requestKind,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types,
+ DaggerElements elements) {
+ this.binding = checkNotNull(resolvedBindings.contributionBinding());
+ this.requestKind = checkNotNull(requestKind);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.types = checkNotNull(types);
+ this.bindsTypeChecker = new BindsTypeChecker(types, elements);
+ }
+
+ /**
+ * Returns {@code true} if the {@code @Binds} binding's scope is stronger than the scope of the
+ * binding it depends on.
+ */
+ static boolean isBindsScopeStrongerThanDependencyScope(
+ ResolvedBindings resolvedBindings, BindingGraph graph) {
+ ContributionBinding bindsBinding = resolvedBindings.contributionBinding();
+ checkArgument(bindsBinding.kind().equals(DELEGATE));
+ Binding dependencyBinding =
+ graph
+ .contributionBindings()
+ .get(getOnlyElement(bindsBinding.dependencies()).key())
+ .binding();
+ ScopeKind bindsScope = ScopeKind.get(bindsBinding, graph);
+ ScopeKind dependencyScope = ScopeKind.get(dependencyBinding, graph);
+ return bindsScope.isStrongerScopeThan(dependencyScope);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ Expression delegateExpression =
+ componentBindingExpressions.getDependencyExpression(
+ bindingRequest(getOnlyElement(binding.dependencies()).key(), requestKind),
+ requestingClass);
+
+ TypeMirror contributedType = binding.contributedType();
+ switch (requestKind) {
+ case INSTANCE:
+ return instanceRequiresCast(delegateExpression, requestingClass)
+ ? delegateExpression.castTo(contributedType)
+ : delegateExpression;
+ default:
+ return castToRawTypeIfNecessary(
+ delegateExpression, requestType(requestKind, contributedType, types));
+ }
+ }
+
+ private boolean instanceRequiresCast(Expression delegateExpression, ClassName requestingClass) {
+ // delegateExpression.type() could be Object if expression is satisfied with a raw
+ // Provider's get() method.
+ return !bindsTypeChecker.isAssignable(
+ delegateExpression.type(), binding.contributedType(), binding.contributionType())
+ && isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName());
+ }
+
+ /**
+ * If {@code delegateExpression} can be assigned to {@code desiredType} safely, then {@code
+ * delegateExpression} is returned unchanged. If the {@code delegateExpression} is already a raw
+ * type, returns {@code delegateExpression} as well, as casting would have no effect. Otherwise,
+ * returns a {@link Expression#castTo(TypeMirror) casted} version of {@code delegateExpression}
+ * to the raw type of {@code desiredType}.
+ */
+ // TODO(ronshapiro): this probably can be generalized for usage in InjectionMethods
+ private Expression castToRawTypeIfNecessary(
+ Expression delegateExpression, TypeMirror desiredType) {
+ if (types.isAssignable(delegateExpression.type(), desiredType)) {
+ return delegateExpression;
+ }
+ return delegateExpression.castTo(types.erasure(desiredType));
+ }
+
+ private enum ScopeKind {
+ UNSCOPED,
+ SINGLE_CHECK,
+ DOUBLE_CHECK,
+ ;
+
+ static ScopeKind get(Binding binding, BindingGraph graph) {
+ return binding
+ .scope()
+ .map(scope -> scope.isReusable() ? SINGLE_CHECK : DOUBLE_CHECK)
+ .orElse(UNSCOPED);
+ }
+
+ boolean isStrongerScopeThan(ScopeKind other) {
+ return this.ordinal() > other.ordinal();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DelegateDeclaration.java b/java/dagger/internal/codegen/DelegateDeclaration.java
new file mode 100644
index 0000000..67991de
--- /dev/null
+++ b/java/dagger/internal/codegen/DelegateDeclaration.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MoreAnnotationMirrors.wrapOptionalInEquivalence;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.Iterables;
+import dagger.Binds;
+import dagger.internal.codegen.ContributionType.HasContributionType;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+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.type.ExecutableType;
+
+/**
+ * The declaration for a delegate binding established by a {@link Binds} method.
+ */
+@AutoValue
+abstract class DelegateDeclaration extends BindingDeclaration implements HasContributionType {
+ abstract DependencyRequest delegateRequest();
+
+ abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKey();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ static final class Factory {
+ private final DaggerTypes types;
+ private final KeyFactory keyFactory;
+ private final DependencyRequestFactory dependencyRequestFactory;
+
+ @Inject
+ Factory(
+ DaggerTypes types,
+ KeyFactory keyFactory,
+ DependencyRequestFactory dependencyRequestFactory) {
+ this.types = types;
+ this.keyFactory = keyFactory;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ DelegateDeclaration create(
+ ExecutableElement bindsMethod, TypeElement contributingModule) {
+ checkArgument(MoreElements.isAnnotationPresent(bindsMethod, Binds.class));
+ ExecutableType resolvedMethod =
+ MoreTypes.asExecutable(
+ types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), bindsMethod));
+ DependencyRequest delegateRequest =
+ dependencyRequestFactory.forRequiredResolvedVariable(
+ Iterables.getOnlyElement(bindsMethod.getParameters()),
+ Iterables.getOnlyElement(resolvedMethod.getParameterTypes()));
+ return new AutoValue_DelegateDeclaration(
+ ContributionType.fromBindingElement(bindsMethod),
+ keyFactory.forBindsMethod(bindsMethod, contributingModule),
+ Optional.<Element>of(bindsMethod),
+ Optional.of(contributingModule),
+ delegateRequest,
+ wrapOptionalInEquivalence(getMapKey(bindsMethod)));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java b/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java
new file mode 100644
index 0000000..7524cdf
--- /dev/null
+++ b/java/dagger/internal/codegen/DelegatingFrameworkInstanceCreationExpression.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.model.DependencyRequest;
+
+/** A framework instance creation expression for a {@link dagger.Binds @Binds} binding. */
+final class DelegatingFrameworkInstanceCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ContributionBinding binding;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentBindingExpressions componentBindingExpressions;
+
+ DelegatingFrameworkInstanceCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ DependencyRequest dependency = getOnlyElement(binding.dependencies());
+ return CodeBlocks.cast(
+ componentBindingExpressions
+ .getDependencyExpression(
+ bindingRequest(dependency.key(), binding.frameworkType()),
+ componentImplementation.name())
+ .codeBlock(),
+ binding.frameworkType().frameworkClass());
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyCycleValidator.java b/java/dagger/internal/codegen/DependencyCycleValidator.java
new file mode 100644
index 0000000..d5d4b62
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyCycleValidator.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.Iterables.limit;
+import static com.google.common.collect.Iterables.skip;
+import static com.google.common.collect.Sets.newHashSetWithExpectedSize;
+import static dagger.internal.codegen.DaggerGraphs.shortestPath;
+import static dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.RequestKinds.extractKeyType;
+import static dagger.internal.codegen.RequestKinds.getRequestKind;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.graph.EndpointPair;
+import com.google.common.graph.ImmutableNetwork;
+import com.google.common.graph.MutableNetwork;
+import com.google.common.graph.NetworkBuilder;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.BindingGraph.Node;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import dagger.model.RequestKind;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/** Reports errors for dependency cycles. */
+final class DependencyCycleValidator implements BindingGraphPlugin {
+
+ private final DependencyRequestFormatter dependencyRequestFormatter;
+
+ @Inject
+ DependencyCycleValidator(DependencyRequestFormatter dependencyRequestFormatter) {
+ this.dependencyRequestFormatter = dependencyRequestFormatter;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/DependencyCycle";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ ImmutableNetwork<Node, DependencyEdge> dependencyGraph =
+ nonCycleBreakingDependencyGraph(bindingGraph);
+ // Check each endpoint pair only once, no matter how many parallel edges connect them.
+ Set<EndpointPair<Node>> dependencyEndpointPairs = dependencyGraph.asGraph().edges();
+ Set<EndpointPair<Node>> visited = newHashSetWithExpectedSize(dependencyEndpointPairs.size());
+ for (EndpointPair<Node> endpointPair : dependencyEndpointPairs) {
+ cycleContainingEndpointPair(endpointPair, dependencyGraph, visited)
+ .ifPresent(cycle -> reportCycle(cycle, bindingGraph, diagnosticReporter));
+ }
+ }
+
+ private Optional<Cycle<Node>> cycleContainingEndpointPair(
+ EndpointPair<Node> endpoints,
+ ImmutableNetwork<Node, DependencyEdge> dependencyGraph,
+ Set<EndpointPair<Node>> visited) {
+ if (!visited.add(endpoints)) {
+ // don't recheck endpoints we already know are part of a cycle
+ return Optional.empty();
+ }
+
+ // If there's a path from the target back to the source, there's a cycle.
+ ImmutableList<Node> cycleNodes =
+ shortestPath(dependencyGraph, endpoints.target(), endpoints.source());
+ if (cycleNodes.isEmpty()) {
+ return Optional.empty();
+ }
+
+ Cycle<Node> cycle = Cycle.fromPath(cycleNodes);
+ visited.addAll(cycle.endpointPairs()); // no need to check any edge in this cycle again
+ return Optional.of(cycle);
+ }
+
+ /**
+ * Reports a dependency cycle at the dependency into the cycle that is closest to an entry point.
+ *
+ * <p>For cycles found in reachable binding graphs, looks for the shortest path from the component
+ * that contains the cycle (all bindings in a cycle must be in the same component; see below) to
+ * some binding in the cycle. Then looks for the last dependency in that path that is not in the
+ * cycle; that is the dependency that will be reported, so that the dependency trace will end just
+ * before the cycle.
+ *
+ * <p>For cycles found during full binding graph validation, just reports the component that
+ * contains the cycle.
+ *
+ * <p>Proof (by counterexample) that all bindings in a cycle must be in the same component: Assume
+ * one binding in the cycle is in a parent component. Bindings cannot depend on bindings in child
+ * components, so that binding cannot depend on the next binding in the cycle.
+ */
+ private void reportCycle(
+ Cycle<Node> cycle, BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ if (bindingGraph.isFullBindingGraph()) {
+ diagnosticReporter.reportComponent(
+ ERROR,
+ bindingGraph.componentNode(cycle.nodes().asList().get(0).componentPath()).get(),
+ errorMessage(cycle, bindingGraph));
+ return;
+ }
+
+ ImmutableList<Node> path = shortestPathToCycleFromAnEntryPoint(cycle, bindingGraph);
+ Node cycleStartNode = path.get(path.size() - 1);
+ Node previousNode = path.get(path.size() - 2);
+ DependencyEdge dependencyToReport =
+ chooseDependencyEdgeConnecting(previousNode, cycleStartNode, bindingGraph);
+ diagnosticReporter.reportDependency(
+ ERROR, dependencyToReport, errorMessage(cycle.shift(cycleStartNode), bindingGraph));
+ }
+
+ private ImmutableList<Node> shortestPathToCycleFromAnEntryPoint(
+ Cycle<Node> cycle, BindingGraph bindingGraph) {
+ Node someCycleNode = cycle.nodes().asList().get(0);
+ ComponentNode componentContainingCycle =
+ bindingGraph.componentNode(someCycleNode.componentPath()).get();
+ ImmutableList<Node> pathToCycle =
+ shortestPath(bindingGraph.network(), componentContainingCycle, someCycleNode);
+ return subpathToCycle(pathToCycle, cycle);
+ }
+
+ /**
+ * Returns the subpath from the head of {@code path} to the first node in {@code path} that's in
+ * the cycle.
+ */
+ private ImmutableList<Node> subpathToCycle(ImmutableList<Node> path, Cycle<Node> cycle) {
+ ImmutableList.Builder<Node> subpath = ImmutableList.builder();
+ for (Node node : path) {
+ subpath.add(node);
+ if (cycle.nodes().contains(node)) {
+ return subpath.build();
+ }
+ }
+ throw new IllegalArgumentException(
+ "path " + path + " doesn't contain any nodes in cycle " + cycle);
+ }
+
+ private String errorMessage(Cycle<Node> cycle, BindingGraph graph) {
+ StringBuilder message = new StringBuilder("Found a dependency cycle:");
+ ImmutableList<DependencyRequest> cycleRequests =
+ cycle.endpointPairs().stream()
+ // TODO(dpb): Would be nice to take the dependency graph here.
+ .map(endpointPair -> nonCycleBreakingEdge(endpointPair, graph))
+ .map(DependencyEdge::dependencyRequest)
+ .collect(toImmutableList())
+ .reverse();
+ dependencyRequestFormatter.formatIndentedList(message, cycleRequests, 0);
+ return message.toString();
+ }
+
+ /**
+ * Returns one of the edges between two nodes that doesn't {@linkplain
+ * #breaksCycle(DependencyEdge, BindingGraph) break} a cycle.
+ */
+ private DependencyEdge nonCycleBreakingEdge(EndpointPair<Node> endpointPair, BindingGraph graph) {
+ return graph.network().edgesConnecting(endpointPair.source(), endpointPair.target()).stream()
+ .flatMap(instancesOf(DependencyEdge.class))
+ .filter(edge -> !breaksCycle(edge, graph))
+ .findFirst()
+ .get();
+ }
+
+ private boolean breaksCycle(DependencyEdge edge, BindingGraph graph) {
+ if (edge.dependencyRequest().key().multibindingContributionIdentifier().isPresent()) {
+ return false;
+ }
+ if (breaksCycle(edge.dependencyRequest().key().type(), edge.dependencyRequest().kind())) {
+ return true;
+ }
+ Node target = graph.network().incidentNodes(edge).target();
+ if (target instanceof dagger.model.Binding
+ && ((dagger.model.Binding) target).kind().equals(BindingKind.OPTIONAL)) {
+ /* For @BindsOptionalOf bindings, unwrap the type inside the Optional. If the unwrapped type
+ * breaks the cycle, so does the optional binding. */
+ TypeMirror optionalValueType = OptionalType.from(edge.dependencyRequest().key()).valueType();
+ RequestKind requestKind = getRequestKind(optionalValueType);
+ return breaksCycle(extractKeyType(requestKind, optionalValueType), requestKind);
+ }
+ return false;
+ }
+
+ private boolean breaksCycle(TypeMirror requestedType, RequestKind requestKind) {
+ switch (requestKind) {
+ case PROVIDER:
+ case LAZY:
+ case PROVIDER_OF_LAZY:
+ return true;
+
+ case INSTANCE:
+ if (MapType.isMap(requestedType)) {
+ MapType mapType = MapType.from(requestedType);
+ return !mapType.isRawType() && mapType.valuesAreTypeOf(Provider.class);
+ }
+ // fall through
+
+ default:
+ return false;
+ }
+ }
+
+ private DependencyEdge chooseDependencyEdgeConnecting(
+ Node source, Node target, BindingGraph bindingGraph) {
+ return bindingGraph.network().edgesConnecting(source, target).stream()
+ .flatMap(instancesOf(DependencyEdge.class))
+ .findFirst()
+ .get();
+ }
+
+ /** Returns the subgraph containing only {@link DependencyEdge}s that would not break a cycle. */
+ // TODO(dpb): Return a network containing only Binding nodes.
+ private ImmutableNetwork<Node, DependencyEdge> nonCycleBreakingDependencyGraph(
+ BindingGraph bindingGraph) {
+ MutableNetwork<Node, DependencyEdge> dependencyNetwork =
+ NetworkBuilder.from(bindingGraph.network())
+ .expectedNodeCount(bindingGraph.network().nodes().size())
+ .expectedEdgeCount(bindingGraph.dependencyEdges().size())
+ .build();
+ bindingGraph.dependencyEdges().stream()
+ .filter(edge -> !breaksCycle(edge, bindingGraph))
+ .forEach(
+ edge -> {
+ EndpointPair<Node> endpoints = bindingGraph.network().incidentNodes(edge);
+ dependencyNetwork.addEdge(endpoints.source(), endpoints.target(), edge);
+ });
+ return ImmutableNetwork.copyOf(dependencyNetwork);
+ }
+
+ /**
+ * An ordered set of endpoint pairs representing the edges in the cycle. The target of each pair
+ * is the source of the next pair. The target of the last pair is the source of the first pair.
+ */
+ @AutoValue
+ abstract static class Cycle<N> {
+ /**
+ * The ordered set of endpoint pairs representing the edges in the cycle. The target of each
+ * pair is the source of the next pair. The target of the last pair is the source of the first
+ * pair.
+ */
+ abstract ImmutableSet<EndpointPair<N>> endpointPairs();
+
+ /** Returns the nodes that participate in the cycle. */
+ ImmutableSet<N> nodes() {
+ return endpointPairs().stream()
+ .flatMap(pair -> Stream.of(pair.source(), pair.target()))
+ .collect(toImmutableSet());
+ }
+
+ /** Returns the number of edges in the cycle. */
+ int size() {
+ return endpointPairs().size();
+ }
+
+ /**
+ * Shifts this cycle so that it starts with a specific node.
+ *
+ * @return a cycle equivalent to this one but whose first pair starts with {@code startNode}
+ */
+ Cycle<N> shift(N startNode) {
+ int startIndex = Iterables.indexOf(endpointPairs(), pair -> pair.source().equals(startNode));
+ checkArgument(
+ startIndex >= 0, "startNode (%s) is not part of this cycle: %s", startNode, this);
+ if (startIndex == 0) {
+ return this;
+ }
+ ImmutableSet.Builder<EndpointPair<N>> shifted = ImmutableSet.builder();
+ shifted.addAll(skip(endpointPairs(), startIndex));
+ shifted.addAll(limit(endpointPairs(), size() - startIndex));
+ return new AutoValue_DependencyCycleValidator_Cycle<>(shifted.build());
+ }
+
+ @Override
+ public final String toString() {
+ return endpointPairs().toString();
+ }
+
+ /**
+ * Creates a {@link Cycle} from a nonempty list of nodes, assuming there is an edge between each
+ * pair of nodes as well as an edge from the last node to the first.
+ */
+ static <N> Cycle<N> fromPath(List<N> nodes) {
+ checkArgument(!nodes.isEmpty());
+ ImmutableSet.Builder<EndpointPair<N>> cycle = ImmutableSet.builder();
+ cycle.add(EndpointPair.ordered(getLast(nodes), nodes.get(0)));
+ for (int i = 0; i < nodes.size() - 1; i++) {
+ cycle.add(EndpointPair.ordered(nodes.get(i), nodes.get(i + 1)));
+ }
+ return new AutoValue_DependencyCycleValidator_Cycle<>(cycle.build());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyEdgeImpl.java b/java/dagger/internal/codegen/DependencyEdgeImpl.java
new file mode 100644
index 0000000..64b0845
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyEdgeImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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 dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.DependencyRequest;
+
+/** An implementation of {@link DependencyEdge}. */
+final class DependencyEdgeImpl implements DependencyEdge {
+
+ private final DependencyRequest dependencyRequest;
+ private final boolean entryPoint;
+
+ DependencyEdgeImpl(DependencyRequest dependencyRequest, boolean entryPoint) {
+ this.dependencyRequest = dependencyRequest;
+ this.entryPoint = entryPoint;
+ }
+
+ @Override
+ public DependencyRequest dependencyRequest() {
+ return dependencyRequest;
+ }
+
+ @Override
+ public boolean isEntryPoint() {
+ return entryPoint;
+ }
+
+ @Override
+ public String toString() {
+ String string =
+ dependencyRequest
+ .requestElement()
+ .map(ElementFormatter::elementToString)
+ .orElseGet(
+ () ->
+ "synthetic request for "
+ + dependencyRequest.kind().format(dependencyRequest.key()));
+ return entryPoint ? string + " (entry point)" : string;
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java b/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java
new file mode 100644
index 0000000..b42f9c4
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyMethodProducerCreationExpression.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
+import static dagger.internal.codegen.javapoet.TypeNames.dependencyMethodProducerOf;
+import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/**
+ * A {@link dagger.producers.Producer} creation expression 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}.
+ */
+// TODO(dpb): Resolve with DependencyMethodProviderCreationExpression.
+final class DependencyMethodProducerCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final ContributionBinding binding;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final BindingGraph graph;
+
+ DependencyMethodProducerCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ ComponentRequirement dependency =
+ graph.componentDescriptor().getDependencyThatDefinesMethod(binding.bindingElement().get());
+ FieldSpec dependencyField =
+ FieldSpec.builder(
+ ClassName.get(dependency.typeElement()), dependency.variableName(), PRIVATE, FINAL)
+ .initializer(
+ componentRequirementExpressions.getExpressionDuringInitialization(
+ dependency,
+ // This isn't a real class name, but we want the requesting class for the
+ // expression to *not* be the same class as the component implementation,
+ // because it isn't... it's an anonymous inner class.
+ // TODO(cgdecker): If we didn't use an anonymous inner class here but instead
+ // generated a named nested class as with
+ // DependencyMethodProviderCreationExpression, we wouldn't need to deal with
+ // this and might be able to avoid potentially creating an extra field in the
+ // component?
+ componentImplementation.name().nestedClass("Anonymous")))
+ .build();
+ // TODO(b/70395982): Explore using a private static type instead of an anonymous class.
+ TypeName keyType = TypeName.get(binding.key().type());
+ return CodeBlock.of(
+ "$L",
+ anonymousClassBuilder("")
+ .superclass(dependencyMethodProducerOf(keyType))
+ .addField(dependencyField)
+ .addMethod(
+ methodBuilder("callDependencyMethod")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(listenableFutureOf(keyType))
+ .addStatement(
+ "return $N.$L()",
+ dependencyField,
+ binding.bindingElement().get().getSimpleName())
+ .build())
+ .build());
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.java b/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.java
new file mode 100644
index 0000000..8532481
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyMethodProviderCreationExpression.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.ComponentImplementation.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.common.MoreTypes;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import javax.lang.model.element.Element;
+
+/**
+ * A {@link javax.inject.Provider} creation expression for a provision method on a component's
+ * {@linkplain dagger.Component#dependencies()} dependency}.
+ */
+// TODO(dpb): Resolve with DependencyMethodProducerCreationExpression.
+final class DependencyMethodProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ComponentImplementation componentImplementation;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final CompilerOptions compilerOptions;
+ private final BindingGraph graph;
+ private final ContributionBinding binding;
+
+ DependencyMethodProviderCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ CompilerOptions compilerOptions,
+ BindingGraph graph) {
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
+ this.compilerOptions = checkNotNull(compilerOptions);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ // TODO(sameb): The Provider.get() throws a very vague NPE. The stack trace doesn't
+ // help to figure out what the method or return type is. If we include a string
+ // of the return type or method name in the error message, that can defeat obfuscation.
+ // We can easily include the raw type (no generics) + annotation type (no values),
+ // using .class & String.format -- but that wouldn't be the whole story.
+ // What should we do?
+ CodeBlock invocation =
+ ComponentProvisionBindingExpression.maybeCheckForNull(
+ (ProvisionBinding) binding,
+ compilerOptions,
+ CodeBlock.of(
+ "$N.$N()", dependency().variableName(), provisionMethod().getSimpleName()));
+ ClassName dependencyClassName = ClassName.get(dependency().typeElement());
+ TypeName keyType = TypeName.get(binding.key().type());
+ MethodSpec.Builder getMethod =
+ methodBuilder("get")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(keyType)
+ .addStatement("return $L", invocation);
+ if (binding.nullableType().isPresent()) {
+ getMethod.addAnnotation(ClassName.get(MoreTypes.asTypeElement(binding.nullableType().get())));
+ }
+ componentImplementation.addType(
+ COMPONENT_PROVISION_FACTORY,
+ classBuilder(factoryClassName())
+ .addSuperinterface(providerOf(keyType))
+ .addModifiers(PRIVATE, STATIC)
+ .addField(dependencyClassName, dependency().variableName(), PRIVATE, FINAL)
+ .addMethod(
+ constructorBuilder()
+ .addParameter(dependencyClassName, dependency().variableName())
+ .addStatement("this.$1L = $1L", dependency().variableName())
+ .build())
+ .addMethod(getMethod.build())
+ .build());
+ return CodeBlock.of(
+ "new $T($L)",
+ factoryClassName(),
+ componentRequirementExpressions.getExpressionDuringInitialization(
+ dependency(), componentImplementation.name()));
+ }
+
+ private ClassName factoryClassName() {
+ String factoryName =
+ ClassName.get(dependency().typeElement()).toString().replace('.', '_')
+ + "_"
+ + binding.bindingElement().get().getSimpleName();
+ return componentImplementation.name().nestedClass(factoryName);
+ }
+
+ private ComponentRequirement dependency() {
+ return graph.componentDescriptor().getDependencyThatDefinesMethod(provisionMethod());
+ }
+
+ private Element provisionMethod() {
+ return binding.bindingElement().get();
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyRequestFactory.java b/java/dagger/internal/codegen/DependencyRequestFactory.java
new file mode 100644
index 0000000..3ad12e2
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyRequestFactory.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreTypes.isTypeOf;
+import static com.google.common.base.Preconditions.checkArgument;
+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.ConfigurationAnnotations.getNullableType;
+import static dagger.internal.codegen.RequestKinds.extractKeyType;
+import static dagger.internal.codegen.RequestKinds.frameworkClass;
+import static dagger.internal.codegen.RequestKinds.getRequestKind;
+import static dagger.model.RequestKind.FUTURE;
+import static dagger.model.RequestKind.INSTANCE;
+import static dagger.model.RequestKind.MEMBERS_INJECTION;
+import static dagger.model.RequestKind.PRODUCER;
+import static dagger.model.RequestKind.PROVIDER;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.Lazy;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.List;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Factory for {@link DependencyRequest}s.
+ *
+ * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available, which
+ * may mean that the type will be generated in a later round of processing.
+ */
+final class DependencyRequestFactory {
+ private final KeyFactory keyFactory;
+ private final DaggerTypes types;
+
+ @Inject
+ DependencyRequestFactory(KeyFactory keyFactory, DaggerTypes types) {
+ this.keyFactory = keyFactory;
+ this.types = types;
+ }
+
+ ImmutableSet<DependencyRequest> forRequiredResolvedVariables(
+ List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
+ checkState(resolvedTypes.size() == variables.size());
+ ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder();
+ for (int i = 0; i < variables.size(); i++) {
+ builder.add(forRequiredResolvedVariable(variables.get(i), resolvedTypes.get(i)));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Creates synthetic dependency requests for each individual multibinding contribution in {@code
+ * multibindingContributions}.
+ */
+ ImmutableSet<DependencyRequest> forMultibindingContributions(
+ Key multibindingKey, Iterable<ContributionBinding> multibindingContributions) {
+ ImmutableSet.Builder<DependencyRequest> requests = ImmutableSet.builder();
+ for (ContributionBinding multibindingContribution : multibindingContributions) {
+ requests.add(forMultibindingContribution(multibindingKey, multibindingContribution));
+ }
+ return requests.build();
+ }
+
+ /** Creates a synthetic dependency request for one individual {@code multibindingContribution}. */
+ private DependencyRequest forMultibindingContribution(
+ Key multibindingKey, ContributionBinding multibindingContribution) {
+ checkArgument(
+ multibindingContribution.key().multibindingContributionIdentifier().isPresent(),
+ "multibindingContribution's key must have a multibinding contribution identifier: %s",
+ multibindingContribution);
+ return DependencyRequest.builder()
+ .kind(multibindingContributionRequestKind(multibindingKey, multibindingContribution))
+ .key(multibindingContribution.key())
+ .build();
+ }
+
+ // TODO(b/28555349): support PROVIDER_OF_LAZY here too
+ private static final ImmutableSet<RequestKind> WRAPPING_MAP_VALUE_FRAMEWORK_TYPES =
+ ImmutableSet.of(PROVIDER, PRODUCER);
+
+ private RequestKind multibindingContributionRequestKind(
+ Key multibindingKey, ContributionBinding multibindingContribution) {
+ switch (multibindingContribution.contributionType()) {
+ case MAP:
+ MapType mapType = MapType.from(multibindingKey);
+ for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) {
+ if (mapType.valuesAreTypeOf(frameworkClass(kind))) {
+ return kind;
+ }
+ }
+ // fall through
+ case SET:
+ case SET_VALUES:
+ return INSTANCE;
+ case UNIQUE:
+ throw new IllegalArgumentException(
+ "multibindingContribution must be a multibinding: " + multibindingContribution);
+ }
+ throw new AssertionError(multibindingContribution.toString());
+ }
+
+ DependencyRequest forRequiredResolvedVariable(
+ VariableElement variableElement, TypeMirror resolvedType) {
+ checkNotNull(variableElement);
+ checkNotNull(resolvedType);
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
+ return newDependencyRequest(variableElement, resolvedType, qualifier);
+ }
+
+ DependencyRequest forComponentProvisionMethod(
+ ExecutableElement provisionMethod, ExecutableType provisionMethodType) {
+ checkNotNull(provisionMethod);
+ checkNotNull(provisionMethodType);
+ checkArgument(
+ provisionMethod.getParameters().isEmpty(),
+ "Component provision methods must be empty: %s",
+ provisionMethod);
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(provisionMethod);
+ return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier);
+ }
+
+ DependencyRequest forComponentProductionMethod(
+ ExecutableElement productionMethod, ExecutableType productionMethodType) {
+ checkNotNull(productionMethod);
+ checkNotNull(productionMethodType);
+ checkArgument(
+ productionMethod.getParameters().isEmpty(),
+ "Component production methods must be empty: %s",
+ productionMethod);
+ TypeMirror type = productionMethodType.getReturnType();
+ Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(productionMethod);
+ // Only a component production method can be a request for a ListenableFuture, so we
+ // special-case it here.
+ if (isTypeOf(ListenableFuture.class, type)) {
+ return DependencyRequest.builder()
+ .kind(FUTURE)
+ .key(keyFactory.forQualifiedType(qualifier, types.unwrapType(type)))
+ .requestElement(productionMethod)
+ .build();
+ } else {
+ return newDependencyRequest(productionMethod, type, qualifier);
+ }
+ }
+
+ DependencyRequest forComponentMembersInjectionMethod(
+ ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType) {
+ checkNotNull(membersInjectionMethod);
+ checkNotNull(membersInjectionMethodType);
+ Optional<AnnotationMirror> qualifier =
+ InjectionAnnotations.getQualifier(membersInjectionMethod);
+ checkArgument(!qualifier.isPresent());
+ TypeMirror membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes());
+ return DependencyRequest.builder()
+ .kind(MEMBERS_INJECTION)
+ .key(keyFactory.forMembersInjectedType(membersInjectedType))
+ .requestElement(membersInjectionMethod)
+ .build();
+ }
+
+ DependencyRequest forProductionImplementationExecutor() {
+ return DependencyRequest.builder()
+ .kind(PROVIDER)
+ .key(keyFactory.forProductionImplementationExecutor())
+ .build();
+ }
+
+ DependencyRequest forProductionComponentMonitor() {
+ return DependencyRequest.builder()
+ .kind(PROVIDER)
+ .key(keyFactory.forProductionComponentMonitor())
+ .build();
+ }
+
+ /**
+ * Returns a synthetic request for the present value of an optional binding generated from a
+ * {@link dagger.BindsOptionalOf} declaration.
+ */
+ DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind) {
+ Optional<Key> key = keyFactory.unwrapOptional(requestKey);
+ checkArgument(key.isPresent(), "not a request for optional: %s", requestKey);
+ return DependencyRequest.builder()
+ .kind(kind)
+ .key(key.get())
+ .isNullable(
+ allowsNull(getRequestKind(OptionalType.from(requestKey).valueType()), Optional.empty()))
+ .build();
+ }
+
+ private DependencyRequest newDependencyRequest(
+ Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier) {
+ RequestKind requestKind = getRequestKind(type);
+ return DependencyRequest.builder()
+ .kind(requestKind)
+ .key(keyFactory.forQualifiedType(qualifier, extractKeyType(requestKind, type)))
+ .requestElement(requestElement)
+ .isNullable(allowsNull(requestKind, getNullableType(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.
+ */
+ private boolean allowsNull(RequestKind kind, Optional<DeclaredType> nullableType) {
+ return nullableType.isPresent() || !kind.equals(INSTANCE);
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyRequestFormatter.java b/java/dagger/internal/codegen/DependencyRequestFormatter.java
new file mode 100644
index 0000000..25becaf
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyRequestFormatter.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.ElementFormatter.elementToString;
+import static dagger.internal.codegen.RequestKinds.requestType;
+
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.producers.Produces;
+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.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor8;
+
+/**
+ * Formats a {@link DependencyRequest} into a {@link String} suitable for an error message listing a
+ * chain of dependencies.
+ *
+ * <dl>
+ * <dt>For component provision methods
+ * <dd>{@code @Qualifier SomeType is provided at\n ComponentType.method()}
+ * <dt>For component injection methods
+ * <dd>{@code SomeType is injected at\n ComponentType.method(foo)}
+ * <dt>For parameters to {@link Provides @Provides}, {@link Produces @Produces}, or {@link
+ * Inject @Inject} methods:
+ * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType.method([…, ]param[, …])}
+ * <dt>For parameters to {@link Inject @Inject} constructors:
+ * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType([…, ]param[, …])}
+ * <dt>For {@link Inject @Inject} fields:
+ * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType.field}
+ * </dl>
+ */
+final class DependencyRequestFormatter extends Formatter<DependencyRequest> {
+
+ private final DaggerTypes types;
+
+ @Inject
+ DependencyRequestFormatter(DaggerTypes types) {
+ this.types = types;
+ }
+
+ @Override
+ public String format(DependencyRequest request) {
+ return request
+ .requestElement()
+ .map(element -> element.accept(formatVisitor, request))
+ .orElse("");
+ }
+
+ /**
+ * Appends a newline and the formatted dependency request unless {@link
+ * #format(DependencyRequest)} returns the empty string.
+ */
+ @CanIgnoreReturnValue
+ StringBuilder appendFormatLine(StringBuilder builder, DependencyRequest dependencyRequest) {
+ String formatted = format(dependencyRequest);
+ if (!formatted.isEmpty()) {
+ builder.append('\n').append(formatted);
+ }
+ return builder;
+ }
+
+ private final ElementVisitor<String, DependencyRequest> formatVisitor =
+ new ElementKindVisitor8<String, DependencyRequest>() {
+
+ @Override
+ public String visitExecutableAsMethod(ExecutableElement method, DependencyRequest request) {
+ return INDENT
+ + request.key()
+ + " is "
+ + componentMethodRequestVerb(request)
+ + " at\n"
+ + DOUBLE_INDENT
+ + elementToString(method);
+ }
+
+ @Override
+ public String visitVariable(VariableElement variable, DependencyRequest request) {
+ TypeMirror requestedType = requestType(request.kind(), request.key().type(), types);
+ return INDENT
+ + formatQualifier(request.key().qualifier())
+ + requestedType
+ + " is injected at\n"
+ + DOUBLE_INDENT
+ + elementToString(variable);
+ }
+
+ @Override
+ public String visitType(TypeElement e, DependencyRequest request) {
+ return ""; // types by themselves provide no useful information.
+ }
+
+ @Override
+ protected String defaultAction(Element element, DependencyRequest request) {
+ throw new IllegalStateException(
+ "Invalid request " + element.getKind() + " element " + element);
+ }
+ };
+
+ private String formatQualifier(Optional<AnnotationMirror> maybeQualifier) {
+ return maybeQualifier.map(qualifier -> qualifier + " ").orElse("");
+ }
+
+ /**
+ * Returns the verb for a component method dependency request. Returns "produced", "provided", or
+ * "injected", depending on the kind of request.
+ */
+ private String componentMethodRequestVerb(DependencyRequest request) {
+ switch (request.kind()) {
+ case FUTURE:
+ case PRODUCER:
+ return "produced";
+
+ case INSTANCE:
+ case LAZY:
+ case PROVIDER:
+ case PROVIDER_OF_LAZY:
+ return "provided";
+
+ case MEMBERS_INJECTION:
+ return "injected";
+
+ case PRODUCED:
+ break;
+ }
+ throw new AssertionError("illegal request kind for method: " + request);
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyRequestValidator.java b/java/dagger/internal/codegen/DependencyRequestValidator.java
new file mode 100644
index 0000000..1a99818
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyRequestValidator.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.RequestKinds.extractKeyType;
+import static dagger.internal.codegen.RequestKinds.getRequestKind;
+import static javax.lang.model.type.TypeKind.WILDCARD;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.MembersInjector;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/** Validation for dependency requests. */
+final class DependencyRequestValidator {
+ private final MembersInjectionValidator membersInjectionValidator;
+
+ @Inject
+ DependencyRequestValidator(MembersInjectionValidator membersInjectionValidator) {
+ this.membersInjectionValidator = membersInjectionValidator;
+ }
+
+ /**
+ * Adds an error if the given dependency request has more than one qualifier annotation or is a
+ * non-instance request with a wildcard type.
+ */
+ void validateDependencyRequest(
+ ValidationReport.Builder<?> report, Element requestElement, TypeMirror requestType) {
+ ImmutableSet<? extends AnnotationMirror> qualifiers = getQualifiers(requestElement);
+ if (qualifiers.size() > 1) {
+ for (AnnotationMirror qualifier : qualifiers) {
+ report.addError(
+ "A single dependency request may not use more than one @Qualifier",
+ requestElement,
+ qualifier);
+ }
+ }
+
+ TypeMirror keyType = extractKeyType(getRequestKind(requestType), requestType);
+ if (keyType.getKind().equals(WILDCARD)) {
+ // TODO(ronshapiro): Explore creating this message using RequestKinds.
+ report.addError(
+ "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, "
+ + "or Produced<T> when T is a wildcard type such as "
+ + keyType,
+ requestElement);
+ }
+ if (MoreTypes.isType(keyType) && MoreTypes.isTypeOf(MembersInjector.class, keyType)) {
+ DeclaredType membersInjectorType = MoreTypes.asDeclared(keyType);
+ if (membersInjectorType.getTypeArguments().isEmpty()) {
+ report.addError("Cannot inject a raw MembersInjector", requestElement);
+ } else {
+ report.addSubreport(
+ membersInjectionValidator.validateMembersInjectionRequest(
+ requestElement, membersInjectorType.getTypeArguments().get(0)));
+ }
+ }
+ }
+
+ /**
+ * Adds an error if the given dependency request is for a {@link dagger.producers.Producer} or
+ * {@link dagger.producers.Produced}.
+ *
+ * <p>Only call this when processing a provision binding.
+ */
+ // TODO(dpb): Should we disallow Producer entry points in non-production components?
+ void checkNotProducer(ValidationReport.Builder<?> report, VariableElement requestElement) {
+ TypeMirror requestType = requestElement.asType();
+ if (FrameworkTypes.isProducerType(requestType)) {
+ report.addError(
+ String.format(
+ "%s may only be injected in @Produces methods",
+ MoreTypes.asTypeElement(requestType).getSimpleName()),
+ requestElement);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DependencyVariableNamer.java b/java/dagger/internal/codegen/DependencyVariableNamer.java
new file mode 100644
index 0000000..21f2d32
--- /dev/null
+++ b/java/dagger/internal/codegen/DependencyVariableNamer.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.SourceFiles.simpleVariableName;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Ascii;
+import com.google.common.base.CaseFormat;
+import dagger.Lazy;
+import dagger.model.DependencyRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.inject.Provider;
+
+/**
+ * Picks a reasonable name for what we think is being provided from the variable name associated
+ * with the {@link DependencyRequest}. I.e. strips out words like "lazy" and "provider" if we
+ * believe that those refer to {@link Lazy} and {@link Provider} rather than the type being
+ * provided.
+ */
+//TODO(gak): develop the heuristics to get better names
+final class DependencyVariableNamer {
+ private static final Pattern LAZY_PROVIDER_PATTERN = Pattern.compile("lazy(\\w+)Provider");
+
+ static String name(DependencyRequest dependency) {
+ if (!dependency.requestElement().isPresent()) {
+ return simpleVariableName(MoreTypes.asTypeElement(dependency.key().type()));
+ }
+
+ String variableName = dependency.requestElement().get().getSimpleName().toString();
+ if (Ascii.isUpperCase(variableName.charAt(0))) {
+ variableName = toLowerCamel(variableName);
+ }
+ switch (dependency.kind()) {
+ case INSTANCE:
+ return variableName;
+ case LAZY:
+ return variableName.startsWith("lazy") && !variableName.equals("lazy")
+ ? toLowerCamel(variableName.substring(4))
+ : variableName;
+ case PROVIDER_OF_LAZY:
+ Matcher matcher = LAZY_PROVIDER_PATTERN.matcher(variableName);
+ if (matcher.matches()) {
+ return toLowerCamel(matcher.group(1));
+ }
+ // fall through
+ case PROVIDER:
+ return variableName.endsWith("Provider") && !variableName.equals("Provider")
+ ? variableName.substring(0, variableName.length() - 8)
+ : variableName;
+ case PRODUCED:
+ return variableName.startsWith("produced") && !variableName.equals("produced")
+ ? toLowerCamel(variableName.substring(8))
+ : variableName;
+ case PRODUCER:
+ return variableName.endsWith("Producer") && !variableName.equals("Producer")
+ ? variableName.substring(0, variableName.length() - 8)
+ : variableName;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static String toLowerCamel(String name) {
+ return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name);
+ }
+}
diff --git a/java/dagger/internal/codegen/DependsOnProductionExecutorValidator.java b/java/dagger/internal/codegen/DependsOnProductionExecutorValidator.java
new file mode 100644
index 0000000..e611d22
--- /dev/null
+++ b/java/dagger/internal/codegen/DependsOnProductionExecutorValidator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.DaggerStreams.instancesOf;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.MaybeBinding;
+import dagger.model.Key;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import javax.inject.Inject;
+
+/**
+ * Reports an error on all bindings that depend explicitly on the {@code @Production Executor} key.
+ */
+// TODO(dpb,beder): Validate this during @Inject/@Provides/@Produces validation.
+final class DependsOnProductionExecutorValidator implements BindingGraphPlugin {
+ private final CompilerOptions compilerOptions;
+ private final KeyFactory keyFactory;
+
+ @Inject
+ DependsOnProductionExecutorValidator(CompilerOptions compilerOptions, KeyFactory keyFactory) {
+ this.compilerOptions = compilerOptions;
+ this.keyFactory = keyFactory;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/DependsOnProductionExecutor";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ if (!compilerOptions.usesProducers()) {
+ return;
+ }
+
+ Key productionImplementationExecutorKey = keyFactory.forProductionImplementationExecutor();
+ Key productionExecutorKey = keyFactory.forProductionExecutor();
+
+ bindingGraph.network().nodes().stream()
+ .flatMap(instancesOf(MaybeBinding.class))
+ .filter(node -> node.key().equals(productionExecutorKey))
+ .flatMap(productionExecutor -> bindingGraph.requestingBindings(productionExecutor).stream())
+ .filter(binding -> !binding.key().equals(productionImplementationExecutorKey))
+ .forEach(binding -> reportError(diagnosticReporter, binding));
+ }
+
+ private void reportError(DiagnosticReporter diagnosticReporter, dagger.model.Binding binding) {
+ diagnosticReporter.reportBinding(
+ ERROR, binding, "%s may not depend on the production executor", binding.key());
+ }
+}
diff --git a/java/dagger/internal/codegen/DerivedFromFrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/DerivedFromFrameworkInstanceBindingExpression.java
new file mode 100644
index 0000000..4f2f622
--- /dev/null
+++ b/java/dagger/internal/codegen/DerivedFromFrameworkInstanceBindingExpression.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import javax.lang.model.type.TypeMirror;
+
+/** A binding expression that depends on a framework instance. */
+final class DerivedFromFrameworkInstanceBindingExpression extends BindingExpression {
+
+ private final BindingRequest frameworkRequest;
+ private final RequestKind requestKind;
+ private final FrameworkType frameworkType;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+
+ DerivedFromFrameworkInstanceBindingExpression(
+ Key key,
+ FrameworkType frameworkType,
+ RequestKind requestKind,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types) {
+ this.frameworkRequest = bindingRequest(key, frameworkType);
+ this.requestKind = checkNotNull(requestKind);
+ this.frameworkType = checkNotNull(frameworkType);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.types = checkNotNull(types);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return frameworkType.to(
+ requestKind,
+ componentBindingExpressions.getDependencyExpression(frameworkRequest, requestingClass),
+ types);
+ }
+
+ @Override
+ Expression getDependencyExpressionForComponentMethod(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ Expression frameworkInstance =
+ componentBindingExpressions.getDependencyExpressionForComponentMethod(
+ frameworkRequest, componentMethod, component);
+ Expression forRequestKind = frameworkType.to(requestKind, frameworkInstance, types);
+ TypeMirror rawReturnType = types.erasure(componentMethod.resolvedReturnType(types));
+ if (!types.isAssignable(forRequestKind.type(), rawReturnType)) {
+ checkState(
+ component.isAbstract(),
+ "FrameworkType.to() should always return an accessible type unless we're in "
+ + "ahead-of-time mode, where the framework instance type is erased since it's not "
+ + "publicly accessible, but the return type is accessible to the package. "
+ + "\n Component: %s, method: %s",
+ component.name(),
+ componentMethod);
+ return forRequestKind.castTo(rawReturnType);
+ }
+ return forRequestKind;
+ }
+}
diff --git a/java/dagger/internal/codegen/DeserializedComponentImplementationBuilder.java b/java/dagger/internal/codegen/DeserializedComponentImplementationBuilder.java
new file mode 100644
index 0000000..45e99a8
--- /dev/null
+++ b/java/dagger/internal/codegen/DeserializedComponentImplementationBuilder.java
@@ -0,0 +1,256 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues;
+import static dagger.internal.codegen.serialization.ProtoSerialization.fromAnnotationValue;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+import static javax.lang.model.util.ElementFilter.typesIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.ComponentDefinitionType;
+import dagger.internal.ConfigureInitializationParameters;
+import dagger.internal.ModifiableBinding;
+import dagger.internal.ModifiableModule;
+import dagger.internal.codegen.ComponentImplementation.ConfigureInitializationMethod;
+import dagger.internal.codegen.serialization.BindingRequestProto;
+import dagger.internal.codegen.serialization.ComponentRequirementProto;
+import dagger.internal.codegen.serialization.FrameworkTypeWrapper;
+import dagger.internal.codegen.serialization.KeyProto;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Reconstructs {@link ComponentImplementation}s that have already been compiled. Uses metadata
+ * annotations on the generated type and it's methods to reconstitute the equivalent {@link
+ * ComponentImplementation} state.
+ */
+final class DeserializedComponentImplementationBuilder {
+ private final CompilerOptions compilerOptions;
+ private final ComponentCreatorImplementationFactory componentCreatorImplementationFactory;
+ private final TypeProtoConverter typeProtoConverter;
+ private final KeyFactory keyFactory;
+
+ @Inject
+ DeserializedComponentImplementationBuilder(
+ CompilerOptions compilerOptions,
+ ComponentCreatorImplementationFactory componentCreatorImplementationFactory,
+ TypeProtoConverter typeProtoConverter,
+ KeyFactory keyFactory) {
+ this.compilerOptions = compilerOptions;
+ this.componentCreatorImplementationFactory = componentCreatorImplementationFactory;
+ this.typeProtoConverter = typeProtoConverter;
+ this.keyFactory = keyFactory;
+ }
+
+ /** Creates a new {@link ComponentImplementation} from a compiled component. */
+ ComponentImplementation create(ComponentDescriptor component, TypeElement generatedComponent) {
+ Optional<ComponentImplementation> superclassImplementation =
+ deserializedSuperclassImplementation(
+ component, MoreTypes.asTypeElement(generatedComponent.getSuperclass()));
+
+ ComponentImplementation componentImplementation =
+ ComponentImplementation.forDeserializedComponent(
+ component,
+ ClassName.get(generatedComponent),
+ generatedComponent.getNestingKind(),
+ superclassImplementation,
+ compilerOptions);
+
+ componentImplementation.setCreatorImplementation(
+ superclassImplementation.isPresent()
+ ? Optional.empty()
+ : componentCreatorImplementationFactory.create(
+ componentImplementation, Optional.empty()));
+
+ // TODO(b/117833324): Consider omitting superclass implementations, so that only one instance of
+ // ComponentImplementation needs to be created (in most cases, we don't care about nested levels
+ // of superclass implementations, except for the base implementation). If that's possible, use
+ // getLocalAndInheritedMethods instead of getEnclosedElements() here.
+ for (ExecutableElement method : methodsIn(generatedComponent.getEnclosedElements())) {
+ getAnnotationMirror(method, ModifiableBinding.class)
+ .asSet()
+ .forEach(
+ annotation ->
+ addModifiableBindingMethod(componentImplementation, method, annotation));
+
+ getAnnotationMirror(method, ModifiableModule.class)
+ .asSet()
+ .forEach(
+ annotation -> addModifiableModuleMethod(componentImplementation, method, annotation));
+
+ getAnnotationMirror(method, ConfigureInitializationParameters.class)
+ .asSet()
+ .forEach(
+ annotation ->
+ setConfigureInitializationMethod(componentImplementation, method, annotation));
+ }
+
+ for (TypeElement nestedType : typesIn(generatedComponent.getEnclosedElements())) {
+ addChildImplementation(component, componentImplementation, nestedType);
+ }
+
+ return componentImplementation;
+ }
+
+ private Optional<ComponentImplementation> deserializedSuperclassImplementation(
+ ComponentDescriptor component, TypeElement superclassElement) {
+ return isAnnotationPresent(superclassElement, ComponentDefinitionType.class)
+ ? Optional.of(create(component, superclassElement))
+ : Optional.empty();
+ }
+
+ private void addModifiableBindingMethod(
+ ComponentImplementation componentImplementation,
+ ExecutableElement method,
+ AnnotationMirror metadataAnnotation) {
+ ModifiableBindingType modifiableBindingType =
+ ModifiableBindingType.valueOf(
+ getAnnotationValue(metadataAnnotation, "modifiableBindingType").getValue().toString());
+
+ BindingRequest request =
+ parseBindingRequest(getAnnotationValue(metadataAnnotation, "bindingRequest"));
+
+ ImmutableList<Key> multibindingContributions =
+ asAnnotationValues(getAnnotationValue(metadataAnnotation, "multibindingContributions"))
+ .stream()
+ .map(this::parseKey)
+ .collect(toImmutableList());
+
+ componentImplementation.addModifiableBindingMethod(
+ modifiableBindingType,
+ request,
+ method.getReturnType(),
+ methodDeclaration(method),
+ method.getModifiers().contains(FINAL));
+ componentImplementation.registerImplementedMultibindingKeys(request, multibindingContributions);
+ }
+
+ private BindingRequest fromProto(BindingRequestProto bindingRequest) {
+ Key key = keyFactory.fromProto(bindingRequest.getKey());
+ return bindingRequest.getFrameworkType().equals(FrameworkTypeWrapper.FrameworkType.UNKNOWN)
+ ? bindingRequest(key, RequestKind.valueOf(bindingRequest.getRequestKind().name()))
+ : bindingRequest(key, FrameworkType.valueOf(bindingRequest.getFrameworkType().name()));
+ }
+
+ /**
+ * Returns a {@link MethodSpec} for a {@link
+ * dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod}. The method contents
+ * are not relevant since this represents a method that has already been compiled.
+ *
+ * <p>Ideally this could be {@code MethodSpec.overriding(method).build()}, but that doesn't work
+ * for {@code final} methods
+ */
+ private MethodSpec methodDeclaration(ExecutableElement method) {
+ return methodBuilder(method.getSimpleName().toString())
+ .addModifiers(method.getModifiers())
+ .returns(TypeName.get(method.getReturnType()))
+ .build();
+ }
+
+ private void addModifiableModuleMethod(
+ ComponentImplementation componentImplementation,
+ ExecutableElement method,
+ AnnotationMirror metadataAnnotation) {
+ ComponentRequirement moduleRequirement =
+ parseComponentRequirement(getAnnotationValue(metadataAnnotation, "value"));
+ componentImplementation.registerModifiableModuleMethod(
+ moduleRequirement, method.getSimpleName().toString());
+ }
+
+ private void setConfigureInitializationMethod(
+ ComponentImplementation componentImplementation,
+ ExecutableElement method,
+ AnnotationMirror metadataAnnotation) {
+ ImmutableSet<ComponentRequirement> parameters =
+ asAnnotationValues(getAnnotationValue(metadataAnnotation, "value")).stream()
+ .map(this::parseComponentRequirement)
+ .collect(toImmutableSet());
+
+ componentImplementation.setConfigureInitializationMethod(
+ ConfigureInitializationMethod.create(MethodSpec.overriding(method).build(), parameters));
+ }
+
+ private void addChildImplementation(
+ ComponentDescriptor component,
+ ComponentImplementation componentImplementation,
+ TypeElement nestedType) {
+ getAnnotationMirror(nestedType, ComponentDefinitionType.class)
+ .transform(annotation -> (TypeMirror) getAnnotationValue(annotation, "value").getValue())
+ .transform(MoreTypes::asTypeElement)
+ .asSet()
+ .forEach(
+ componentDefinitionType -> {
+ ComponentDescriptor child =
+ component.childComponentsByElement().get(componentDefinitionType);
+ componentImplementation.addChild(child, create(child, nestedType));
+ });
+ }
+
+ private Key parseKey(AnnotationValue annotationValue) {
+ return keyFactory.fromProto(
+ fromAnnotationValue(annotationValue, KeyProto.getDefaultInstance()));
+ }
+
+ private BindingRequest parseBindingRequest(AnnotationValue annotationValue) {
+ return fromProto(
+ fromAnnotationValue(annotationValue, BindingRequestProto.getDefaultInstance()));
+ }
+
+ private ComponentRequirement parseComponentRequirement(AnnotationValue annotationValue) {
+ return fromProto(
+ fromAnnotationValue(annotationValue, ComponentRequirementProto.getDefaultInstance()));
+ }
+
+ private ComponentRequirement fromProto(ComponentRequirementProto proto) {
+ switch (proto.getRequirementCase()) {
+ case MODULE:
+ return ComponentRequirement.forModule(typeProtoConverter.fromProto(proto.getModule()));
+ case DEPENDENCY:
+ return ComponentRequirement.forDependency(
+ typeProtoConverter.fromProto(proto.getDependency()));
+ case BOUND_INSTANCE:
+ return ComponentRequirement.forBoundInstance(
+ keyFactory.fromProto(proto.getBoundInstance().getKey()),
+ proto.getBoundInstance().getNullable(),
+ proto.getBoundInstance().getVariableName());
+ case REQUIREMENT_NOT_SET:
+ // fall through
+ }
+ throw new AssertionError(proto);
+ }
+}
diff --git a/java/dagger/internal/codegen/DiagnosticFormatting.java b/java/dagger/internal/codegen/DiagnosticFormatting.java
new file mode 100644
index 0000000..8502ecb
--- /dev/null
+++ b/java/dagger/internal/codegen/DiagnosticFormatting.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utility methods for formatting diagnostics to the {@link javax.annotation.processing.Messager}.
+ */
+final class DiagnosticFormatting {
+
+ /**
+ * A regular expression to match a small list of specific packages deemed to be unhelpful to
+ * display in fully qualified types in error messages.
+ *
+ * <p>Note: This should never be applied to messages themselves.
+ */
+ private static final Pattern COMMON_PACKAGE_PATTERN =
+ Pattern.compile(
+ "(?:^|[^.a-z_])" // What we want to match on but not capture.
+ + "((?:" // Start a group with a non-capturing or part
+ + "java[.]lang"
+ + "|java[.]util"
+ + "|javax[.]inject"
+ + "|dagger"
+ + "|com[.]google[.]common[.]base"
+ + "|com[.]google[.]common[.]collect"
+ + ")[.])" // Always end with a literal .
+ + "[A-Z]"); // What we want to match on but not capture.
+
+ /**
+ * A method to strip out common packages and a few rare type prefixes from types' string
+ * representation before being used in error messages.
+ *
+ * <p>This type assumes a String value that is a valid fully qualified (and possibly
+ * parameterized) type, and should NOT be used with arbitrary text, especially prose error
+ * messages.
+ *
+ * <p>TODO(cgruber): Tighten these to take type representations (mirrors and elements) to avoid
+ * accidental mis-use by running errors through this method.
+ */
+ static String stripCommonTypePrefixes(String type) {
+ // Do regex magic to remove common packages we care to shorten.
+ Matcher matcher = COMMON_PACKAGE_PATTERN.matcher(type);
+ StringBuilder result = new StringBuilder();
+ int index = 0;
+ while (matcher.find()) {
+ result.append(type.subSequence(index, matcher.start(1)));
+ index = matcher.end(1); // Skip the matched pattern content.
+ }
+ result.append(type.subSequence(index, type.length()));
+ return result.toString();
+ }
+
+ private DiagnosticFormatting() {}
+}
diff --git a/java/dagger/internal/codegen/DiagnosticReporterFactory.java b/java/dagger/internal/codegen/DiagnosticReporterFactory.java
new file mode 100644
index 0000000..f657cee
--- /dev/null
+++ b/java/dagger/internal/codegen/DiagnosticReporterFactory.java
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2018 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.auto.common.MoreTypes.asTypeElement;
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.Iterables.indexOf;
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Lists.asList;
+import static dagger.internal.codegen.DaggerGraphs.shortestPath;
+import static dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.DaggerStreams.presentValues;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.ElementFormatter.elementToString;
+import static dagger.internal.codegen.ValidationType.NONE;
+import static dagger.internal.codegen.langmodel.DaggerElements.DECLARATION_ORDER;
+import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
+import static dagger.internal.codegen.langmodel.DaggerElements.elementEncloses;
+import static java.util.Collections.min;
+import static java.util.Comparator.comparing;
+import static java.util.Comparator.comparingInt;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Table;
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+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.Node;
+import dagger.model.ComponentPath;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.function.Function;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+import org.checkerframework.checker.nullness.compatqual.NullableDecl;
+
+/** A factory for {@link DiagnosticReporter}s. */
+// TODO(ronshapiro): If multiple plugins print errors on the same node/edge, should we condense the
+// messages and only print the dependency trace once?
+final class DiagnosticReporterFactory {
+ private final DaggerTypes types;
+ private final Messager messager;
+ private final DependencyRequestFormatter dependencyRequestFormatter;
+ private final ElementFormatter elementFormatter;
+ private final CompilerOptions compilerOptions;
+
+ @Inject
+ DiagnosticReporterFactory(
+ DaggerTypes types,
+ Messager messager,
+ DependencyRequestFormatter dependencyRequestFormatter,
+ ElementFormatter elementFormatter,
+ CompilerOptions compilerOptions) {
+ this.types = types;
+ this.messager = messager;
+ this.dependencyRequestFormatter = dependencyRequestFormatter;
+ this.elementFormatter = elementFormatter;
+ this.compilerOptions = compilerOptions;
+ }
+
+ /** Creates a reporter for a binding graph and a plugin. */
+ DiagnosticReporterImpl reporter(BindingGraph graph, BindingGraphPlugin plugin) {
+ return new DiagnosticReporterImpl(graph, plugin.pluginName());
+ }
+
+ private static <K, V> Function<K, V> memoize(Function<K, V> uncached) {
+ // If Android Guava is on the processor path, then c.g.c.b.Function (which LoadingCache
+ // implements) does not extend j.u.f.Function.
+
+ // First, explicitly convert uncached to c.g.c.b.Function because CacheLoader.from() expects
+ // one.
+ com.google.common.base.Function<K, V> uncachedAsBaseFunction = uncached::apply;
+
+ LoadingCache<K, V> cache =
+ CacheBuilder.newBuilder().build(CacheLoader.from(uncachedAsBaseFunction));
+
+ // Second, explicitly convert LoadingCache to j.u.f.Function.
+ @SuppressWarnings("deprecation") // uncachedAsBaseFunction throws only unchecked exceptions
+ Function<K, V> memoized = cache::apply;
+
+ return memoized;
+ }
+
+ /**
+ * A {@link DiagnosticReporter} that keeps track of which {@linkplain Diagnostic.Kind kinds} of
+ * diagnostics were reported.
+ */
+ final class DiagnosticReporterImpl implements DiagnosticReporter {
+
+ /** A cached function from type to all of its supertypes in breadth-first order. */
+ private final Function<TypeElement, Iterable<TypeElement>> supertypes =
+ memoize(
+ component ->
+ transform(types.supertypes(component.asType()), type -> asTypeElement(type)));
+
+ /** The shortest path (value) from an entry point (column) to a binding (row). */
+ private final Table<MaybeBinding, DependencyEdge, ImmutableList<Node>> shortestPaths =
+ HashBasedTable.create();
+
+ private final BindingGraph graph;
+ private final String plugin;
+ private final TypeElement rootComponent;
+ private final ImmutableSet.Builder<Diagnostic.Kind> reportedDiagnosticKinds =
+ ImmutableSet.builder();
+
+ DiagnosticReporterImpl(BindingGraph graph, String plugin) {
+ this.graph = graph;
+ this.plugin = plugin;
+ this.rootComponent = graph.rootComponentNode().componentPath().currentComponent();
+ }
+
+ /** Returns which {@linkplain Diagnostic.Kind kinds} of diagnostics were reported. */
+ ImmutableSet<Diagnostic.Kind> reportedDiagnosticKinds() {
+ return reportedDiagnosticKinds.build();
+ }
+
+ @Override
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String messageFormat) {
+ StringBuilder message = new StringBuilder(messageFormat);
+ appendComponentPathUnlessAtRoot(message, componentNode);
+ // TODO(dpb): Report at the component node component.
+ printMessage(diagnosticKind, message, rootComponent);
+ }
+
+ @Override
+ @FormatMethod
+ public void reportComponent(
+ Diagnostic.Kind diagnosticKind,
+ ComponentNode componentNode,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportComponent(
+ diagnosticKind, componentNode, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ // TODO(ronshapiro): should this also include the binding element?
+ @Override
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
+ printMessage(diagnosticKind, message + new DiagnosticInfo(binding), rootComponent);
+ }
+
+ @Override
+ public void reportBinding(
+ Diagnostic.Kind diagnosticKind,
+ MaybeBinding binding,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportBinding(diagnosticKind, binding, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ @Override
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
+ printMessage(diagnosticKind, message + new DiagnosticInfo(dependencyEdge), rootComponent);
+ }
+
+ @Override
+ public void reportDependency(
+ Diagnostic.Kind diagnosticKind,
+ DependencyEdge dependencyEdge,
+ String messageFormat,
+ Object firstArg,
+ Object... moreArgs) {
+ reportDependency(
+ diagnosticKind, dependencyEdge, formatMessage(messageFormat, firstArg, moreArgs));
+ }
+
+ @Override
+ public void reportSubcomponentFactoryMethod(
+ Diagnostic.Kind diagnosticKind,
+ ChildFactoryMethodEdge childFactoryMethodEdge,
+ String message) {
+ printMessage(diagnosticKind, message, childFactoryMethodEdge.factoryMethod());
+ }
+
+ @Override
+ public 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());
+ }
+
+ private Node source(Edge edge) {
+ return graph.network().incidentNodes(edge).source();
+ }
+
+ void printMessage(
+ Diagnostic.Kind diagnosticKind,
+ CharSequence message,
+ @NullableDecl Element elementToReport) {
+ if (graph.isFullBindingGraph()) {
+ ValidationType validationType =
+ compilerOptions.fullBindingGraphValidationType(rootComponent);
+ if (validationType.equals(NONE)) {
+ return;
+ }
+ if (diagnosticKind.equals(ERROR)) {
+ diagnosticKind = validationType.diagnosticKind().get();
+ }
+ }
+ reportedDiagnosticKinds.add(diagnosticKind);
+ StringBuilder fullMessage = new StringBuilder();
+ appendBracketPrefix(fullMessage, plugin);
+
+ // TODO(ronshapiro): should we create a HashSet out of elementEncloses() so we don't
+ // need to do an O(n) contains() each time?
+ if (elementToReport != null && !elementEncloses(rootComponent, elementToReport)) {
+ appendBracketPrefix(fullMessage, elementToString(elementToReport));
+ elementToReport = rootComponent;
+ }
+
+ messager.printMessage(diagnosticKind, fullMessage.append(message), elementToReport);
+ }
+
+ private void appendComponentPathUnlessAtRoot(StringBuilder message, Node node) {
+ if (!node.componentPath().equals(graph.rootComponentNode().componentPath())) {
+ message.append(String.format(" [%s]", node.componentPath()));
+ }
+ }
+
+ private void appendBracketPrefix(StringBuilder message, String prefix) {
+ message.append(String.format("[%s] ", prefix));
+ }
+
+ /** The diagnostic information associated with an error. */
+ private final class DiagnosticInfo {
+ final ImmutableList<DependencyEdge> dependencyTrace;
+ final ImmutableSet<DependencyEdge> requests;
+ final ImmutableSet<DependencyEdge> entryPoints;
+
+ DiagnosticInfo(MaybeBinding binding) {
+ entryPoints = graph.entryPointEdgesDependingOnBinding(binding);
+ requests = requests(binding);
+ dependencyTrace = dependencyTrace(binding, entryPoints);
+ }
+
+ DiagnosticInfo(DependencyEdge dependencyEdge) {
+ requests = ImmutableSet.of(dependencyEdge);
+ ImmutableList.Builder<DependencyEdge> dependencyTraceBuilder = ImmutableList.builder();
+ dependencyTraceBuilder.add(dependencyEdge);
+
+ if (dependencyEdge.isEntryPoint()) {
+ entryPoints = ImmutableSet.of(dependencyEdge);
+ } else {
+ // It's not an entry point, so it's part of a binding
+ dagger.model.Binding binding = (dagger.model.Binding) source(dependencyEdge);
+ entryPoints = graph.entryPointEdgesDependingOnBinding(binding);
+ dependencyTraceBuilder.addAll(dependencyTrace(binding, entryPoints));
+ }
+ dependencyTrace = dependencyTraceBuilder.build();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder message =
+ graph.isFullBindingGraph()
+ ? new StringBuilder()
+ : new StringBuilder(dependencyTrace.size() * 100 /* a guess heuristic */);
+
+ // Print the dependency trace unless it's a full binding graph
+ if (!graph.isFullBindingGraph()) {
+ dependencyTrace.forEach(
+ edge ->
+ dependencyRequestFormatter.appendFormatLine(message, edge.dependencyRequest()));
+ if (!dependencyTrace.isEmpty()) {
+ appendComponentPathUnlessAtRoot(message, source(getLast(dependencyTrace)));
+ }
+ }
+
+ // Print any dependency requests that aren't shown as part of the dependency trace.
+ ImmutableSet<Element> requestsToPrint =
+ requests.stream()
+ // if printing entry points, skip entry points and the traced request
+ .filter(
+ request ->
+ graph.isFullBindingGraph()
+ || (!request.isEntryPoint() && !isTracedRequest(request)))
+ .map(request -> request.dependencyRequest().requestElement())
+ .flatMap(presentValues())
+ .collect(toImmutableSet());
+ if (!requestsToPrint.isEmpty()) {
+ message
+ .append("\nIt is")
+ .append(graph.isFullBindingGraph() ? " " : " also ")
+ .append("requested at:");
+ elementFormatter.formatIndentedList(message, requestsToPrint, 1);
+ }
+
+ // Print the remaining entry points, showing which component they're in, unless it's a full
+ // binding graph
+ if (!graph.isFullBindingGraph() && entryPoints.size() > 1) {
+ message.append("\nThe following other entry points also depend on it:");
+ entryPointFormatter.formatIndentedList(
+ message,
+ entryPoints.stream()
+ .filter(entryPoint -> !entryPoint.equals(getLast(dependencyTrace)))
+ .sorted(
+ // 1. List entry points in components closest to the root first.
+ // 2. List entry points declared in a component before those in a supertype.
+ // 3. List entry points in declaration order in their declaring type.
+ rootComponentFirst()
+ .thenComparing(nearestComponentSupertypeFirst())
+ .thenComparing(requestElementDeclarationOrder()))
+ .collect(toImmutableList()),
+ 1);
+ }
+ return message.toString();
+ }
+
+ private final Formatter<DependencyEdge> entryPointFormatter =
+ new Formatter<DependencyEdge>() {
+ @Override
+ public String format(DependencyEdge object) {
+ Element requestElement = object.dependencyRequest().requestElement().get();
+ StringBuilder element = new StringBuilder(elementToString(requestElement));
+
+ // For entry points declared in subcomponents or supertypes of the root component,
+ // append the component path to make clear to the user which component it's in.
+ ComponentPath componentPath = source(object).componentPath();
+ if (!componentPath.atRoot()
+ || !requestElement.getEnclosingElement().equals(rootComponent)) {
+ element.append(String.format(" [%s]", componentPath));
+ }
+ return element.toString();
+ }
+ };
+
+ private boolean isTracedRequest(DependencyEdge request) {
+ return !dependencyTrace.isEmpty() && request.equals(dependencyTrace.get(0));
+ }
+
+ /**
+ * 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.model could be useful, i.e.
+ // bindingGraph.shortestPathFromEntryPoint(DependencyEdge, MaybeBindingNode)
+ ImmutableList<DependencyEdge> dependencyTrace(
+ MaybeBinding binding, ImmutableSet<DependencyEdge> entryPoints) {
+ // Module binding graphs may have bindings unreachable from any entry points. If there are
+ // no entry points for this DiagnosticInfo, don't try to print a dependency trace.
+ if (entryPoints.isEmpty()) {
+ return ImmutableList.of();
+ }
+ // Show the full dependency trace for one entry point.
+ DependencyEdge entryPointForTrace =
+ min(
+ entryPoints,
+ // prefer entry points in components closest to the root
+ rootComponentFirst()
+ // then prefer entry points with a short dependency path to the error
+ .thenComparing(shortestDependencyPathFirst(binding))
+ // then prefer entry points declared in the component to those declared in a
+ // supertype
+ .thenComparing(nearestComponentSupertypeFirst())
+ // finally prefer entry points declared first in their enclosing type
+ .thenComparing(requestElementDeclarationOrder()));
+
+ ImmutableList<Node> shortestBindingPath =
+ shortestPathFromEntryPoint(entryPointForTrace, binding);
+ verify(
+ !shortestBindingPath.isEmpty(),
+ "no dependency path from %s to %s in %s",
+ entryPointForTrace,
+ binding,
+ graph);
+
+ ImmutableList.Builder<DependencyEdge> dependencyTrace = ImmutableList.builder();
+ dependencyTrace.add(entryPointForTrace);
+ for (int i = 0; i < shortestBindingPath.size() - 1; i++) {
+ Set<Edge> dependenciesBetween =
+ graph
+ .network()
+ .edgesConnecting(shortestBindingPath.get(i), shortestBindingPath.get(i + 1));
+ // If a binding requests a key more than once, any of them should be fine to get to the
+ // shortest path
+ dependencyTrace.add((DependencyEdge) Iterables.get(dependenciesBetween, 0));
+ }
+ return dependencyTrace.build().reverse();
+ }
+
+ /** Returns all the nonsynthetic dependency requests for a binding. */
+ ImmutableSet<DependencyEdge> requests(MaybeBinding binding) {
+ return graph.network().inEdges(binding).stream()
+ .flatMap(instancesOf(DependencyEdge.class))
+ .filter(edge -> edge.dependencyRequest().requestElement().isPresent())
+ .sorted(requestEnclosingTypeName().thenComparing(requestElementDeclarationOrder()))
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns a comparator that sorts entry points in components whose paths from the root are
+ * shorter first.
+ */
+ Comparator<DependencyEdge> rootComponentFirst() {
+ return comparingInt(entryPoint -> source(entryPoint).componentPath().components().size());
+ }
+
+ /**
+ * Returns a comparator that puts entry points whose shortest dependency path to {@code
+ * binding} is shortest first.
+ */
+ Comparator<DependencyEdge> shortestDependencyPathFirst(MaybeBinding binding) {
+ return comparing(entryPoint -> shortestPathFromEntryPoint(entryPoint, binding).size());
+ }
+
+ ImmutableList<Node> shortestPathFromEntryPoint(
+ DependencyEdge entryPoint, MaybeBinding binding) {
+ return shortestPaths
+ .row(binding)
+ .computeIfAbsent(
+ entryPoint,
+ ep ->
+ shortestPath(
+ node ->
+ filter(
+ graph.network().successors(node), MaybeBinding.class::isInstance),
+ graph.network().incidentNodes(ep).target(),
+ binding));
+ }
+
+ /**
+ * Returns a comparator that sorts entry points in by the distance of the type that declares
+ * them from the type of the component that contains them.
+ *
+ * <p>For instance, an entry point declared directly in the component type would sort before
+ * one declared in a direct supertype, which would sort before one declared in a supertype of
+ * a supertype.
+ */
+ Comparator<DependencyEdge> nearestComponentSupertypeFirst() {
+ return comparingInt(
+ entryPoint ->
+ indexOf(
+ supertypes.apply(componentContainingEntryPoint(entryPoint)),
+ equalTo(typeDeclaringEntryPoint(entryPoint))));
+ }
+
+ TypeElement componentContainingEntryPoint(DependencyEdge entryPoint) {
+ return source(entryPoint).componentPath().currentComponent();
+ }
+
+ TypeElement typeDeclaringEntryPoint(DependencyEdge entryPoint) {
+ return MoreElements.asType(
+ entryPoint.dependencyRequest().requestElement().get().getEnclosingElement());
+ }
+
+ /**
+ * Returns a comparator that sorts dependency edges lexicographically by the qualified name of
+ * the type that contains them. Only appropriate for edges with request elements.
+ */
+ Comparator<DependencyEdge> requestEnclosingTypeName() {
+ return comparing(
+ edge ->
+ closestEnclosingTypeElement(edge.dependencyRequest().requestElement().get())
+ .getQualifiedName()
+ .toString());
+ }
+
+ /**
+ * Returns a comparator that sorts edges in the order in which their request elements were
+ * declared in their declaring type.
+ *
+ * <p>Only useful to compare edges whose request elements were declared in the same type.
+ */
+ Comparator<DependencyEdge> requestElementDeclarationOrder() {
+ return comparing(
+ edge -> edge.dependencyRequest().requestElement().get(), DECLARATION_ORDER);
+ }
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/DuplicateBindingsValidator.java b/java/dagger/internal/codegen/DuplicateBindingsValidator.java
new file mode 100644
index 0000000..3eed45f
--- /dev/null
+++ b/java/dagger/internal/codegen/DuplicateBindingsValidator.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSetMultimap;
+import static dagger.internal.codegen.Formatter.INDENT;
+import static dagger.internal.codegen.Optionals.emptiesLast;
+import static dagger.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MEMBERS_INJECTION;
+import static java.util.Comparator.comparing;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMultiset;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import dagger.model.Binding;
+import dagger.model.BindingGraph;
+import dagger.model.BindingKind;
+import dagger.model.ComponentPath;
+import dagger.model.Key;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+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.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic.Kind;
+
+/** Reports errors for conflicting bindings with the same key. */
+final class DuplicateBindingsValidator implements BindingGraphPlugin {
+
+ // 1. contributing module or enclosing type
+ // 2. binding element's simple name
+ // 3. binding element's type
+ private static final Comparator<BindingDeclaration> BINDING_DECLARATION_COMPARATOR =
+ comparing(
+ (BindingDeclaration declaration) ->
+ declaration.contributingModule().isPresent()
+ ? declaration.contributingModule()
+ : declaration.bindingTypeElement(),
+ emptiesLast(comparing((TypeElement type) -> type.getQualifiedName().toString())))
+ .thenComparing(
+ (BindingDeclaration declaration) -> declaration.bindingElement(),
+ emptiesLast(
+ comparing((Element element) -> element.getSimpleName().toString())
+ .thenComparing((Element element) -> element.asType().toString())));
+
+ private static final Comparator<Binding> BY_LENGTH_OF_COMPONENT_PATH =
+ comparing(binding -> binding.componentPath().components().size());
+
+ private final BindingDeclarationFormatter bindingDeclarationFormatter;
+ private final CompilerOptions compilerOptions;
+
+ @Inject
+ DuplicateBindingsValidator(
+ BindingDeclarationFormatter bindingDeclarationFormatter, CompilerOptions compilerOptions) {
+ this.bindingDeclarationFormatter = bindingDeclarationFormatter;
+ this.compilerOptions = compilerOptions;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/DuplicateBindings";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ // If two unrelated subcomponents have the same duplicate bindings only because they install the
+ // 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<>();
+ 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);
+ }
+ });
+ }
+
+ /**
+ * Returns sets of duplicate bindings. Bindings are duplicates if they bind the same key and are
+ * visible from the same component. Two bindings that differ only in the component that owns them
+ * are not considered to be duplicates, because that means the same binding was "copied" down to a
+ * 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(
+ BindingGraph bindingGraph) {
+ return groupBindingsByKey(bindingGraph).stream()
+ .flatMap(bindings -> mutuallyVisibleSubsets(bindings).stream())
+ .map(BindingElement::index)
+ .filter(duplicates -> duplicates.keySet().size() > 1)
+ .collect(toImmutableSet());
+ }
+
+ private static ImmutableSet<ImmutableSet<Binding>> groupBindingsByKey(BindingGraph bindingGraph) {
+ return valueSetsForEachKey(
+ bindingGraph.bindings().stream()
+ .filter(binding -> !binding.kind().equals(MEMBERS_INJECTION))
+ .collect(toImmutableSetMultimap(Binding::key, binding -> binding)));
+ }
+
+ /**
+ * Returns the subsets of the input set that contain bindings that are all visible from the same
+ * component. A binding is visible from its component and all its descendants.
+ */
+ private static ImmutableSet<ImmutableSet<Binding>> mutuallyVisibleSubsets(
+ Set<Binding> duplicateBindings) {
+ ImmutableListMultimap<ComponentPath, Binding> bindingsByComponentPath =
+ Multimaps.index(duplicateBindings, Binding::componentPath);
+ ImmutableSetMultimap.Builder<ComponentPath, Binding> mutuallyVisibleBindings =
+ ImmutableSetMultimap.builder();
+ bindingsByComponentPath
+ .asMap()
+ .forEach(
+ (componentPath, bindings) -> {
+ mutuallyVisibleBindings.putAll(componentPath, bindings);
+ for (ComponentPath ancestor = componentPath; !ancestor.atRoot(); ) {
+ ancestor = ancestor.parent();
+ ImmutableList<Binding> bindingsInAncestor = bindingsByComponentPath.get(ancestor);
+ mutuallyVisibleBindings.putAll(componentPath, bindingsInAncestor);
+ }
+ });
+ return valueSetsForEachKey(mutuallyVisibleBindings.build());
+ }
+
+ private void reportDuplicateBindings(
+ ImmutableSetMultimap<BindingElement, Binding> duplicateBindings,
+ BindingGraph bindingGraph,
+ DiagnosticReporter diagnosticReporter) {
+ if (explicitBindingConfictsWithInject(duplicateBindings.keySet())) {
+ compilerOptions
+ .explicitBindingConflictsWithInjectValidationType()
+ .diagnosticKind()
+ .ifPresent(
+ diagnosticKind ->
+ reportExplicitBindingConflictsWithInject(
+ duplicateBindings, diagnosticReporter, diagnosticKind));
+ return;
+ }
+ ImmutableSet<Binding> bindings = ImmutableSet.copyOf(duplicateBindings.values());
+ Binding oneBinding = bindings.asList().get(0);
+ diagnosticReporter.reportBinding(
+ ERROR,
+ oneBinding,
+ Iterables.any(bindings, binding -> binding.kind().isMultibinding())
+ ? incompatibleBindingsMessage(oneBinding.key(), bindings, bindingGraph)
+ : duplicateBindingMessage(oneBinding.key(), bindings, bindingGraph));
+ }
+
+ /**
+ * Returns {@code true} if the bindings contain one {@code @Inject} binding and one that isn't.
+ */
+ private static boolean explicitBindingConfictsWithInject(
+ ImmutableSet<BindingElement> duplicateBindings) {
+ ImmutableMultiset<BindingKind> bindingKinds =
+ Multimaps.index(duplicateBindings, BindingElement::bindingKind).keys();
+ return bindingKinds.count(INJECTION) == 1 && bindingKinds.size() == 2;
+ }
+
+ private void reportExplicitBindingConflictsWithInject(
+ ImmutableSetMultimap<BindingElement, Binding> duplicateBindings,
+ DiagnosticReporter diagnosticReporter,
+ Kind diagnosticKind) {
+ Binding injectBinding =
+ rootmostBindingWithKind(k -> k.equals(INJECTION), duplicateBindings.values());
+ Binding explicitBinding =
+ rootmostBindingWithKind(k -> !k.equals(INJECTION), duplicateBindings.values());
+ StringBuilder message =
+ new StringBuilder()
+ .append(explicitBinding.key())
+ .append(" is bound multiple times:")
+ .append(formatWithComponentPath(injectBinding))
+ .append(formatWithComponentPath(explicitBinding))
+ .append(
+ "\nThis condition was never validated before, and will soon be an error. "
+ + "See https://dagger.dev/conflicting-inject.");
+
+ diagnosticReporter.reportBinding(diagnosticKind, explicitBinding, message.toString());
+ }
+
+ private String formatWithComponentPath(Binding binding) {
+ return String.format(
+ "\n%s%s [%s]",
+ Formatter.INDENT,
+ bindingDeclarationFormatter.format(((BindingNode) binding).delegate()),
+ binding.componentPath());
+ }
+
+ private String duplicateBindingMessage(
+ Key key, ImmutableSet<Binding> duplicateBindings, BindingGraph graph) {
+ StringBuilder message = new StringBuilder().append(key).append(" is bound multiple times:");
+ formatDeclarations(message, 1, declarations(graph, duplicateBindings));
+ return message.toString();
+ }
+
+ private String incompatibleBindingsMessage(
+ Key key, ImmutableSet<Binding> duplicateBindings, BindingGraph graph) {
+ ImmutableSet<dagger.model.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.model.Binding multibinding = getOnlyElement(multibindings);
+ messageFormatter.format("%s bindings and declarations:", multibindingTypeString(multibinding));
+ formatDeclarations(message, 2, declarations(graph, multibindings));
+
+ Set<dagger.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)));
+ return message.toString();
+ }
+
+ private void formatDeclarations(
+ StringBuilder builder,
+ int indentLevel,
+ Iterable<? extends BindingDeclaration> bindingDeclarations) {
+ bindingDeclarationFormatter.formatIndentedList(
+ builder, ImmutableList.copyOf(bindingDeclarations), indentLevel);
+ }
+
+ private ImmutableSet<BindingDeclaration> declarations(
+ BindingGraph graph, Set<dagger.model.Binding> bindings) {
+ return bindings.stream()
+ .flatMap(binding -> declarations(graph, binding).stream())
+ .distinct()
+ .sorted(BINDING_DECLARATION_COMPARATOR)
+ .collect(toImmutableSet());
+ }
+
+ private ImmutableSet<BindingDeclaration> declarations(
+ BindingGraph graph, dagger.model.Binding binding) {
+ ImmutableSet.Builder<BindingDeclaration> declarations = ImmutableSet.builder();
+ BindingNode bindingNode = (BindingNode) binding;
+ bindingNode.associatedDeclarations().forEach(declarations::add);
+ if (bindingDeclarationFormatter.canFormat(bindingNode.delegate())) {
+ declarations.add(bindingNode.delegate());
+ } else {
+ graph.requestedBindings(binding).stream()
+ .flatMap(requestedBinding -> declarations(graph, requestedBinding).stream())
+ .forEach(declarations::add);
+ }
+ return declarations.build();
+ }
+
+ private String multibindingTypeString(dagger.model.Binding multibinding) {
+ switch (multibinding.kind()) {
+ case MULTIBOUND_MAP:
+ return "Map";
+ case MULTIBOUND_SET:
+ return "Set";
+ default:
+ throw new AssertionError(multibinding);
+ }
+ }
+
+ private static <E> ImmutableSet<ImmutableSet<E>> valueSetsForEachKey(Multimap<?, E> multimap) {
+ return multimap.asMap().values().stream().map(ImmutableSet::copyOf).collect(toImmutableSet());
+ }
+
+ /** Returns the binding of the given kind that is closest to the root component. */
+ private static Binding rootmostBindingWithKind(
+ Predicate<BindingKind> bindingKindPredicate, ImmutableCollection<Binding> bindings) {
+ return bindings.stream()
+ .filter(b -> bindingKindPredicate.test(b.kind()))
+ .min(BY_LENGTH_OF_COMPONENT_PATH)
+ .get();
+ }
+
+ /** The identifying information about a binding, excluding its {@link Binding#componentPath()}. */
+ @AutoValue
+ abstract static class BindingElement {
+
+ abstract BindingKind bindingKind();
+
+ abstract Optional<Element> bindingElement();
+
+ abstract Optional<TypeElement> contributingModule();
+
+ static ImmutableSetMultimap<BindingElement, Binding> index(Set<Binding> bindings) {
+ return bindings.stream().collect(toImmutableSetMultimap(BindingElement::forBinding, b -> b));
+ }
+
+ private static BindingElement forBinding(Binding binding) {
+ return new AutoValue_DuplicateBindingsValidator_BindingElement(
+ binding.kind(), binding.bindingElement(), binding.contributingModule());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ElementFormatter.java b/java/dagger/internal/codegen/ElementFormatter.java
new file mode 100644
index 0000000..40d7606
--- /dev/null
+++ b/java/dagger/internal/codegen/ElementFormatter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 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.auto.common.MoreElements.asExecutable;
+import static java.util.stream.Collectors.joining;
+
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementKindVisitor8;
+
+/**
+ * Formats elements into a useful string representation.
+ *
+ * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name.
+ *
+ * <p>Parameters are given with their enclosing executable, with other parameters elided.
+ */
+final class ElementFormatter extends Formatter<Element> {
+ @Inject
+ ElementFormatter() {}
+
+ @Override
+ public String format(Element element) {
+ return elementToString(element);
+ }
+
+ /**
+ * Returns a useful string form for an element.
+ *
+ * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name.
+ *
+ * <p>Parameters are given with their enclosing executable, with other parameters elided.
+ */
+ static String elementToString(Element element) {
+ return element.accept(ELEMENT_TO_STRING, null);
+ }
+
+ private static final ElementVisitor<String, Void> ELEMENT_TO_STRING =
+ new ElementKindVisitor8<String, Void>() {
+ @Override
+ public String visitExecutable(ExecutableElement executableElement, Void aVoid) {
+ return enclosingTypeAndMemberName(executableElement)
+ .append(
+ executableElement.getParameters().stream()
+ .map(parameter -> parameter.asType().toString())
+ .collect(joining(", ", "(", ")")))
+ .toString();
+ }
+
+ @Override
+ public String visitVariableAsParameter(VariableElement parameter, Void aVoid) {
+ ExecutableElement methodOrConstructor = asExecutable(parameter.getEnclosingElement());
+ return enclosingTypeAndMemberName(methodOrConstructor)
+ .append('(')
+ .append(
+ formatArgumentInList(
+ methodOrConstructor.getParameters().indexOf(parameter),
+ methodOrConstructor.getParameters().size(),
+ parameter.getSimpleName()))
+ .append(')')
+ .toString();
+ }
+
+ @Override
+ public String visitVariableAsField(VariableElement field, Void aVoid) {
+ return enclosingTypeAndMemberName(field).toString();
+ }
+
+ @Override
+ public String visitType(TypeElement type, Void aVoid) {
+ return type.getQualifiedName().toString();
+ }
+
+ @Override
+ protected String defaultAction(Element element, Void aVoid) {
+ throw new UnsupportedOperationException(
+ "Can't determine string for " + element.getKind() + " element " + element);
+ }
+
+ private StringBuilder enclosingTypeAndMemberName(Element element) {
+ StringBuilder name = new StringBuilder(element.getEnclosingElement().accept(this, null));
+ if (!element.getSimpleName().contentEquals("<init>")) {
+ name.append('.').append(element.getSimpleName());
+ }
+ return name;
+ }
+ };
+}
diff --git a/java/dagger/internal/codegen/ErrorMessages.java b/java/dagger/internal/codegen/ErrorMessages.java
new file mode 100644
index 0000000..4195e1a
--- /dev/null
+++ b/java/dagger/internal/codegen/ErrorMessages.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2014 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 com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/** The collection of error messages to be reported back to users. */
+final class ErrorMessages {
+
+ private static final UnaryOperator<String> PRODUCTION =
+ s ->
+ s.replace("component", "production component")
+ .replace("Component", "ProductionComponent");
+
+ private static final UnaryOperator<String> SUBCOMPONENT =
+ s -> s.replace("component", "subcomponent").replace("Component", "Subcomponent");
+
+ private static final UnaryOperator<String> FACTORY = s -> s.replace("Builder", "Factory");
+
+ private static final ImmutableMap<ComponentKind, Function<String, String>>
+ COMPONENT_TRANSFORMATIONS =
+ ImmutableMap.of(
+ ComponentKind.COMPONENT, UnaryOperator.identity(),
+ ComponentKind.SUBCOMPONENT, SUBCOMPONENT,
+ ComponentKind.PRODUCTION_COMPONENT, PRODUCTION,
+ ComponentKind.PRODUCTION_SUBCOMPONENT, PRODUCTION.andThen(SUBCOMPONENT));
+
+ static ComponentMessages componentMessagesFor(ComponentKind componentKind) {
+ return new ComponentMessages(COMPONENT_TRANSFORMATIONS.get(componentKind));
+ }
+
+ static ComponentMessages componentMessagesFor(ComponentAnnotation componentAnnotation) {
+ return new ComponentMessages(
+ transformation(componentAnnotation.isProduction(), componentAnnotation.isSubcomponent()));
+ }
+
+ static ComponentCreatorMessages creatorMessagesFor(ComponentCreatorAnnotation creatorAnnotation) {
+ Function<String, String> transformation =
+ transformation(
+ creatorAnnotation.isProductionCreatorAnnotation(),
+ creatorAnnotation.isSubcomponentCreatorAnnotation());
+ switch (creatorAnnotation.creatorKind()) {
+ case BUILDER:
+ return new BuilderMessages(transformation);
+ case FACTORY:
+ return new FactoryMessages(transformation);
+ }
+ throw new AssertionError(creatorAnnotation);
+ }
+
+ private static Function<String, String> transformation(
+ boolean isProduction, boolean isSubcomponent) {
+ Function<String, String> transformation = isProduction ? PRODUCTION : UnaryOperator.identity();
+ return isSubcomponent ? transformation.andThen(SUBCOMPONENT) : transformation;
+ }
+
+ private abstract static class Messages {
+ private final Function<String, String> transformation;
+
+ Messages(Function<String, String> transformation) {
+ this.transformation = transformation;
+ }
+
+ protected final String process(String s) {
+ return transformation.apply(s);
+ }
+ }
+
+ /** Errors for components. */
+ static final class ComponentMessages extends Messages {
+ ComponentMessages(Function<String, String> transformation) {
+ super(transformation);
+ }
+
+ final String moreThanOne() {
+ return process("@Component has more than one @Component.Builder or @Component.Factory: %s");
+ }
+ }
+
+ /** Errors for component creators. */
+ abstract static class ComponentCreatorMessages extends Messages {
+ ComponentCreatorMessages(Function<String, String> transformation) {
+ super(transformation);
+ }
+
+ static String builderMethodRequiresNoArgs() {
+ return "Methods returning a @Component.Builder must have no arguments";
+ }
+
+ static String moreThanOneRefToSubcomponent() {
+ return "Only one method can create a given subcomponent. %s is created by: %s";
+ }
+
+ final String invalidConstructor() {
+ return process("@Component.Builder classes must have exactly one constructor,"
+ + " and it must not be private or have any parameters");
+ }
+
+ final String generics() {
+ return process("@Component.Builder types must not have any generic types");
+ }
+
+ final String mustBeInComponent() {
+ return process("@Component.Builder types must be nested within a @Component");
+ }
+
+ final String mustBeClassOrInterface() {
+ return process("@Component.Builder types must be abstract classes or interfaces");
+ }
+
+ final String isPrivate() {
+ return process("@Component.Builder types must not be private");
+ }
+
+ final String mustBeStatic() {
+ return process("@Component.Builder types must be static");
+ }
+
+ final String mustBeAbstract() {
+ return process("@Component.Builder types must be abstract");
+ }
+
+ abstract String missingFactoryMethod();
+
+ abstract String multipleSettersForModuleOrDependencyType();
+
+ abstract String extraSetters();
+
+ abstract String missingSetters();
+
+ abstract String twoFactoryMethods();
+
+ abstract String inheritedTwoFactoryMethods();
+
+ abstract String factoryMethodMustReturnComponentType();
+
+ final String inheritedFactoryMethodMustReturnComponentType() {
+ return factoryMethodMustReturnComponentType() + ". Inherited method: %s";
+ }
+
+ abstract String factoryMethodMayNotBeAnnotatedWithBindsInstance();
+
+ final String inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance() {
+ return factoryMethodMayNotBeAnnotatedWithBindsInstance() + ". Inherited method: %s";
+ }
+
+ final String setterMethodsMustTakeOneArg() {
+ return process("@Component.Builder methods must not have more than one argument");
+ }
+
+ final String inheritedSetterMethodsMustTakeOneArg() {
+ return setterMethodsMustTakeOneArg() + ". Inherited method: %s";
+ }
+
+ final String setterMethodsMustReturnVoidOrBuilder() {
+ return process("@Component.Builder setter methods must return void, the builder,"
+ + " or a supertype of the builder");
+ }
+
+ final String inheritedSetterMethodsMustReturnVoidOrBuilder() {
+ return setterMethodsMustReturnVoidOrBuilder() + ". Inherited method: %s";
+ }
+
+ final String methodsMayNotHaveTypeParameters() {
+ return process("@Component.Builder methods must not have type parameters");
+ }
+
+ final String inheritedMethodsMayNotHaveTypeParameters() {
+ return methodsMayNotHaveTypeParameters() + ". Inherited method: %s";
+ }
+
+ abstract String nonBindsInstanceParametersMayNotBePrimitives();
+
+ final String inheritedNonBindsInstanceParametersMayNotBePrimitives() {
+ return nonBindsInstanceParametersMayNotBePrimitives() + ". Inherited method: %s";
+ }
+
+ final String factoryMethodReturnsSupertypeWithMissingMethods(
+ TypeElement component,
+ TypeElement componentBuilder,
+ TypeMirror returnType,
+ ExecutableElement buildMethod,
+ Set<ExecutableElement> additionalMethods) {
+ return String.format(
+ "%1$s.%2$s() returns %3$s, but %4$s declares additional component method(s): %5$s. In "
+ + "order to provide type-safe access to these methods, override %2$s() to return "
+ + "%4$s",
+ componentBuilder.getQualifiedName(),
+ buildMethod.getSimpleName(),
+ returnType,
+ component.getQualifiedName(),
+ Joiner.on(", ").join(additionalMethods));
+ }
+
+ final String bindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
+ return process("@Component.Builder setter methods may not have @BindsInstance on both the "
+ + "method and its parameter; choose one or the other");
+ }
+
+ final String inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
+ return bindsInstanceNotAllowedOnBothSetterMethodAndParameter() + ". Inherited method: %s";
+ }
+ }
+
+ private static final class BuilderMessages extends ComponentCreatorMessages {
+ BuilderMessages(Function<String, String> transformation) {
+ super(transformation);
+ }
+
+ @Override
+ String missingFactoryMethod() {
+ return process(
+ "@Component.Builder types must have exactly one no-args method that "
+ + " returns the @Component type");
+ }
+
+ @Override
+ String multipleSettersForModuleOrDependencyType() {
+ return process(
+ "@Component.Builder types must not have more than one setter method per module or "
+ + "dependency, but %s is set by %s");
+ }
+
+ @Override
+ String extraSetters() {
+ return process(
+ "@Component.Builder has setters for modules or components that aren't required: %s");
+ }
+
+ @Override
+ String missingSetters() {
+ return process(
+ "@Component.Builder is missing setters for required modules or components: %s");
+ }
+
+ @Override
+ String twoFactoryMethods() {
+ return process(
+ "@Component.Builder types must have exactly one zero-arg method, and that"
+ + " method must return the @Component type. Already found: %s");
+ }
+
+ @Override
+ String inheritedTwoFactoryMethods() {
+ return process(
+ "@Component.Builder types must have exactly one zero-arg method, and that"
+ + " method must return the @Component type. Found %s and %s");
+ }
+
+ @Override
+ String factoryMethodMustReturnComponentType() {
+ return process(
+ "@Component.Builder methods that have no arguments must return the @Component type or a "
+ + "supertype of the @Component");
+ }
+
+ @Override
+ String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
+ return process(
+ "@Component.Builder no-arg build methods may not be annotated with @BindsInstance");
+ }
+
+ @Override
+ String nonBindsInstanceParametersMayNotBePrimitives() {
+ return process(
+ "@Component.Builder methods that are not annotated with @BindsInstance "
+ + "must take either a module or a component dependency, not a primitive");
+ }
+ }
+
+ private static final class FactoryMessages extends ComponentCreatorMessages {
+ FactoryMessages(Function<String, String> transformation) {
+ super(transformation.andThen(FACTORY));
+ }
+
+ @Override
+ String missingFactoryMethod() {
+ return process(
+ "@Component.Factory types must have exactly one method that "
+ + "returns the @Component type");
+ }
+
+ @Override
+ String multipleSettersForModuleOrDependencyType() {
+ return process(
+ "@Component.Factory methods must not have more than one parameter per module or "
+ + "dependency, but %s is set by %s");
+ }
+
+ @Override
+ String extraSetters() {
+ return process(
+ "@Component.Factory method has parameters for modules or components that aren't "
+ + "required: %s");
+ }
+
+ @Override
+ String missingSetters() {
+ return process(
+ "@Component.Factory method is missing parameters for required modules or components: %s");
+ }
+
+ @Override
+ String twoFactoryMethods() {
+ return process(
+ "@Component.Factory types must have exactly one abstract method. Already found: %s");
+ }
+
+ @Override
+ String inheritedTwoFactoryMethods() {
+ return twoFactoryMethods();
+ }
+
+ @Override
+ String factoryMethodMustReturnComponentType() {
+ return process(
+ "@Component.Factory abstract methods must return the @Component type or a "
+ + "supertype of the @Component");
+ }
+
+ @Override
+ String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
+ return process("@Component.Factory method may not be annotated with @BindsInstance");
+ }
+
+ @Override
+ String nonBindsInstanceParametersMayNotBePrimitives() {
+ return process(
+ "@Component.Factory method parameters that are not annotated with @BindsInstance "
+ + "must be either a module or a component dependency, not a primitive");
+ }
+ }
+
+ private ErrorMessages() {}
+}
diff --git a/java/dagger/internal/codegen/FactoryGenerator.java b/java/dagger/internal/codegen/FactoryGenerator.java
new file mode 100644
index 0000000..d367bc5
--- /dev/null
+++ b/java/dagger/internal/codegen/FactoryGenerator.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Maps.transformValues;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.DELEGATE;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
+import static dagger.internal.codegen.GwtCompatibility.gwtIncompatibleAnnotation;
+import static dagger.internal.codegen.SourceFiles.bindingTypeElementTypeVariableNames;
+import static dagger.internal.codegen.SourceFiles.frameworkFieldUsages;
+import static dagger.internal.codegen.SourceFiles.frameworkTypeUsageStatement;
+import static dagger.internal.codegen.SourceFiles.generateBindingFieldsForDependencies;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.SourceFiles.parameterizedGeneratedTypeNameForBinding;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+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.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;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.Factory;
+import dagger.internal.Preconditions;
+import dagger.internal.codegen.InjectionMethods.InjectionSiteMethod;
+import dagger.internal.codegen.InjectionMethods.ProvisionMethod;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+
+/**
+ * Generates {@link Factory} implementations from {@link ProvisionBinding} instances for
+ * {@link Inject} constructors.
+ */
+final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding> {
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final CompilerOptions compilerOptions;
+
+ @Inject
+ FactoryGenerator(
+ Filer filer,
+ SourceVersion sourceVersion,
+ DaggerTypes types,
+ DaggerElements elements,
+ CompilerOptions compilerOptions) {
+ super(filer, elements, sourceVersion);
+ this.types = types;
+ this.elements = elements;
+ this.compilerOptions = compilerOptions;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ProvisionBinding binding) {
+ return generatedClassNameForBinding(binding);
+ }
+
+ @Override
+ Element originatingElement(ProvisionBinding binding) {
+ // we only create factories for bindings that have a binding element
+ return binding.bindingElement().get();
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, ProvisionBinding binding) {
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkArgument(!binding.unresolved().isPresent());
+ checkArgument(binding.bindingElement().isPresent());
+
+ return binding.factoryCreationStrategy().equals(DELEGATE)
+ ? Optional.empty()
+ : Optional.of(factoryBuilder(binding));
+ }
+
+ private TypeSpec.Builder factoryBuilder(ProvisionBinding binding) {
+ TypeSpec.Builder factoryBuilder =
+ classBuilder(nameGeneratedType(binding))
+ .addModifiers(PUBLIC, FINAL)
+ .addSuperinterface(factoryTypeName(binding))
+ .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
+
+ addConstructorAndFields(binding, factoryBuilder);
+ factoryBuilder.addMethod(getMethod(binding));
+ addCreateMethod(binding, factoryBuilder);
+
+ factoryBuilder.addMethod(
+ ProvisionMethod.create(binding, compilerOptions, elements).toMethodSpec());
+ gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
+
+ return factoryBuilder;
+ }
+
+ private void addConstructorAndFields(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
+ if (binding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)) {
+ return;
+ }
+ // TODO(user): Make the constructor private?
+ MethodSpec.Builder constructor = constructorBuilder().addModifiers(PUBLIC);
+ constructorParams(binding).forEach(
+ param -> {
+ constructor.addParameter(param).addStatement("this.$1N = $1N", param);
+ factoryBuilder.addField(
+ FieldSpec.builder(param.type, param.name, PRIVATE, FINAL).build());
+ });
+ factoryBuilder.addMethod(constructor.build());
+ }
+
+ private ImmutableList<ParameterSpec> constructorParams(ProvisionBinding binding) {
+ ImmutableList.Builder<ParameterSpec> params = ImmutableList.builder();
+ moduleParameter(binding).ifPresent(params::add);
+ frameworkFields(binding).values().forEach(field -> params.add(toParameter(field)));
+ return params.build();
+ }
+
+ private Optional<ParameterSpec> moduleParameter(ProvisionBinding binding) {
+ if (binding.requiresModuleInstance()) {
+ // TODO(user, dpb): Should this use contributingModule()?
+ TypeName type = TypeName.get(binding.bindingTypeElement().get().asType());
+ return Optional.of(ParameterSpec.builder(type, "module").build());
+ }
+ return Optional.empty();
+ }
+
+ private ImmutableMap<Key, FieldSpec> frameworkFields(ProvisionBinding binding) {
+ UniqueNameSet uniqueFieldNames = new UniqueNameSet();
+ // TODO(user, dpb): Add a test for the case when a Factory parameter is named "module".
+ if (binding.requiresModuleInstance()) {
+ uniqueFieldNames.claim("module");
+ }
+ return ImmutableMap.copyOf(
+ transformValues(
+ generateBindingFieldsForDependencies(binding),
+ field ->
+ FieldSpec.builder(
+ field.type(), uniqueFieldNames.getUniqueName(field.name()), PRIVATE, FINAL)
+ .build()));
+ }
+
+ private void addCreateMethod(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
+ // If constructing a factory for @Inject or @Provides bindings, we use a static create method
+ // so that generated components can avoid having to refer to the generic types
+ // of the factory. (Otherwise they may have visibility problems referring to the types.)
+ MethodSpec.Builder createMethodBuilder =
+ methodBuilder("create")
+ .addModifiers(PUBLIC, STATIC)
+ .returns(parameterizedGeneratedTypeNameForBinding(binding))
+ .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
+
+ switch (binding.factoryCreationStrategy()) {
+ case SINGLETON_INSTANCE:
+ FieldSpec.Builder instanceFieldBuilder =
+ FieldSpec.builder(nameGeneratedType(binding), "INSTANCE", PRIVATE, STATIC, FINAL)
+ .initializer("new $T()", nameGeneratedType(binding));
+
+ if (!bindingTypeElementTypeVariableNames(binding).isEmpty()) {
+ // If the factory has type parameters, ignore them in the field declaration & initializer
+ instanceFieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
+
+ createMethodBuilder.addAnnotation(suppressWarnings(UNCHECKED));
+ }
+ createMethodBuilder.addStatement("return INSTANCE");
+ factoryBuilder.addField(instanceFieldBuilder.build());
+ break;
+ case CLASS_CONSTRUCTOR:
+ List<ParameterSpec> params = constructorParams(binding);
+ createMethodBuilder.addParameters(params);
+ createMethodBuilder.addStatement(
+ "return new $T($L)",
+ parameterizedGeneratedTypeNameForBinding(binding),
+ makeParametersCodeBlock(Lists.transform(params, input -> CodeBlock.of("$N", input))));
+ break;
+ default:
+ throw new AssertionError();
+ }
+ factoryBuilder.addMethod(createMethodBuilder.build());
+ }
+
+ private MethodSpec getMethod(ProvisionBinding binding) {
+ TypeName providedTypeName = providedTypeName(binding);
+ MethodSpec.Builder getMethod =
+ methodBuilder("get")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(providedTypeName);
+
+ ImmutableMap<Key, FieldSpec> frameworkFields = frameworkFields(binding);
+ CodeBlock parametersCodeBlock =
+ makeParametersCodeBlock(
+ frameworkFieldUsages(binding.provisionDependencies(), frameworkFields).values());
+
+ if (binding.kind().equals(PROVISION)) {
+ binding
+ .nullableType()
+ .ifPresent(nullableType -> CodeBlocks.addAnnotation(getMethod, nullableType));
+ getMethod.addStatement(
+ "return $L",
+ ProvisionMethod.invoke(
+ binding,
+ request ->
+ frameworkTypeUsageStatement(
+ CodeBlock.of("$N", frameworkFields.get(request.key())), request.kind()),
+ nameGeneratedType(binding),
+ binding.requiresModuleInstance()
+ ? Optional.of(CodeBlock.of("module"))
+ : Optional.empty(),
+ compilerOptions,
+ elements));
+ } else if (!binding.injectionSites().isEmpty()) {
+ CodeBlock instance = CodeBlock.of("instance");
+ getMethod
+ .addStatement("$1T $2L = new $1T($3L)", providedTypeName, instance, parametersCodeBlock)
+ .addCode(
+ InjectionSiteMethod.invokeAll(
+ binding.injectionSites(),
+ nameGeneratedType(binding),
+ instance,
+ binding.key().type(),
+ types,
+ frameworkFieldUsages(binding.dependencies(), frameworkFields)::get,
+ elements))
+ .addStatement("return $L", instance);
+ } else {
+ getMethod.addStatement(
+ "return new $T($L)", providedTypeName, parametersCodeBlock);
+ }
+ return getMethod.build();
+ }
+
+ private static TypeName providedTypeName(ProvisionBinding binding) {
+ return TypeName.get(binding.contributedType());
+ }
+
+ private static TypeName factoryTypeName(ProvisionBinding binding) {
+ return factoryOf(providedTypeName(binding));
+ }
+
+ private static ParameterSpec toParameter(FieldSpec field) {
+ return ParameterSpec.builder(field.type, field.name).build();
+ }
+
+ /**
+ * Returns {@code Preconditions.checkNotNull(providesMethodInvocation)} with a message suitable
+ * for {@code @Provides} methods.
+ */
+ static CodeBlock checkNotNullProvidesMethod(CodeBlock providesMethodInvocation) {
+ return CodeBlock.of(
+ "$T.checkNotNull($L, $S)",
+ Preconditions.class,
+ providesMethodInvocation,
+ "Cannot return null from a non-@Nullable @Provides method");
+ }
+}
diff --git a/java/dagger/internal/codegen/FeatureStatus.java b/java/dagger/internal/codegen/FeatureStatus.java
new file mode 100644
index 0000000..9ff254e
--- /dev/null
+++ b/java/dagger/internal/codegen/FeatureStatus.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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;
+
+/** Allows options to control how features in component processing are enabled. */
+enum FeatureStatus {
+ ENABLED,
+ DISABLED;
+}
diff --git a/java/dagger/internal/codegen/Formatter.java b/java/dagger/internal/codegen/Formatter.java
new file mode 100644
index 0000000..53d4f9a
--- /dev/null
+++ b/java/dagger/internal/codegen/Formatter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkElementIndex;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+
+/**
+ * A formatter which transforms an instance of a particular type into a string
+ * representation.
+ *
+ * @param <T> the type of the object to be transformed.
+ */
+abstract class Formatter<T> implements Function<T, String> {
+
+ static final String INDENT = " ";
+ static final String DOUBLE_INDENT = INDENT + INDENT;
+ private static final int LIST_LIMIT = 10;
+
+ /**
+ * Performs the transformation of an object into a string representation.
+ */
+ public abstract String format(T object);
+
+ /**
+ * Performs the transformation of an object into a string representation in conformity with the
+ * {@link Function}{@code <T, String>} contract, delegating to {@link #format(Object)}.
+ *
+ * @deprecated Call {@link #format(Object)} instead. This method exists to make formatters easy to
+ * use when functions are required, but shouldn't be called directly.
+ */
+ @SuppressWarnings("javadoc")
+ @Deprecated
+ @Override
+ public final String apply(T object) {
+ return format(object);
+ }
+
+ /** Formats {@code items}, one per line. Stops after {@value #LIST_LIMIT} items. */
+ public void formatIndentedList(
+ StringBuilder builder, Iterable<? extends T> items, int indentLevel) {
+ for (T item : Iterables.limit(items, LIST_LIMIT)) {
+ String formatted = format(item);
+ if (formatted.isEmpty()) {
+ continue;
+ }
+ builder.append('\n');
+ appendIndent(builder, indentLevel);
+ builder.append(formatted);
+ }
+ int numberOfOtherItems = Iterables.size(items) - LIST_LIMIT;
+ if (numberOfOtherItems > 0) {
+ builder.append('\n');
+ appendIndent(builder, indentLevel);
+ builder.append("and ").append(numberOfOtherItems).append(" other");
+ }
+ if (numberOfOtherItems > 1) {
+ builder.append('s');
+ }
+ }
+
+ private void appendIndent(StringBuilder builder, int indentLevel) {
+ for (int i = 0; i < indentLevel; i++) {
+ builder.append(INDENT);
+ }
+ }
+
+ static String formatArgumentInList(int index, int size, CharSequence name) {
+ checkElementIndex(index, size);
+ StringBuilder builder = new StringBuilder();
+ if (index > 0) {
+ builder.append("…, ");
+ }
+ builder.append(name);
+ if (index < size - 1) {
+ builder.append(", …");
+ }
+ return builder.toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/ForwardingCompilerOptions.java b/java/dagger/internal/codegen/ForwardingCompilerOptions.java
new file mode 100644
index 0000000..4a1deda
--- /dev/null
+++ b/java/dagger/internal/codegen/ForwardingCompilerOptions.java
@@ -0,0 +1,122 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+/** A {@link CompilerOptions} object that delegates to another one. */
+class ForwardingCompilerOptions extends CompilerOptions {
+
+ private final CompilerOptions delegate;
+
+ ForwardingCompilerOptions(CompilerOptions delegate) {
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @Override
+ boolean usesProducers() {
+ return delegate.usesProducers();
+ }
+
+ @Override
+ boolean fastInit() {
+ return delegate.fastInit();
+ }
+
+ @Override
+ boolean formatGeneratedSource() {
+ return delegate.formatGeneratedSource();
+ }
+
+ @Override
+ boolean writeProducerNameInToken() {
+ return delegate.writeProducerNameInToken();
+ }
+
+ @Override
+ Diagnostic.Kind nullableValidationKind() {
+ return delegate.nullableValidationKind();
+ }
+
+ @Override
+ Diagnostic.Kind privateMemberValidationKind() {
+ return delegate.privateMemberValidationKind();
+ }
+
+ @Override
+ Diagnostic.Kind staticMemberValidationKind() {
+ return delegate.staticMemberValidationKind();
+ }
+
+ @Override
+ boolean ignorePrivateAndStaticInjectionForComponent() {
+ return delegate.ignorePrivateAndStaticInjectionForComponent();
+ }
+
+ @Override
+ ValidationType scopeCycleValidationType() {
+ return delegate.scopeCycleValidationType();
+ }
+
+ @Override
+ boolean warnIfInjectionFactoryNotGeneratedUpstream() {
+ return delegate.warnIfInjectionFactoryNotGeneratedUpstream();
+ }
+
+ @Override
+ boolean headerCompilation() {
+ return delegate.headerCompilation();
+ }
+
+ @Override
+ boolean aheadOfTimeSubcomponents() {
+ return delegate.aheadOfTimeSubcomponents();
+ }
+
+ @Override
+ boolean forceUseSerializedComponentImplementations() {
+ return delegate.forceUseSerializedComponentImplementations();
+ }
+
+ @Override
+ boolean emitModifiableMetadataAnnotations() {
+ return delegate.emitModifiableMetadataAnnotations();
+ }
+
+ @Override
+ boolean useGradleIncrementalProcessing() {
+ return delegate.useGradleIncrementalProcessing();
+ }
+
+ @Override
+ ValidationType fullBindingGraphValidationType(TypeElement element) {
+ return delegate.fullBindingGraphValidationType(element);
+ }
+
+ @Override
+ Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind() {
+ return delegate.moduleHasDifferentScopesDiagnosticKind();
+ }
+
+ @Override
+ ValidationType explicitBindingConflictsWithInjectValidationType() {
+ return delegate.explicitBindingConflictsWithInjectValidationType();
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkDependency.java b/java/dagger/internal/codegen/FrameworkDependency.java
new file mode 100644
index 0000000..feea7a0
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkDependency.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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 com.google.auto.value.AutoValue;
+import dagger.model.Key;
+
+/**
+ * The framework class and binding key for a resolved dependency of a binding. If a binding has
+ * several dependencies for a key, then only one instance of this class will represent them all.
+ *
+ * <p>In the following example, the binding {@code provideFoo()} has two dependency requests:
+ *
+ * <ol>
+ * <li>{@code Bar bar}
+ * <li>{@code Provider<Bar> barProvider}
+ * </ol>
+ *
+ * But they both can be satisfied with the same instance of {@code Provider<Bar>}. So one instance
+ * of {@code FrameworkDependency} will be used for both. Its {@link #key()} will be for {@code Bar},
+ * and its {@link #frameworkType()} will be {@link FrameworkType#PROVIDER}.
+ *
+ * <pre><code>
+ * {@literal @Provides} static Foo provideFoo(Bar bar, {@literal Provider<Bar>} barProvider) {
+ * return new Foo(…);
+ * }
+ * </code></pre>
+ */
+@AutoValue
+abstract class FrameworkDependency {
+
+ /** The fully-resolved key shared by all the dependency requests. */
+ abstract Key key();
+
+ /** The type of the framework dependency. */
+ abstract FrameworkType frameworkType();
+
+ /** The framework class to use for this dependency. */
+ final Class<?> frameworkClass() {
+ return frameworkType().frameworkClass();
+ }
+
+ /** Returns a new instance with the given key and type. */
+ static FrameworkDependency create(Key key, FrameworkType frameworkType) {
+ return new AutoValue_FrameworkDependency(key, frameworkType);
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkField.java b/java/dagger/internal/codegen/FrameworkField.java
new file mode 100644
index 0000000..de2ada0
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkField.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 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 dagger.model.BindingKind.MEMBERS_INJECTOR;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.CaseFormat;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import java.util.Optional;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor8;
+
+/**
+ * A value object that represents a field in the generated Component class.
+ *
+ * <p>Examples:
+ * <ul>
+ * <li>{@code Provider<String>}
+ * <li>{@code Producer<Widget>}
+ * <li>{@code Provider<Map<SomeMapKey, MapValue>>}.
+ * </ul>
+ */
+@AutoValue
+abstract class FrameworkField {
+
+ /**
+ * Creates a framework field.
+ *
+ * @param frameworkClassName the name of the framework class (e.g., {@link javax.inject.Provider})
+ * @param valueTypeName the name of the type parameter of the framework class (e.g., {@code Foo}
+ * for {@code Provider<Foo>}
+ * @param fieldName the name of the field
+ */
+ static FrameworkField create(
+ ClassName frameworkClassName, TypeName valueTypeName, String fieldName) {
+ String suffix = frameworkClassName.simpleName();
+ return new AutoValue_FrameworkField(
+ ParameterizedTypeName.get(frameworkClassName, valueTypeName),
+ fieldName.endsWith(suffix) ? fieldName : fieldName + suffix);
+ }
+
+ /**
+ * A framework field for a {@link ResolvedBindings}.
+ *
+ * @param frameworkClass if present, the field will use this framework class instead of the normal
+ * one for the bindings
+ */
+ static FrameworkField forResolvedBindings(
+ ResolvedBindings resolvedBindings, Optional<ClassName> frameworkClass) {
+ return create(
+ frameworkClass.orElse(
+ ClassName.get(
+ FrameworkType.forBindingType(resolvedBindings.bindingType()).frameworkClass())),
+ TypeName.get(fieldValueType(resolvedBindings)),
+ frameworkFieldName(resolvedBindings));
+ }
+
+ private static TypeMirror fieldValueType(ResolvedBindings resolvedBindings) {
+ return resolvedBindings.isMultibindingContribution()
+ ? resolvedBindings.contributionBinding().contributedType()
+ : resolvedBindings.key().type();
+ }
+
+ private static String frameworkFieldName(ResolvedBindings resolvedBindings) {
+ if (!resolvedBindings.contributionBindings().isEmpty()) {
+ ContributionBinding binding = resolvedBindings.contributionBinding();
+ if (binding.bindingElement().isPresent()) {
+ String name = BINDING_ELEMENT_NAME.visit(binding.bindingElement().get(), binding);
+ return binding.kind().equals(MEMBERS_INJECTOR)
+ ? name + "MembersInjector"
+ : name;
+ }
+ }
+ return KeyVariableNamer.name(resolvedBindings.key());
+ }
+
+ private static final ElementVisitor<String, Binding> BINDING_ELEMENT_NAME =
+ new ElementKindVisitor8<String, Binding>() {
+
+ @Override
+ protected String defaultAction(Element e, Binding p) {
+ throw new IllegalArgumentException("Unexpected binding " + p);
+ }
+
+ @Override
+ public String visitExecutableAsConstructor(ExecutableElement e, Binding p) {
+ return visit(e.getEnclosingElement(), p);
+ }
+
+ @Override
+ public String visitExecutableAsMethod(ExecutableElement e, Binding p) {
+ return e.getSimpleName().toString();
+ }
+
+ @Override
+ public String visitType(TypeElement e, Binding p) {
+ return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, e.getSimpleName().toString());
+ }
+
+ @Override
+ public String visitVariableAsParameter(VariableElement e, Binding p) {
+ return e.getSimpleName().toString();
+ }
+ };
+
+ abstract ParameterizedTypeName type();
+ abstract String name();
+}
diff --git a/java/dagger/internal/codegen/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
new file mode 100644
index 0000000..a3de083
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkFieldInitializer.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.ComponentImplementation.FieldSpecKind.FRAMEWORK_FIELD;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.DelegateFactory;
+import dagger.internal.codegen.javapoet.AnnotationSpecs;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.producers.internal.DelegateProducer;
+import java.util.Optional;
+
+/**
+ * An object that can initialize a framework-type component field for a binding. An instance should
+ * be created for each field.
+ */
+class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
+
+ /**
+ * An object that can determine the expression to use to assign to the component field for a
+ * binding.
+ */
+ interface FrameworkInstanceCreationExpression {
+ /** Returns the expression to use to assign to the component field for the binding. */
+ CodeBlock creationExpression();
+
+ /**
+ * Returns the framework class to use for the field, if different from the one implied by the
+ * binding. This implementation returns {@link Optional#empty()}.
+ */
+ default Optional<ClassName> alternativeFrameworkClass() {
+ return Optional.empty();
+ }
+
+ /**
+ * Returns {@code true} if instead of using {@link #creationExpression()} to create a framework
+ * instance, a case in {@link InnerSwitchingProviders} should be created for this binding.
+ */
+ // TODO(ronshapiro): perhaps this isn't the right approach. Instead of saying "Use
+ // SetFactory.EMPTY because you will only get 1 class for all types of bindings that use
+ // SetFactory", maybe we should still use an inner switching provider but the same switching
+ // provider index for all cases.
+ default boolean useInnerSwitchingProvider() {
+ return true;
+ }
+ }
+
+ private final ComponentImplementation componentImplementation;
+ private final ResolvedBindings resolvedBindings;
+ private final FrameworkInstanceCreationExpression frameworkInstanceCreationExpression;
+ private FieldSpec fieldSpec;
+ private InitializationState fieldInitializationState = InitializationState.UNINITIALIZED;
+
+ FrameworkFieldInitializer(
+ ComponentImplementation componentImplementation,
+ ResolvedBindings resolvedBindings,
+ FrameworkInstanceCreationExpression frameworkInstanceCreationExpression) {
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.resolvedBindings = checkNotNull(resolvedBindings);
+ this.frameworkInstanceCreationExpression = checkNotNull(frameworkInstanceCreationExpression);
+ }
+
+ /**
+ * Returns the {@link MemberSelect} for the framework field, and adds the field and its
+ * initialization code to the component if it's needed and not already added.
+ */
+ @Override
+ public final MemberSelect memberSelect() {
+ initializeField();
+ return MemberSelect.localField(componentImplementation.name(), checkNotNull(fieldSpec).name);
+ }
+
+ /** Adds the field and its initialization code to the component. */
+ private void initializeField() {
+ switch (fieldInitializationState) {
+ case UNINITIALIZED:
+ // Change our state in case we are recursively invoked via initializeBindingExpression
+ fieldInitializationState = InitializationState.INITIALIZING;
+ CodeBlock.Builder codeBuilder = CodeBlock.builder();
+ CodeBlock fieldInitialization = frameworkInstanceCreationExpression.creationExpression();
+ CodeBlock initCode = CodeBlock.of("this.$N = $L;", getOrCreateField(), fieldInitialization);
+
+ if (isReplacingSuperclassFrameworkInstance()
+ || fieldInitializationState == InitializationState.DELEGATED) {
+ codeBuilder.add(
+ "$T.setDelegate($N, $L);", delegateType(), fieldSpec, fieldInitialization);
+ } else {
+ codeBuilder.add(initCode);
+ }
+ componentImplementation.addInitialization(codeBuilder.build());
+
+ fieldInitializationState = InitializationState.INITIALIZED;
+ break;
+
+ case INITIALIZING:
+ // We were recursively invoked, so create a delegate factory instead
+ fieldInitializationState = InitializationState.DELEGATED;
+ componentImplementation.addInitialization(
+ CodeBlock.of("this.$N = new $T<>();", getOrCreateField(), delegateType()));
+ break;
+
+ case DELEGATED:
+ case INITIALIZED:
+ break;
+ }
+ }
+
+ /**
+ * Adds a field representing the resolved bindings, optionally forcing it to use a particular
+ * binding type (instead of the type the resolved bindings would typically use).
+ */
+ private FieldSpec getOrCreateField() {
+ if (fieldSpec != null) {
+ return fieldSpec;
+ }
+ boolean useRawType = !componentImplementation.isTypeAccessible(resolvedBindings.key().type());
+ FrameworkField contributionBindingField =
+ FrameworkField.forResolvedBindings(
+ resolvedBindings, frameworkInstanceCreationExpression.alternativeFrameworkClass());
+
+ TypeName fieldType =
+ useRawType ? contributionBindingField.type().rawType : contributionBindingField.type();
+
+ FieldSpec.Builder contributionField =
+ FieldSpec.builder(
+ fieldType, componentImplementation.getUniqueFieldName(contributionBindingField.name()));
+ contributionField.addModifiers(PRIVATE);
+ if (useRawType) {
+ contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES));
+ }
+
+ if (isReplacingSuperclassFrameworkInstance()) {
+ // If a binding is modified in a subclass, the framework instance will be replaced in the
+ // subclass implementation. The superclass framework instance initialization will run first,
+ // however, and may refer to the modifiable binding method returning this type's modified
+ // framework instance before it is initialized, so we use a delegate factory as a placeholder
+ // until it has properly been initialized.
+ contributionField.initializer("new $T<>()", delegateType());
+ }
+
+ fieldSpec = contributionField.build();
+ componentImplementation.addField(FRAMEWORK_FIELD, fieldSpec);
+
+ return fieldSpec;
+ }
+
+ /**
+ * Returns true if this framework field is replacing a superclass's implementation of the
+ * framework field.
+ */
+ private boolean isReplacingSuperclassFrameworkInstance() {
+ return componentImplementation
+ .superclassImplementation()
+ .flatMap(
+ superclassImplementation ->
+ // TODO(b/117833324): can we constrain this further?
+ superclassImplementation.getModifiableBindingMethod(
+ BindingRequest.bindingRequest(
+ resolvedBindings.key(),
+ isProvider() ? FrameworkType.PROVIDER : FrameworkType.PRODUCER_NODE)))
+ .isPresent();
+ }
+
+ private Class<?> delegateType() {
+ return isProvider() ? DelegateFactory.class : DelegateProducer.class;
+ }
+
+ private boolean isProvider() {
+ return resolvedBindings.bindingType().equals(BindingType.PROVISION)
+ && frameworkInstanceCreationExpression
+ .alternativeFrameworkClass()
+ .map(TypeNames.PROVIDER::equals)
+ .orElse(true);
+ }
+
+ /** Initialization state for a factory field. */
+ private enum InitializationState {
+ /** The field is {@code null}. */
+ UNINITIALIZED,
+
+ /**
+ * The field's dependencies are being set up. If the field is needed in this state, use a {@link
+ * DelegateFactory}.
+ */
+ INITIALIZING,
+
+ /**
+ * The field's dependencies are being set up, but the field can be used because it has already
+ * been set to a {@link DelegateFactory}.
+ */
+ DELEGATED,
+
+ /** The field is set to an undelegated factory. */
+ INITIALIZED;
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
new file mode 100644
index 0000000..6f62d66
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkInstanceBindingExpression.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/** A binding expression that uses a {@link FrameworkType} field. */
+abstract class FrameworkInstanceBindingExpression extends BindingExpression {
+ private final ResolvedBindings resolvedBindings;
+ private final FrameworkInstanceSupplier frameworkInstanceSupplier;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ FrameworkInstanceBindingExpression(
+ ResolvedBindings resolvedBindings,
+ FrameworkInstanceSupplier frameworkInstanceSupplier,
+ DaggerTypes types,
+ DaggerElements elements) {
+ this.resolvedBindings = checkNotNull(resolvedBindings);
+ this.frameworkInstanceSupplier = checkNotNull(frameworkInstanceSupplier);
+ this.types = checkNotNull(types);
+ this.elements = checkNotNull(elements);
+ }
+
+ /**
+ * The expression for the framework instance for this binding. The field will be {@link
+ * ComponentImplementation#addInitialization(CodeBlock) initialized} and {@link
+ * ComponentImplementation#addField(ComponentImplementation.FieldSpecKind, FieldSpec) added} to
+ * the component the first time this method is invoked.
+ */
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ MemberSelect memberSelect = frameworkInstanceSupplier.memberSelect();
+ TypeMirror contributedType = resolvedBindings.contributionBinding().contributedType();
+ TypeMirror expressionType =
+ isTypeAccessibleFrom(contributedType, requestingClass.packageName())
+ || isInlinedFactoryCreation(memberSelect)
+ ? types.wrapType(contributedType, frameworkType().frameworkClass())
+ : rawFrameworkType();
+ return Expression.create(expressionType, memberSelect.getExpressionFor(requestingClass));
+ }
+
+ /** Returns the framework type for the binding. */
+ protected abstract FrameworkType frameworkType();
+
+ /**
+ * Returns {@code true} if a factory is created inline each time it is requested. For example, in
+ * the initialization {@code this.fooProvider = Foo_Factory.create(Bar_Factory.create());}, {@code
+ * Bar_Factory} is considered to be inline.
+ *
+ * <p>This is used in {@link #getDependencyExpression(ClassName)} when determining the type of a
+ * factory. Normally if the {@link ContributionBinding#contributedType()} is not accessible from
+ * the component, the type of the expression will be a raw {@link javax.inject.Provider}. However,
+ * if the factory is created inline, even if contributed type is not accessible, javac will still
+ * be able to determine the type that is returned from the {@code Foo_Factory.create()} method.
+ */
+ private static boolean isInlinedFactoryCreation(MemberSelect memberSelect) {
+ return memberSelect.staticMember();
+ }
+
+ private DeclaredType rawFrameworkType() {
+ return types.getDeclaredType(elements.getTypeElement(frameworkType().frameworkClass()));
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkInstanceSupplier.java b/java/dagger/internal/codegen/FrameworkInstanceSupplier.java
new file mode 100644
index 0000000..4c45630
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkInstanceSupplier.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2017 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;
+
+/** An object that supplies a {@link MemberSelect} for a framework instance. */
+interface FrameworkInstanceSupplier {
+ /** Returns a {@link MemberSelect}, with possible side effects on the first call. */
+ MemberSelect memberSelect();
+}
diff --git a/java/dagger/internal/codegen/FrameworkType.java b/java/dagger/internal/codegen/FrameworkType.java
new file mode 100644
index 0000000..f4e3779
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkType.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static dagger.model.RequestKind.INSTANCE;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import dagger.Lazy;
+import dagger.internal.DoubleCheck;
+import dagger.internal.ProviderOfLazy;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.RequestKind;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.internal.Producers;
+import java.util.Optional;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/** One of the core types initialized as fields in a generated component. */
+enum FrameworkType {
+ /** A {@link Provider}. */
+ PROVIDER {
+ @Override
+ Class<?> frameworkClass() {
+ return Provider.class;
+ }
+
+ @Override
+ Optional<RequestKind> requestKind() {
+ return Optional.of(RequestKind.PROVIDER);
+ }
+
+ @Override
+ CodeBlock to(RequestKind requestKind, CodeBlock from) {
+ switch (requestKind) {
+ case INSTANCE:
+ return CodeBlock.of("$L.get()", from);
+
+ case LAZY:
+ return CodeBlock.of("$T.lazy($L)", DoubleCheck.class, from);
+
+ case PROVIDER:
+ return from;
+
+ case PROVIDER_OF_LAZY:
+ return CodeBlock.of("$T.create($L)", ProviderOfLazy.class, from);
+
+ case PRODUCER:
+ return CodeBlock.of("$T.producerFromProvider($L)", Producers.class, from);
+
+ case FUTURE:
+ return CodeBlock.of("$T.immediateFuture($L)", Futures.class, to(INSTANCE, from));
+
+ case PRODUCED:
+ return CodeBlock.of("$T.successful($L)", Produced.class, to(INSTANCE, from));
+
+ default:
+ throw new IllegalArgumentException(
+ String.format("Cannot request a %s from a %s", requestKind, this));
+ }
+ }
+
+ @Override
+ Expression to(RequestKind requestKind, Expression from, DaggerTypes types) {
+ CodeBlock codeBlock = to(requestKind, from.codeBlock());
+ switch (requestKind) {
+ case INSTANCE:
+ return Expression.create(types.unwrapTypeOrObject(from.type()), codeBlock);
+
+ case PROVIDER:
+ return from;
+
+ case PROVIDER_OF_LAZY:
+ TypeMirror lazyType = types.rewrapType(from.type(), Lazy.class);
+ return Expression.create(types.wrapType(lazyType, Provider.class), codeBlock);
+
+ case FUTURE:
+ return Expression.create(
+ types.rewrapType(from.type(), ListenableFuture.class), codeBlock);
+
+ default:
+ return Expression.create(
+ types.rewrapType(from.type(), RequestKinds.frameworkClass(requestKind)), codeBlock);
+ }
+ }
+ },
+
+ /** A {@link Producer}. */
+ PRODUCER_NODE {
+ @Override
+ Class<?> frameworkClass() {
+ // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
+ // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
+ // made to not implement Producer.
+ return Producer.class;
+ }
+
+ @Override
+ Optional<RequestKind> requestKind() {
+ return Optional.empty();
+ }
+
+ @Override
+ CodeBlock to(RequestKind requestKind, CodeBlock from) {
+ switch (requestKind) {
+ case FUTURE:
+ return CodeBlock.of("$L.get()", from);
+
+ case PRODUCER:
+ return from;
+
+ default:
+ throw new IllegalArgumentException(
+ String.format("Cannot request a %s from a %s", requestKind, this));
+ }
+ }
+
+ @Override
+ Expression to(RequestKind requestKind, Expression from, DaggerTypes types) {
+ switch (requestKind) {
+ case FUTURE:
+ return Expression.create(
+ types.rewrapType(from.type(), ListenableFuture.class),
+ to(requestKind, from.codeBlock()));
+
+ case PRODUCER:
+ return Expression.create(from.type(), to(requestKind, from.codeBlock()));
+
+ default:
+ throw new IllegalArgumentException(
+ String.format("Cannot request a %s from a %s", requestKind, this));
+ }
+ }
+ },
+ ;
+
+ /** Returns the framework type appropriate for fields for a given binding type. */
+ static FrameworkType forBindingType(BindingType bindingType) {
+ switch (bindingType) {
+ case PROVISION:
+ return PROVIDER;
+ case PRODUCTION:
+ return PRODUCER_NODE;
+ case MEMBERS_INJECTION:
+ }
+ throw new AssertionError(bindingType);
+ }
+
+ /** Returns the framework type that exactly matches the given request kind, if one exists. */
+ static Optional<FrameworkType> forRequestKind(RequestKind requestKind) {
+ switch (requestKind) {
+ case PROVIDER:
+ return Optional.of(FrameworkType.PROVIDER);
+ default:
+ return Optional.empty();
+ }
+ }
+
+ /** The class of fields of this type. */
+ abstract Class<?> frameworkClass();
+
+ /** Returns the {@link #frameworkClass()} parameterized with a type. */
+ ParameterizedTypeName frameworkClassOf(TypeName valueType) {
+ return ParameterizedTypeName.get(ClassName.get(frameworkClass()), valueType);
+ }
+
+ /** The request kind that an instance of this framework type can satisfy directly, if any. */
+ abstract Optional<RequestKind> requestKind();
+
+ /**
+ * Returns a {@link CodeBlock} that evaluates to a requested object given an expression that
+ * evaluates to an instance of this framework type.
+ *
+ * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
+ * satisfy
+ * @param from a {@link CodeBlock} that evaluates to an instance of this framework type
+ * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
+ * requestKind}
+ */
+ abstract CodeBlock to(RequestKind requestKind, CodeBlock from);
+
+ /**
+ * Returns an {@link Expression} that evaluates to a requested object given an expression that
+ * evaluates to an instance of this framework type.
+ *
+ * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
+ * satisfy
+ * @param from an expression that evaluates to an instance of this framework type
+ * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
+ * requestKind}
+ */
+ abstract Expression to(RequestKind requestKind, Expression from, DaggerTypes types);
+
+ @Override
+ public String toString() {
+ return UPPER_UNDERSCORE.to(UPPER_CAMEL, super.toString());
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkTypeMapper.java b/java/dagger/internal/codegen/FrameworkTypeMapper.java
new file mode 100644
index 0000000..7746692
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkTypeMapper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingType.PRODUCTION;
+import static java.util.stream.Collectors.toSet;
+
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import dagger.producers.Producer;
+import java.util.Set;
+import javax.inject.Provider;
+
+/**
+ * A mapper for associating a {@link RequestKind} to a {@link FrameworkType}, dependent on the type
+ * of code to be generated (e.g., for {@link Provider} or {@link Producer}).
+ */
+enum FrameworkTypeMapper {
+ FOR_PROVIDER() {
+ @Override
+ public FrameworkType getFrameworkType(RequestKind requestKind) {
+ switch (requestKind) {
+ case INSTANCE:
+ case PROVIDER:
+ case PROVIDER_OF_LAZY:
+ case LAZY:
+ return FrameworkType.PROVIDER;
+ case PRODUCED:
+ case PRODUCER:
+ throw new IllegalArgumentException(requestKind.toString());
+ default:
+ throw new AssertionError(requestKind);
+ }
+ }
+ },
+ FOR_PRODUCER() {
+ @Override
+ public FrameworkType getFrameworkType(RequestKind requestKind) {
+ switch (requestKind) {
+ case INSTANCE:
+ case PRODUCED:
+ case PRODUCER:
+ return FrameworkType.PRODUCER_NODE;
+ case PROVIDER:
+ case PROVIDER_OF_LAZY:
+ case LAZY:
+ return FrameworkType.PROVIDER;
+ default:
+ throw new AssertionError(requestKind);
+ }
+ }
+ };
+
+ static FrameworkTypeMapper forBindingType(BindingType bindingType) {
+ return bindingType.equals(PRODUCTION) ? FOR_PRODUCER : FOR_PROVIDER;
+ }
+
+ abstract FrameworkType getFrameworkType(RequestKind requestKind);
+
+ /**
+ * Returns the {@link FrameworkType} to use for a collection of requests of the same {@link Key}.
+ * This allows factories to only take a single argument for multiple requests of the same key.
+ */
+ FrameworkType getFrameworkType(Set<DependencyRequest> requests) {
+ Set<FrameworkType> frameworkTypes =
+ requests.stream().map(request -> getFrameworkType(request.kind())).collect(toSet());
+ return frameworkTypes.size() == 1 ? getOnlyElement(frameworkTypes) : FrameworkType.PROVIDER;
+ }
+}
diff --git a/java/dagger/internal/codegen/FrameworkTypes.java b/java/dagger/internal/codegen/FrameworkTypes.java
new file mode 100644
index 0000000..19d2eda
--- /dev/null
+++ b/java/dagger/internal/codegen/FrameworkTypes.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.MoreTypes.isType;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.Lazy;
+import dagger.MembersInjector;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import java.util.Set;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A collection of utility methods for dealing with Dagger framework types. A framework type is any
+ * type that the framework itself defines.
+ */
+final class FrameworkTypes {
+ private static final ImmutableSet<Class<?>> PROVISION_TYPES =
+ ImmutableSet.of(Provider.class, Lazy.class, MembersInjector.class);
+
+ // NOTE(beder): ListenableFuture is not considered a producer framework type because it is not
+ // defined by the framework, so we can't treat it specially in ordinary Dagger.
+ private static final ImmutableSet<Class<?>> PRODUCTION_TYPES =
+ ImmutableSet.of(Produced.class, Producer.class);
+
+ /** Returns true if the type represents a producer-related framework type. */
+ static boolean isProducerType(TypeMirror type) {
+ return isType(type) && typeIsOneOf(PRODUCTION_TYPES, type);
+ }
+
+ /** Returns true if the type represents a framework type. */
+ static boolean isFrameworkType(TypeMirror type) {
+ return isType(type)
+ && (typeIsOneOf(PROVISION_TYPES, type)
+ || typeIsOneOf(PRODUCTION_TYPES, type));
+ }
+
+ private static boolean typeIsOneOf(Set<Class<?>> classes, TypeMirror type) {
+ for (Class<?> clazz : classes) {
+ if (MoreTypes.isTypeOf(clazz, type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private FrameworkTypes() {}
+}
diff --git a/java/dagger/internal/codegen/GenerationCompilerOptions.java b/java/dagger/internal/codegen/GenerationCompilerOptions.java
new file mode 100644
index 0000000..1b14a7e
--- /dev/null
+++ b/java/dagger/internal/codegen/GenerationCompilerOptions.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+/**
+ * A {@link Qualifier} for bindings associated with the serialization/deserialization of {@link
+ * dagger.internal.GenerationOptions}.
+ */
+@Retention(RUNTIME)
+@Qualifier
+@interface GenerationCompilerOptions {}
diff --git a/java/dagger/internal/codegen/GenerationOptionsModule.java b/java/dagger/internal/codegen/GenerationOptionsModule.java
new file mode 100644
index 0000000..aa3c461
--- /dev/null
+++ b/java/dagger/internal/codegen/GenerationOptionsModule.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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 dagger.Module;
+import dagger.Provides;
+import dagger.internal.GenerationOptions;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.Optional;
+
+/** Adds bindings for serializing and rereading {@link GenerationOptions}. */
+@Module
+interface GenerationOptionsModule {
+ @Provides
+ @PerComponentImplementation
+ @GenerationCompilerOptions
+ static CompilerOptions generationOptions(
+ CompilerOptions defaultOptions,
+ ComponentImplementation componentImplementation,
+ DaggerElements elements) {
+ // Avoid looking up types that don't exist. Performance improves for large components.
+ if (!defaultOptions.aheadOfTimeSubcomponents()) {
+ return defaultOptions;
+ }
+ // Inspect the base implementation for the @GenerationOptions annotation. Even if
+ // componentImplementation is the base implementation, inspect it for the case where we are
+ // recomputing the ComponentImplementation from a previous compilation.
+ // TODO(b/117833324): consider adding a method that returns baseImplementation.orElse(this).
+ // The current state of the world is a little confusing and maybe not intuitive: the base
+ // implementation has no base implementation, but it _is_ a base implementation.
+ return Optional.of(componentImplementation.baseImplementation().orElse(componentImplementation))
+ .map(baseImplementation -> elements.getTypeElement(baseImplementation.name()))
+ // If this returns null, the type has not been generated yet and Optional will switch to an
+ // empty state. This means that we're currently generating componentImplementation, or that
+ // the base implementation is being generated in this round, and thus the options passed to
+ // this compilation are applicable
+ .map(typeElement -> typeElement.getAnnotation(GenerationOptions.class))
+ .map(defaultOptions::withGenerationOptions)
+ .orElse(defaultOptions);
+ }
+}
diff --git a/java/dagger/internal/codegen/GwtCompatibility.java b/java/dagger/internal/codegen/GwtCompatibility.java
new file mode 100644
index 0000000..34d8f6d
--- /dev/null
+++ b/java/dagger/internal/codegen/GwtCompatibility.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.squareup.javapoet.AnnotationSpec;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Name;
+
+final class GwtCompatibility {
+
+ /**
+ * Returns a {@code @GwtIncompatible} annotation that is applied to {@code binding}'s {@link
+ * Binding#bindingElement()} or any enclosing type.
+ */
+ static Optional<AnnotationSpec> gwtIncompatibleAnnotation(Binding binding) {
+ checkArgument(binding.bindingElement().isPresent());
+ Element element = binding.bindingElement().get();
+ while (element != null) {
+ Optional<AnnotationSpec> gwtIncompatible =
+ element
+ .getAnnotationMirrors()
+ .stream()
+ .filter(annotation -> isGwtIncompatible(annotation))
+ .map(AnnotationSpec::get)
+ .findFirst();
+ if (gwtIncompatible.isPresent()) {
+ return gwtIncompatible;
+ }
+ element = element.getEnclosingElement();
+ }
+ return Optional.empty();
+ }
+
+ private static boolean isGwtIncompatible(AnnotationMirror annotation) {
+ Name simpleName = annotation.getAnnotationType().asElement().getSimpleName();
+ return simpleName.contentEquals("GwtIncompatible");
+ }
+}
diff --git a/java/dagger/internal/codegen/HjarSourceFileGenerator.java b/java/dagger/internal/codegen/HjarSourceFileGenerator.java
new file mode 100644
index 0000000..5c36322
--- /dev/null
+++ b/java/dagger/internal/codegen/HjarSourceFileGenerator.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 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.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
+import java.util.Optional;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+
+/**
+ * A source file generator that only writes the relevant code necessary for Bazel to create a
+ * correct header (ABI) jar.
+ */
+final class HjarSourceFileGenerator<T> extends SourceFileGenerator<T> {
+ private final SourceFileGenerator<T> delegate;
+
+ private HjarSourceFileGenerator(SourceFileGenerator<T> delegate) {
+ super(delegate);
+ this.delegate = delegate;
+ }
+
+ static <T> SourceFileGenerator<T> wrap(SourceFileGenerator<T> delegate) {
+ return new HjarSourceFileGenerator<>(delegate);
+ }
+
+ @Override
+ ClassName nameGeneratedType(T input) {
+ return delegate.nameGeneratedType(input);
+ }
+
+ @Override
+ Element originatingElement(T input) {
+ return delegate.originatingElement(input);
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, T input) {
+ return delegate
+ .write(generatedTypeName, input)
+ .map(completeType -> skeletonType(completeType.build()));
+ }
+
+ private TypeSpec.Builder skeletonType(TypeSpec completeType) {
+ TypeSpec.Builder skeleton =
+ classBuilder(completeType.name)
+ .addSuperinterfaces(completeType.superinterfaces)
+ .addTypeVariables(completeType.typeVariables)
+ .addModifiers(completeType.modifiers.toArray(new Modifier[0]))
+ .addAnnotations(completeType.annotations);
+
+ if (!completeType.superclass.equals(ClassName.OBJECT)) {
+ skeleton.superclass(completeType.superclass);
+ }
+
+ completeType.methodSpecs.stream()
+ .filter(method -> !method.modifiers.contains(PRIVATE) || method.isConstructor())
+ .map(this::skeletonMethod)
+ .forEach(skeleton::addMethod);
+
+ completeType.fieldSpecs.stream()
+ .filter(field -> !field.modifiers.contains(PRIVATE))
+ .map(this::skeletonField)
+ .forEach(skeleton::addField);
+
+ completeType.typeSpecs.stream()
+ .map(type -> skeletonType(type).build())
+ .forEach(skeleton::addType);
+
+ return skeleton;
+ }
+
+ private MethodSpec skeletonMethod(MethodSpec completeMethod) {
+ MethodSpec.Builder skeleton =
+ completeMethod.isConstructor()
+ ? constructorBuilder()
+ : methodBuilder(completeMethod.name).returns(completeMethod.returnType);
+
+ if (completeMethod.isConstructor()) {
+ // Code in Turbine must (for technical reasons in javac) have a valid super() call for
+ // constructors, otherwise javac will bark, and Turbine has no way to avoid this. So we retain
+ // constructor method bodies if they do exist
+ skeleton.addCode(completeMethod.code);
+ }
+
+ return skeleton
+ .addModifiers(completeMethod.modifiers)
+ .addTypeVariables(completeMethod.typeVariables)
+ .addParameters(completeMethod.parameters)
+ .addExceptions(completeMethod.exceptions)
+ .varargs(completeMethod.varargs)
+ .addAnnotations(completeMethod.annotations)
+ .build();
+ }
+
+ private FieldSpec skeletonField(FieldSpec completeField) {
+ return FieldSpec.builder(
+ completeField.type,
+ completeField.name,
+ completeField.modifiers.toArray(new Modifier[0]))
+ .addAnnotations(completeField.annotations)
+ .build();
+ }
+}
diff --git a/java/dagger/internal/codegen/ImmediateFutureBindingExpression.java b/java/dagger/internal/codegen/ImmediateFutureBindingExpression.java
new file mode 100644
index 0000000..69b107c
--- /dev/null
+++ b/java/dagger/internal/codegen/ImmediateFutureBindingExpression.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import javax.lang.model.SourceVersion;
+
+final class ImmediateFutureBindingExpression extends BindingExpression {
+
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+ private final SourceVersion sourceVersion;
+ private final Key key;
+
+ ImmediateFutureBindingExpression(
+ ResolvedBindings resolvedBindings,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types,
+ SourceVersion sourceVersion) {
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ this.types = checkNotNull(types);
+ this.sourceVersion = checkNotNull(sourceVersion);
+ this.key = resolvedBindings.key();
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return Expression.create(
+ types.wrapType(key.type(), ListenableFuture.class),
+ CodeBlock.of("$T.immediateFuture($L)", Futures.class, instanceExpression(requestingClass)));
+ }
+
+ private CodeBlock instanceExpression(ClassName requestingClass) {
+ Expression expression =
+ componentBindingExpressions.getDependencyExpression(
+ bindingRequest(key, RequestKind.INSTANCE), requestingClass);
+ if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
+ // Java 7 type inference is not as strong as in Java 8, and therefore some generated code must
+ // cast.
+ //
+ // For example, javac7 cannot detect that Futures.immediateFuture(ImmutableSet.of("T"))
+ // can safely be assigned to ListenableFuture<Set<T>>.
+ if (!types.isSameType(expression.type(), key.type())) {
+ return CodeBlock.of(
+ "($T) $L", types.accessibleType(key.type(), requestingClass), expression.codeBlock());
+ }
+ }
+ return expression.codeBlock();
+ }
+}
diff --git a/java/dagger/internal/codegen/InaccessibleMapKeyProxyGenerator.java b/java/dagger/internal/codegen/InaccessibleMapKeyProxyGenerator.java
new file mode 100644
index 0000000..19c4d19
--- /dev/null
+++ b/java/dagger/internal/codegen/InaccessibleMapKeyProxyGenerator.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+
+/**
+ * Generates a class that exposes a non-{@code public} {@link
+ * ContributionBinding#mapKeyAnnotation()} @MapKey} annotation.
+ */
+final class InaccessibleMapKeyProxyGenerator extends SourceFileGenerator<ContributionBinding> {
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ @Inject
+ InaccessibleMapKeyProxyGenerator(
+ Filer filer, DaggerTypes types, DaggerElements elements, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ this.types = types;
+ this.elements = elements;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ContributionBinding binding) {
+ return MapKeys.mapKeyProxyClassName(binding);
+ }
+
+ @Override
+ Element originatingElement(ContributionBinding binding) {
+ // a map key is only ever present on bindings that have a binding element
+ return binding.bindingElement().get();
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedName, ContributionBinding binding) {
+ return MapKeys.mapKeyFactoryMethod(binding, types, elements)
+ .map(
+ method ->
+ classBuilder(generatedName)
+ .addModifiers(PUBLIC, FINAL)
+ .addMethod(constructorBuilder().addModifiers(PRIVATE).build())
+ .addMethod(method));
+ }
+}
diff --git a/java/dagger/internal/codegen/IncompatiblyScopedBindingsValidator.java b/java/dagger/internal/codegen/IncompatiblyScopedBindingsValidator.java
new file mode 100644
index 0000000..d649e46
--- /dev/null
+++ b/java/dagger/internal/codegen/IncompatiblyScopedBindingsValidator.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.Formatter.INDENT;
+import static dagger.internal.codegen.Scopes.getReadableSource;
+import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
+import static dagger.model.BindingKind.INJECTION;
+import static java.util.stream.Collectors.joining;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimaps;
+import dagger.model.Binding;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import java.util.Optional;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.tools.Diagnostic;
+
+/**
+ * Reports an error for any component that uses bindings with scopes that are not assigned to the
+ * component.
+ */
+final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
+
+ private final MethodSignatureFormatter methodSignatureFormatter;
+ private final CompilerOptions compilerOptions;
+
+ @Inject
+ IncompatiblyScopedBindingsValidator(
+ MethodSignatureFormatter methodSignatureFormatter, CompilerOptions compilerOptions) {
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ this.compilerOptions = compilerOptions;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/IncompatiblyScopedBindings";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ ImmutableSetMultimap.Builder<ComponentNode, dagger.model.Binding> incompatibleBindings =
+ ImmutableSetMultimap.builder();
+ for (dagger.model.Binding binding : bindingGraph.bindings()) {
+ binding
+ .scope()
+ .filter(scope -> !scope.isReusable())
+ .ifPresent(
+ scope -> {
+ ComponentNode componentNode =
+ bindingGraph.componentNode(binding.componentPath()).get();
+ if (!componentNode.scopes().contains(scope)) {
+ // @Inject bindings in module or subcomponent binding graphs will appear at the
+ // properly scoped ancestor component, so ignore them here.
+ if (binding.kind().equals(INJECTION)
+ && (bindingGraph.rootComponentNode().isSubcomponent()
+ || !bindingGraph.rootComponentNode().isRealComponent())) {
+ return;
+ }
+ incompatibleBindings.put(componentNode, binding);
+ }
+ });
+ }
+ Multimaps.asMap(incompatibleBindings.build())
+ .forEach((componentNode, bindings) -> report(componentNode, bindings, diagnosticReporter));
+ }
+
+ private void report(
+ ComponentNode componentNode,
+ Set<Binding> bindings,
+ DiagnosticReporter diagnosticReporter) {
+ Diagnostic.Kind diagnosticKind = ERROR;
+ StringBuilder message =
+ new StringBuilder(componentNode.componentPath().currentComponent().getQualifiedName());
+
+ if (!componentNode.isRealComponent()) {
+ // If the "component" is really a module, it will have no scopes attached. We want to report
+ // if there is more than one scope in that component.
+ if (bindings.stream().map(Binding::scope).map(Optional::get).distinct().count() <= 1) {
+ return;
+ }
+ message.append(" contains bindings with different scopes:");
+ diagnosticKind = compilerOptions.moduleHasDifferentScopesDiagnosticKind();
+ } else if (componentNode.scopes().isEmpty()) {
+ message.append(" (unscoped) may not reference scoped bindings:");
+ } else {
+ message
+ .append(" scoped with ")
+ .append(
+ componentNode.scopes().stream().map(Scopes::getReadableSource).collect(joining(" ")))
+ .append(" may not reference bindings with different scopes:");
+ }
+
+ // TODO(ronshapiro): Should we group by scope?
+ for (Binding binding : bindings) {
+ message.append('\n').append(INDENT);
+
+ // TODO(dpb): Use BindingDeclarationFormatter.
+ // But that doesn't print scopes for @Inject-constructed types.
+ switch (binding.kind()) {
+ case DELEGATE:
+ case PROVISION:
+ message.append(
+ methodSignatureFormatter.format(
+ MoreElements.asExecutable(binding.bindingElement().get())));
+ break;
+
+ case INJECTION:
+ message
+ .append(getReadableSource(binding.scope().get()))
+ .append(" class ")
+ .append(
+ closestEnclosingTypeElement(binding.bindingElement().get()).getQualifiedName());
+ break;
+
+ default:
+ throw new AssertionError(binding);
+ }
+ }
+ diagnosticReporter.reportComponent(diagnosticKind, componentNode, message.toString());
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectBindingRegistry.java b/java/dagger/internal/codegen/InjectBindingRegistry.java
new file mode 100644
index 0000000..2840d75
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectBindingRegistry.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 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 com.google.errorprone.annotations.CanIgnoreReturnValue;
+import dagger.Component;
+import dagger.Provides;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Maintains the collection of provision bindings from {@link Inject} constructors and members
+ * injection bindings from {@link Inject} fields and methods known to the annotation processor. Note
+ * that this registry <b>does not</b> handle any explicit bindings (those from {@link Provides}
+ * methods, {@link Component} dependencies, etc.).
+ */
+interface InjectBindingRegistry {
+ /**
+ * Returns a {@link ProvisionBinding} for {@code key}. If none has been registered yet, registers
+ * one.
+ */
+ Optional<ProvisionBinding> getOrFindProvisionBinding(Key key);
+
+ /**
+ * Returns a {@link MembersInjectionBinding} for {@code key}. If none has been registered yet,
+ * registers one, along with all necessary members injection bindings for superclasses.
+ */
+ Optional<MembersInjectionBinding> getOrFindMembersInjectionBinding(Key key);
+
+ /**
+ * Returns a {@link ProvisionBinding} for a {@link dagger.MembersInjector} of {@code key}. If none
+ * has been registered yet, registers one.
+ */
+ Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key);
+
+ @CanIgnoreReturnValue
+ Optional<ProvisionBinding> tryRegisterConstructor(ExecutableElement constructorElement);
+
+ @CanIgnoreReturnValue
+ Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(TypeElement typeElement);
+
+ /**
+ * This method ensures that sources for all registered {@link Binding bindings} (either explicitly
+ * or implicitly via {@link #getOrFindMembersInjectionBinding} or {@link
+ * #getOrFindProvisionBinding}) are generated.
+ */
+ void generateSourcesForRequiredBindings(
+ SourceFileGenerator<ProvisionBinding> factoryGenerator,
+ SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator)
+ throws SourceFileGenerationException;
+}
diff --git a/java/dagger/internal/codegen/InjectBindingRegistryImpl.java b/java/dagger/internal/codegen/InjectBindingRegistryImpl.java
new file mode 100644
index 0000000..45dc391
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectBindingRegistryImpl.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.InjectionAnnotations.injectedConstructors;
+import static dagger.internal.codegen.Keys.isValidImplicitProvisionKey;
+import static dagger.internal.codegen.Keys.isValidMembersInjectionKey;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.squareup.javapoet.ClassName;
+import dagger.Component;
+import dagger.MembersInjector;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+/**
+ * Maintains the collection of provision bindings from {@link Inject} constructors and members
+ * injection bindings from {@link Inject} fields and methods known to the annotation processor.
+ * Note that this registry <b>does not</b> handle any explicit bindings (those from {@link Provides}
+ * methods, {@link Component} dependencies, etc.).
+ */
+@Singleton
+final class InjectBindingRegistryImpl implements InjectBindingRegistry {
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+ private final Messager messager;
+ private final InjectValidator injectValidator;
+ private final InjectValidator injectValidatorWhenGeneratingCode;
+ private final KeyFactory keyFactory;
+ private final BindingFactory bindingFactory;
+ private final CompilerOptions compilerOptions;
+
+ final class BindingsCollection<B extends Binding> {
+ private final Class<?> factoryClass;
+ private final Map<Key, B> bindingsByKey = Maps.newLinkedHashMap();
+ private final Deque<B> bindingsRequiringGeneration = new ArrayDeque<>();
+ private final Set<Key> materializedBindingKeys = Sets.newLinkedHashSet();
+
+ BindingsCollection(Class<?> factoryClass) {
+ this.factoryClass = factoryClass;
+ }
+
+ void generateBindings(SourceFileGenerator<B> generator) throws SourceFileGenerationException {
+ for (B binding = bindingsRequiringGeneration.poll();
+ binding != null;
+ binding = bindingsRequiringGeneration.poll()) {
+ checkState(!binding.unresolved().isPresent());
+ if (injectValidatorWhenGeneratingCode.isValidType(binding.key().type())) {
+ generator.generate(binding);
+ }
+ materializedBindingKeys.add(binding.key());
+ }
+ // Because Elements instantiated across processing rounds are not guaranteed to be equals() to
+ // the logically same element, clear the cache after generating
+ bindingsByKey.clear();
+ }
+
+ /** Returns a previously cached binding. */
+ B getBinding(Key key) {
+ return bindingsByKey.get(key);
+ }
+
+ /** Caches the binding and generates it if it needs generation. */
+ void tryRegisterBinding(B binding, boolean warnIfNotAlreadyGenerated) {
+ tryToCacheBinding(binding);
+ tryToGenerateBinding(binding, warnIfNotAlreadyGenerated);
+ }
+
+ /**
+ * Tries to generate a binding, not generating if it already is generated. For resolved
+ * bindings, this will try to generate the unresolved version of the binding.
+ */
+ void tryToGenerateBinding(B binding, boolean warnIfNotAlreadyGenerated) {
+ if (shouldGenerateBinding(binding, generatedClassNameForBinding(binding))) {
+ bindingsRequiringGeneration.offer(binding);
+ if (compilerOptions.warnIfInjectionFactoryNotGeneratedUpstream()
+ && warnIfNotAlreadyGenerated) {
+ messager.printMessage(
+ Kind.NOTE,
+ String.format(
+ "Generating a %s for %s. "
+ + "Prefer to run the dagger processor over that class instead.",
+ factoryClass.getSimpleName(),
+ types.erasure(binding.key().type()))); // erasure to strip <T> from msgs.
+ }
+ }
+ }
+
+ /** Returns true if the binding needs to be generated. */
+ private boolean shouldGenerateBinding(B binding, ClassName factoryName) {
+ return !binding.unresolved().isPresent()
+ && !materializedBindingKeys.contains(binding.key())
+ && !bindingsRequiringGeneration.contains(binding)
+ && elements.getTypeElement(factoryName) == null;
+ }
+
+ /** Caches the binding for future lookups by key. */
+ private void tryToCacheBinding(B binding) {
+ // We only cache resolved bindings or unresolved bindings w/o type arguments.
+ // Unresolved bindings w/ type arguments aren't valid for the object graph.
+ if (binding.unresolved().isPresent()
+ || binding.bindingTypeElement().get().getTypeParameters().isEmpty()) {
+ Key key = binding.key();
+ Binding previousValue = bindingsByKey.put(key, binding);
+ checkState(previousValue == null || binding.equals(previousValue),
+ "couldn't register %s. %s was already registered for %s",
+ binding, previousValue, key);
+ }
+ }
+ }
+
+ private final BindingsCollection<ProvisionBinding> provisionBindings =
+ new BindingsCollection<>(Provider.class);
+ private final BindingsCollection<MembersInjectionBinding> membersInjectionBindings =
+ new BindingsCollection<>(MembersInjector.class);
+
+ @Inject
+ InjectBindingRegistryImpl(
+ DaggerElements elements,
+ DaggerTypes types,
+ Messager messager,
+ InjectValidator injectValidator,
+ KeyFactory keyFactory,
+ BindingFactory bindingFactory,
+ CompilerOptions compilerOptions) {
+ this.elements = elements;
+ this.types = types;
+ this.messager = messager;
+ this.injectValidator = injectValidator;
+ this.injectValidatorWhenGeneratingCode = injectValidator.whenGeneratingCode();
+ this.keyFactory = keyFactory;
+ this.bindingFactory = bindingFactory;
+ this.compilerOptions = compilerOptions;
+ }
+
+ // TODO(dpb): make the SourceFileGenerators fields so they don't have to be passed in
+ @Override
+ public void generateSourcesForRequiredBindings(
+ SourceFileGenerator<ProvisionBinding> factoryGenerator,
+ SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator)
+ throws SourceFileGenerationException {
+ provisionBindings.generateBindings(factoryGenerator);
+ membersInjectionBindings.generateBindings(membersInjectorGenerator);
+ }
+
+ /**
+ * Registers the binding for generation and later lookup. If the binding is resolved, we also
+ * attempt to register an unresolved version of it.
+ */
+ private void registerBinding(ProvisionBinding binding, boolean warnIfNotAlreadyGenerated) {
+ provisionBindings.tryRegisterBinding(binding, warnIfNotAlreadyGenerated);
+ if (binding.unresolved().isPresent()) {
+ provisionBindings.tryToGenerateBinding(binding.unresolved().get(), warnIfNotAlreadyGenerated);
+ }
+ }
+
+ /**
+ * Registers the binding for generation and later lookup. If the binding is resolved, we also
+ * attempt to register an unresolved version of it.
+ */
+ private void registerBinding(MembersInjectionBinding binding, boolean warnIfNotAlreadyGenerated) {
+ /*
+ * We generate MembersInjector classes for types with @Inject constructors only if they have any
+ * injection sites.
+ *
+ * We generate MembersInjector classes for types without @Inject constructors only if they have
+ * local (non-inherited) injection sites.
+ *
+ * Warn only when registering bindings post-hoc for those types.
+ */
+ warnIfNotAlreadyGenerated =
+ warnIfNotAlreadyGenerated
+ && (!injectedConstructors(binding.membersInjectedType()).isEmpty()
+ ? !binding.injectionSites().isEmpty()
+ : binding.hasLocalInjectionSites());
+ membersInjectionBindings.tryRegisterBinding(binding, warnIfNotAlreadyGenerated);
+ if (binding.unresolved().isPresent()) {
+ membersInjectionBindings.tryToGenerateBinding(
+ binding.unresolved().get(), warnIfNotAlreadyGenerated);
+ }
+ }
+
+ @Override
+ public Optional<ProvisionBinding> tryRegisterConstructor(ExecutableElement constructorElement) {
+ return tryRegisterConstructor(constructorElement, Optional.empty(), false);
+ }
+
+ @CanIgnoreReturnValue
+ private Optional<ProvisionBinding> tryRegisterConstructor(
+ ExecutableElement constructorElement,
+ Optional<TypeMirror> resolvedType,
+ boolean warnIfNotAlreadyGenerated) {
+ TypeElement typeElement = MoreElements.asType(constructorElement.getEnclosingElement());
+ DeclaredType type = MoreTypes.asDeclared(typeElement.asType());
+ Key key = keyFactory.forInjectConstructorWithResolvedType(type);
+ ProvisionBinding cachedBinding = provisionBindings.getBinding(key);
+ if (cachedBinding != null) {
+ return Optional.of(cachedBinding);
+ }
+
+ ValidationReport<TypeElement> report = injectValidator.validateConstructor(constructorElement);
+ report.printMessagesTo(messager);
+ if (report.isClean()) {
+ ProvisionBinding binding = bindingFactory.injectionBinding(constructorElement, resolvedType);
+ registerBinding(binding, warnIfNotAlreadyGenerated);
+ if (!binding.injectionSites().isEmpty()) {
+ tryRegisterMembersInjectedType(typeElement, resolvedType, warnIfNotAlreadyGenerated);
+ }
+ return Optional.of(binding);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(TypeElement typeElement) {
+ return tryRegisterMembersInjectedType(typeElement, Optional.empty(), false);
+ }
+
+ @CanIgnoreReturnValue
+ private Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(
+ TypeElement typeElement,
+ Optional<TypeMirror> resolvedType,
+ boolean warnIfNotAlreadyGenerated) {
+ DeclaredType type = MoreTypes.asDeclared(typeElement.asType());
+ Key key = keyFactory.forInjectConstructorWithResolvedType(type);
+ MembersInjectionBinding cachedBinding = membersInjectionBindings.getBinding(key);
+ if (cachedBinding != null) {
+ return Optional.of(cachedBinding);
+ }
+
+ ValidationReport<TypeElement> report =
+ injectValidator.validateMembersInjectionType(typeElement);
+ report.printMessagesTo(messager);
+ if (report.isClean()) {
+ MembersInjectionBinding binding = bindingFactory.membersInjectionBinding(type, resolvedType);
+ registerBinding(binding, warnIfNotAlreadyGenerated);
+ for (Optional<DeclaredType> supertype = types.nonObjectSuperclass(type);
+ supertype.isPresent();
+ supertype = types.nonObjectSuperclass(supertype.get())) {
+ getOrFindMembersInjectionBinding(keyFactory.forMembersInjectedType(supertype.get()));
+ }
+ return Optional.of(binding);
+ }
+ return Optional.empty();
+ }
+
+ @CanIgnoreReturnValue
+ @Override
+ public Optional<ProvisionBinding> getOrFindProvisionBinding(Key key) {
+ checkNotNull(key);
+ if (!isValidImplicitProvisionKey(key, types)) {
+ return Optional.empty();
+ }
+ ProvisionBinding binding = provisionBindings.getBinding(key);
+ if (binding != null) {
+ return Optional.of(binding);
+ }
+
+ // ok, let's see if we can find an @Inject constructor
+ TypeElement element = MoreElements.asType(types.asElement(key.type()));
+ ImmutableSet<ExecutableElement> injectConstructors = injectedConstructors(element);
+ switch (injectConstructors.size()) {
+ case 0:
+ // No constructor found.
+ return Optional.empty();
+ case 1:
+ return tryRegisterConstructor(
+ Iterables.getOnlyElement(injectConstructors), Optional.of(key.type()), true);
+ default:
+ throw new IllegalStateException("Found multiple @Inject constructors: "
+ + injectConstructors);
+ }
+ }
+
+ @CanIgnoreReturnValue
+ @Override
+ public Optional<MembersInjectionBinding> getOrFindMembersInjectionBinding(Key key) {
+ checkNotNull(key);
+ // TODO(gak): is checking the kind enough?
+ checkArgument(isValidMembersInjectionKey(key));
+ MembersInjectionBinding binding = membersInjectionBindings.getBinding(key);
+ if (binding != null) {
+ return Optional.of(binding);
+ }
+ Optional<MembersInjectionBinding> newBinding =
+ tryRegisterMembersInjectedType(
+ MoreTypes.asTypeElement(key.type()), Optional.of(key.type()), true);
+ return newBinding;
+ }
+
+ @Override
+ public Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key) {
+ if (!isValidMembersInjectionKey(key)) {
+ return Optional.empty();
+ }
+ Key membersInjectionKey = keyFactory.forMembersInjectedType(types.unwrapType(key.type()));
+ return getOrFindMembersInjectionBinding(membersInjectionKey)
+ .map(binding -> bindingFactory.membersInjectorBinding(key, binding));
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectBindingRegistryModule.java b/java/dagger/internal/codegen/InjectBindingRegistryModule.java
new file mode 100644
index 0000000..4563362
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectBindingRegistryModule.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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 dagger.Binds;
+import dagger.Module;
+
+@Module
+interface InjectBindingRegistryModule {
+ @Binds
+ InjectBindingRegistry injectBindingRegistry(InjectBindingRegistryImpl impl);
+}
diff --git a/java/dagger/internal/codegen/InjectBindingValidator.java b/java/dagger/internal/codegen/InjectBindingValidator.java
new file mode 100644
index 0000000..183d162
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectBindingValidator.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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 dagger.model.BindingKind.INJECTION;
+
+import com.google.auto.common.MoreTypes;
+import dagger.internal.codegen.ValidationReport.Item;
+import dagger.model.BindingGraph;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import javax.inject.Inject;
+import javax.lang.model.element.TypeElement;
+
+/** Validates bindings from {@code @Inject}-annotated constructors. */
+final class InjectBindingValidator implements BindingGraphPlugin {
+
+ private final InjectValidator injectValidator;
+
+ @Inject
+ InjectBindingValidator(InjectValidator injectValidator) {
+ this.injectValidator = injectValidator.whenGeneratingCode();
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/InjectBinding";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ bindingGraph.bindings().stream()
+ .filter(binding -> binding.kind().equals(INJECTION)) // TODO(dpb): Move to BindingGraph
+ .forEach(binding -> validateInjectionBinding(binding, diagnosticReporter));
+ }
+
+ private void validateInjectionBinding(
+ dagger.model.Binding node, DiagnosticReporter diagnosticReporter) {
+ ValidationReport<TypeElement> typeReport =
+ injectValidator.validateType(MoreTypes.asTypeElement(node.key().type()));
+ for (Item item : typeReport.allItems()) {
+ diagnosticReporter.reportBinding(item.kind(), node, item.message());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectProcessingStep.java b/java/dagger/internal/codegen/InjectProcessingStep.java
index 5374592..be8c975 100644
--- a/java/dagger/internal/codegen/InjectProcessingStep.java
+++ b/java/dagger/internal/codegen/InjectProcessingStep.java
@@ -18,10 +18,6 @@
import com.google.auto.common.MoreElements;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.binding.InjectBindingRegistry;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.inject.Inject;
@@ -38,7 +34,6 @@
// TODO(gak): add some error handling for bad source files
final class InjectProcessingStep extends TypeCheckingProcessingStep<Element> {
private final ElementVisitor<Void, Void> visitor;
- private final Set<Element> processedElements = Sets.newLinkedHashSet();
@Inject
InjectProcessingStep(InjectBindingRegistry injectBindingRegistry) {
@@ -70,20 +65,12 @@
@Override
public Set<Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(Inject.class, AssistedInject.class);
+ return ImmutableSet.of(Inject.class);
}
@Override
protected void process(
Element injectElement, ImmutableSet<Class<? extends Annotation>> annotations) {
- // Only process an element once to avoid getting duplicate errors when an element is annotated
- // with multiple inject annotations.
- if (processedElements.contains(injectElement)) {
- return;
- }
-
injectElement.accept(visitor, null);
-
- processedElements.add(injectElement);
}
}
diff --git a/java/dagger/internal/codegen/InjectValidator.java b/java/dagger/internal/codegen/InjectValidator.java
new file mode 100644
index 0000000..d3c4ce8
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectValidator.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.isAnnotationPresent;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+import static dagger.internal.codegen.InjectionAnnotations.injectedConstructors;
+import static dagger.internal.codegen.Scopes.scopesOf;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.type.TypeKind.DECLARED;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.langmodel.Accessibility;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Scope;
+import java.util.Optional;
+import java.util.Set;
+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.Modifier;
+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;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Inject}-annotated elements and the types
+ * that contain them.
+ */
+final class InjectValidator {
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final CompilerOptions compilerOptions;
+ private final DependencyRequestValidator dependencyRequestValidator;
+ private final Optional<Diagnostic.Kind> privateAndStaticInjectionDiagnosticKind;
+
+ @Inject
+ InjectValidator(
+ DaggerTypes types,
+ DaggerElements elements,
+ DependencyRequestValidator dependencyRequestValidator,
+ CompilerOptions compilerOptions) {
+ this(types, elements, compilerOptions, dependencyRequestValidator, Optional.empty());
+ }
+
+ private InjectValidator(
+ DaggerTypes types,
+ DaggerElements elements,
+ CompilerOptions compilerOptions,
+ DependencyRequestValidator dependencyRequestValidator,
+ Optional<Kind> privateAndStaticInjectionDiagnosticKind) {
+ this.types = types;
+ this.elements = elements;
+ this.compilerOptions = compilerOptions;
+ this.dependencyRequestValidator = dependencyRequestValidator;
+ this.privateAndStaticInjectionDiagnosticKind = privateAndStaticInjectionDiagnosticKind;
+ }
+
+ /**
+ * Returns a new validator that performs the same validation as this one, but is strict about
+ * rejecting optionally-specified JSR 330 behavior that Dagger doesn't support (unless {@code
+ * -Adagger.ignorePrivateAndStaticInjectionForComponent=enabled} was set in the javac options).
+ */
+ InjectValidator whenGeneratingCode() {
+ return compilerOptions.ignorePrivateAndStaticInjectionForComponent()
+ ? this
+ : new InjectValidator(
+ types,
+ elements,
+ compilerOptions,
+ dependencyRequestValidator,
+ Optional.of(Diagnostic.Kind.ERROR));
+ }
+
+ ValidationReport<TypeElement> validateConstructor(ExecutableElement constructorElement) {
+ ValidationReport.Builder<TypeElement> builder =
+ ValidationReport.about(MoreElements.asType(constructorElement.getEnclosingElement()));
+ if (constructorElement.getModifiers().contains(PRIVATE)) {
+ builder.addError(
+ "Dagger does not support injection into private constructors", constructorElement);
+ }
+
+ for (AnnotationMirror qualifier : getQualifiers(constructorElement)) {
+ builder.addError(
+ "@Qualifier annotations are not allowed on @Inject constructors",
+ constructorElement,
+ qualifier);
+ }
+
+ for (Scope scope : scopesOf(constructorElement)) {
+ builder.addError(
+ "@Scope annotations are not allowed on @Inject constructors; annotate the class instead",
+ constructorElement,
+ scope.scopeAnnotation());
+ }
+
+ for (VariableElement parameter : constructorElement.getParameters()) {
+ validateDependencyRequest(builder, parameter);
+ }
+
+ if (throwsCheckedExceptions(constructorElement)) {
+ builder.addItem(
+ "Dagger does not support checked exceptions on @Inject constructors",
+ privateMemberDiagnosticKind(),
+ constructorElement);
+ }
+
+ checkInjectIntoPrivateClass(constructorElement, builder);
+
+ TypeElement enclosingElement =
+ MoreElements.asType(constructorElement.getEnclosingElement());
+
+ Set<Modifier> typeModifiers = enclosingElement.getModifiers();
+ if (typeModifiers.contains(ABSTRACT)) {
+ builder.addError(
+ "@Inject is nonsense on the constructor of an abstract class", constructorElement);
+ }
+
+ if (enclosingElement.getNestingKind().isNested()
+ && !typeModifiers.contains(STATIC)) {
+ builder.addError(
+ "@Inject constructors are invalid on inner classes. "
+ + "Did you mean to make the class static?",
+ constructorElement);
+ }
+
+ // This is computationally expensive, but probably preferable to a giant index
+ ImmutableSet<ExecutableElement> injectConstructors = injectedConstructors(enclosingElement);
+
+ if (injectConstructors.size() > 1) {
+ builder.addError("Types may only contain one @Inject constructor", constructorElement);
+ }
+
+ ImmutableSet<Scope> scopes = scopesOf(enclosingElement);
+ if (scopes.size() > 1) {
+ for (Scope scope : scopes) {
+ builder.addError(
+ "A single binding may not declare more than one @Scope",
+ enclosingElement,
+ scope.scopeAnnotation());
+ }
+ }
+
+ return builder.build();
+ }
+
+ private ValidationReport<VariableElement> validateField(VariableElement fieldElement) {
+ ValidationReport.Builder<VariableElement> builder = ValidationReport.about(fieldElement);
+ Set<Modifier> modifiers = fieldElement.getModifiers();
+ if (modifiers.contains(FINAL)) {
+ builder.addError("@Inject fields may not be final", fieldElement);
+ }
+
+ if (modifiers.contains(PRIVATE)) {
+ builder.addItem(
+ "Dagger does not support injection into private fields",
+ privateMemberDiagnosticKind(),
+ fieldElement);
+ }
+
+ if (modifiers.contains(STATIC)) {
+ builder.addItem(
+ "Dagger does not support injection into static fields",
+ staticMemberDiagnosticKind(),
+ fieldElement);
+ }
+
+ validateDependencyRequest(builder, fieldElement);
+
+ return builder.build();
+ }
+
+ private ValidationReport<ExecutableElement> validateMethod(ExecutableElement methodElement) {
+ ValidationReport.Builder<ExecutableElement> builder = ValidationReport.about(methodElement);
+ Set<Modifier> modifiers = methodElement.getModifiers();
+ if (modifiers.contains(ABSTRACT)) {
+ builder.addError("Methods with @Inject may not be abstract", methodElement);
+ }
+
+ if (modifiers.contains(PRIVATE)) {
+ builder.addItem(
+ "Dagger does not support injection into private methods",
+ privateMemberDiagnosticKind(),
+ methodElement);
+ }
+
+ if (modifiers.contains(STATIC)) {
+ builder.addItem(
+ "Dagger does not support injection into static methods",
+ staticMemberDiagnosticKind(),
+ methodElement);
+ }
+
+ if (!methodElement.getTypeParameters().isEmpty()) {
+ builder.addError("Methods with @Inject may not declare type parameters", methodElement);
+ }
+
+ for (VariableElement parameter : methodElement.getParameters()) {
+ validateDependencyRequest(builder, parameter);
+ }
+
+ return builder.build();
+ }
+
+ private void validateDependencyRequest(
+ ValidationReport.Builder<?> builder, VariableElement parameter) {
+ dependencyRequestValidator.validateDependencyRequest(builder, parameter, parameter.asType());
+ dependencyRequestValidator.checkNotProducer(builder, parameter);
+ }
+
+ ValidationReport<TypeElement> validateMembersInjectionType(TypeElement typeElement) {
+ // TODO(beder): This element might not be currently compiled, so this error message could be
+ // left in limbo. Find an appropriate way to display the error message in that case.
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(typeElement);
+ boolean hasInjectedMembers = false;
+ for (VariableElement element : ElementFilter.fieldsIn(typeElement.getEnclosedElements())) {
+ if (MoreElements.isAnnotationPresent(element, Inject.class)) {
+ hasInjectedMembers = true;
+ ValidationReport<VariableElement> report = validateField(element);
+ if (!report.isClean()) {
+ builder.addSubreport(report);
+ }
+ }
+ }
+ for (ExecutableElement element : ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
+ if (MoreElements.isAnnotationPresent(element, Inject.class)) {
+ hasInjectedMembers = true;
+ ValidationReport<ExecutableElement> report = validateMethod(element);
+ if (!report.isClean()) {
+ builder.addSubreport(report);
+ }
+ }
+ }
+
+ if (hasInjectedMembers) {
+ checkInjectIntoPrivateClass(typeElement, builder);
+ }
+ TypeMirror superclass = typeElement.getSuperclass();
+ if (!superclass.getKind().equals(TypeKind.NONE)) {
+ ValidationReport<TypeElement> report = validateType(MoreTypes.asTypeElement(superclass));
+ if (!report.isClean()) {
+ builder.addSubreport(report);
+ }
+ }
+ return builder.build();
+ }
+
+ ValidationReport<TypeElement> validateType(TypeElement typeElement) {
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(typeElement);
+ ValidationReport<TypeElement> membersInjectionReport =
+ validateMembersInjectionType(typeElement);
+ if (!membersInjectionReport.isClean()) {
+ builder.addSubreport(membersInjectionReport);
+ }
+ for (ExecutableElement element :
+ ElementFilter.constructorsIn(typeElement.getEnclosedElements())) {
+ if (isAnnotationPresent(element, Inject.class)) {
+ ValidationReport<TypeElement> report = validateConstructor(element);
+ if (!report.isClean()) {
+ builder.addSubreport(report);
+ }
+ }
+ }
+ return builder.build();
+ }
+
+ boolean isValidType(TypeMirror type) {
+ if (!type.getKind().equals(DECLARED)) {
+ return true;
+ }
+ return validateType(MoreTypes.asTypeElement(type)).isClean();
+ }
+
+ /** Returns true if the given method element declares a checked exception. */
+ private boolean throwsCheckedExceptions(ExecutableElement methodElement) {
+ TypeMirror runtimeExceptionType = elements.getTypeElement(RuntimeException.class).asType();
+ TypeMirror errorType = elements.getTypeElement(Error.class).asType();
+ for (TypeMirror thrownType : methodElement.getThrownTypes()) {
+ if (!types.isSubtype(thrownType, runtimeExceptionType)
+ && !types.isSubtype(thrownType, errorType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void checkInjectIntoPrivateClass(
+ Element element, ValidationReport.Builder<TypeElement> builder) {
+ if (!Accessibility.isElementAccessibleFromOwnPackage(
+ DaggerElements.closestEnclosingTypeElement(element))) {
+ builder.addItem(
+ "Dagger does not support injection into private classes",
+ privateMemberDiagnosticKind(),
+ element);
+ }
+ }
+
+ private Diagnostic.Kind privateMemberDiagnosticKind() {
+ return privateAndStaticInjectionDiagnosticKind.orElse(
+ compilerOptions.privateMemberValidationKind());
+ }
+
+ private Diagnostic.Kind staticMemberDiagnosticKind() {
+ return privateAndStaticInjectionDiagnosticKind.orElse(
+ compilerOptions.staticMemberValidationKind());
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectionAnnotations.java b/java/dagger/internal/codegen/InjectionAnnotations.java
new file mode 100644
index 0000000..521ad43
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectionAnnotations.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.lang.model.util.ElementFilter.constructorsIn;
+
+import com.google.auto.common.AnnotationMirrors;
+import com.google.auto.common.SuperficialValidation;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Qualifier;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Utilities relating to annotations defined in the {@code javax.inject} package.
+ */
+final class InjectionAnnotations {
+ static Optional<AnnotationMirror> getQualifier(Element e) {
+ if (!SuperficialValidation.validateElement(e)) {
+ throw new TypeNotPresentException(e.toString(), null);
+ }
+ checkNotNull(e);
+ ImmutableSet<? extends AnnotationMirror> qualifierAnnotations = getQualifiers(e);
+ switch (qualifierAnnotations.size()) {
+ case 0:
+ return Optional.empty();
+ case 1:
+ return Optional.<AnnotationMirror>of(qualifierAnnotations.iterator().next());
+ default:
+ throw new IllegalArgumentException(
+ e + " was annotated with more than one @Qualifier annotation");
+ }
+ }
+
+ static ImmutableSet<? extends AnnotationMirror> getQualifiers(Element element) {
+ return AnnotationMirrors.getAnnotatedAnnotations(element, Qualifier.class);
+ }
+
+ /** Returns the constructors in {@code type} that are annotated with {@link Inject}. */
+ static ImmutableSet<ExecutableElement> injectedConstructors(TypeElement type) {
+ return FluentIterable.from(constructorsIn(type.getEnclosedElements()))
+ .filter(constructor -> isAnnotationPresent(constructor, Inject.class))
+ .toSet();
+ }
+
+ private InjectionAnnotations() {}
+}
diff --git a/java/dagger/internal/codegen/InjectionMethod.java b/java/dagger/internal/codegen/InjectionMethod.java
new file mode 100644
index 0000000..2785b18
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectionMethod.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CheckReturnValue;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.List;
+import java.util.Optional;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Parameterizable;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A static method that implements provision and/or injection in one step:
+ *
+ * <ul>
+ * <li>methods that invoke {@code @Inject} constructors and do members injection if necessary
+ * <li>methods that call {@code @Provides} module methods
+ * <li>methods that perform members injection
+ * </ul>
+ *
+ * <p>Note that although this type uses {@code @AutoValue}, it uses instance equality. It uses
+ * {@code @AutoValue} to avoid the boilerplate of writing a correct builder, but is not intended to
+ * actually be a value type.
+ */
+@AutoValue
+abstract class InjectionMethod {
+ abstract String name();
+
+ abstract boolean varargs();
+
+ abstract ImmutableList<TypeVariableName> typeVariables();
+
+ abstract ImmutableMap<ParameterSpec, TypeMirror> parameters();
+
+ abstract Optional<TypeMirror> returnType();
+
+ abstract Optional<DeclaredType> nullableAnnotation();
+
+ abstract ImmutableList<TypeMirror> exceptions();
+
+ abstract CodeBlock methodBody();
+
+ abstract ClassName enclosingClass();
+
+ MethodSpec toMethodSpec() {
+ MethodSpec.Builder builder =
+ methodBuilder(name())
+ .addModifiers(PUBLIC, STATIC)
+ .varargs(varargs())
+ .addTypeVariables(typeVariables())
+ .addParameters(parameters().keySet())
+ .addCode(methodBody());
+ returnType().map(TypeName::get).ifPresent(builder::returns);
+ nullableAnnotation()
+ .ifPresent(nullableType -> CodeBlocks.addAnnotation(builder, nullableType));
+ exceptions().stream().map(TypeName::get).forEach(builder::addException);
+ return builder.build();
+ }
+
+ CodeBlock invoke(List<CodeBlock> arguments, ClassName requestingClass) {
+ checkArgument(arguments.size() == parameters().size());
+ CodeBlock.Builder invocation = CodeBlock.builder();
+ if (!enclosingClass().equals(requestingClass)) {
+ invocation.add("$T.", enclosingClass());
+ }
+ return invocation.add("$L($L)", name(), makeParametersCodeBlock(arguments)).build();
+ }
+
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ static Builder builder(DaggerElements elements) {
+ Builder builder = new AutoValue_InjectionMethod.Builder();
+ builder.elements = elements;
+ builder.varargs(false).exceptions(ImmutableList.of()).nullableAnnotation(Optional.empty());
+ return builder;
+ }
+
+ @CanIgnoreReturnValue
+ @AutoValue.Builder
+ abstract static class Builder {
+ private final UniqueNameSet parameterNames = new UniqueNameSet();
+ private final CodeBlock.Builder methodBody = CodeBlock.builder();
+ private DaggerElements elements;
+
+ abstract ImmutableMap.Builder<ParameterSpec, TypeMirror> parametersBuilder();
+ abstract ImmutableList.Builder<TypeVariableName> typeVariablesBuilder();
+ abstract Builder name(String name);
+ abstract Builder varargs(boolean varargs);
+ abstract Builder returnType(TypeMirror returnType);
+ abstract Builder exceptions(Iterable<? extends TypeMirror> exceptions);
+ abstract Builder nullableAnnotation(Optional<DeclaredType> nullableAnnotation);
+ abstract Builder methodBody(CodeBlock methodBody);
+
+ final CodeBlock.Builder methodBodyBuilder() {
+ return methodBody;
+ }
+
+ abstract Builder enclosingClass(ClassName enclosingClass);
+
+ /**
+ * Adds a parameter for the given name and type. If another parameter has already been added
+ * with the same name, the name is disambiguated.
+ */
+ ParameterSpec addParameter(String name, TypeMirror type) {
+ ParameterSpec parameter =
+ ParameterSpec.builder(TypeName.get(type), parameterNames.getUniqueName(name)).build();
+ parametersBuilder().put(parameter, type);
+ return parameter;
+ }
+
+ /**
+ * Calls {@link #copyParameter(VariableElement)} for each parameter of of {@code method}, and
+ * concatenates the results of each call, {@link CodeBlocks#makeParametersCodeBlock(Iterable)
+ * separated with commas}.
+ */
+ CodeBlock copyParameters(ExecutableElement method) {
+ ImmutableList.Builder<CodeBlock> argumentsBuilder = ImmutableList.builder();
+ for (VariableElement parameter : method.getParameters()) {
+ argumentsBuilder.add(copyParameter(parameter));
+ }
+ varargs(method.isVarArgs());
+ return makeParametersCodeBlock(argumentsBuilder.build());
+ }
+
+ /**
+ * Adds {@code parameter} as a parameter of this method, using a publicly accessible version of
+ * the parameter's type. Returns a {@link CodeBlock} of the usage of this parameter within the
+ * injection method's {@link #methodBody()}.
+ */
+ CodeBlock copyParameter(VariableElement parameter) {
+ TypeMirror elementType = parameter.asType();
+ boolean useObject = !isRawTypePubliclyAccessible(elementType);
+ TypeMirror publicType = useObject ? objectType() : elementType;
+ ParameterSpec parameterSpec = addParameter(parameter.getSimpleName().toString(), publicType);
+ return useObject
+ ? CodeBlock.of("($T) $N", elementType, parameterSpec)
+ : CodeBlock.of("$N", parameterSpec);
+ }
+
+ private TypeMirror objectType() {
+ return elements.getTypeElement(Object.class).asType();
+ }
+
+ /**
+ * Adds each type parameter of {@code parameterizable} as a type parameter of this injection
+ * method.
+ */
+ Builder copyTypeParameters(Parameterizable parameterizable) {
+ parameterizable.getTypeParameters().stream()
+ .map(TypeVariableName::get)
+ .forEach(typeVariablesBuilder()::add);
+ return this;
+ }
+
+ Builder copyThrows(ExecutableElement element) {
+ exceptions(element.getThrownTypes());
+ return this;
+ }
+
+ @CheckReturnValue
+ final InjectionMethod build() {
+ return methodBody(methodBody.build()).buildInternal();
+ }
+
+ abstract InjectionMethod buildInternal();
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectionMethods.java b/java/dagger/internal/codegen/InjectionMethods.java
new file mode 100644
index 0000000..d61aaa5
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectionMethods.java
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.ConfigurationAnnotations.getNullableType;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.FactoryGenerator.checkNotNullProvidesMethod;
+import static dagger.internal.codegen.RequestKinds.requestTypeName;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toConcatenatedCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
+import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
+import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static java.util.stream.Collectors.toList;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.type.TypeKind.VOID;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import dagger.model.RequestKind;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+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;
+
+/** Convenience methods for creating and invoking {@link InjectionMethod}s. */
+final class InjectionMethods {
+
+ /**
+ * A method that returns an object from a {@code @Provides} method or an {@code @Inject}ed
+ * constructor. Its parameters match the dependency requests for constructor and members
+ * injection.
+ *
+ * <p>For {@code @Provides} methods named "foo", the method name is "proxyFoo". If the
+ * {@code @Provides} method and its raw parameter types are publicly accessible, no method is
+ * necessary and this method returns {@link Optional#empty()}.
+ *
+ * <p>Example:
+ *
+ * <pre><code>
+ * abstract class FooModule {
+ * {@literal @Provides} static Foo provideFoo(Bar bar, Baz baz) { … }
+ * }
+ *
+ * public static proxyProvideFoo(Bar bar, Baz baz) { … }
+ * </code></pre>
+ *
+ * <p>For {@code @Inject}ed constructors, the method name is "newFoo". If the constructor and its
+ * raw parameter types are publicly accessible, no method is necessary and this method returns
+ * {@code Optional#empty()}.
+ *
+ * <p>Example:
+ *
+ * <pre><code>
+ * class Foo {
+ * {@literal @Inject} Foo(Bar bar) {}
+ * }
+ *
+ * public static Foo newFoo(Bar bar) { … }
+ * </code></pre>
+ */
+ static final class ProvisionMethod {
+ /**
+ * Names of methods that are already defined in factories and shouldn't be used for the proxy
+ * method name.
+ */
+ private static final ImmutableSet<String> BANNED_PROXY_NAMES = ImmutableSet.of("get", "create");
+
+ /**
+ * Returns a method that invokes the binding's {@linkplain ProvisionBinding#bindingElement()
+ * constructor} and injects the instance's members.
+ */
+ static InjectionMethod create(
+ ProvisionBinding binding, CompilerOptions compilerOptions, DaggerElements elements) {
+ ClassName proxyEnclosingClass = generatedClassNameForBinding(binding);
+ ExecutableElement element = MoreElements.asExecutable(binding.bindingElement().get());
+ switch (element.getKind()) {
+ case CONSTRUCTOR:
+ return constructorProxy(proxyEnclosingClass, element, elements);
+ case METHOD:
+ return methodProxy(
+ proxyEnclosingClass,
+ element,
+ methodName(element),
+ ReceiverAccessibility.IGNORE,
+ CheckNotNullPolicy.get(binding, compilerOptions),
+ elements);
+ default:
+ throw new AssertionError(element);
+ }
+ }
+
+ /**
+ * Invokes the injection method for {@code binding}, with the dependencies transformed with the
+ * {@code dependencyUsage} function.
+ */
+ // TODO(ronshapiro): Further extract a ProvisionMethod type that composes an InjectionMethod, so
+ // users can write ProvisionMethod.create().invoke()
+ static CodeBlock invoke(
+ ProvisionBinding binding,
+ Function<DependencyRequest, CodeBlock> dependencyUsage,
+ ClassName requestingClass,
+ Optional<CodeBlock> moduleReference,
+ CompilerOptions compilerOptions,
+ DaggerElements elements) {
+ ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
+ moduleReference.ifPresent(arguments::add);
+ arguments.addAll(
+ injectionMethodArguments(
+ binding.provisionDependencies(), dependencyUsage, requestingClass));
+ // TODO(ronshapiro): make InjectionMethods @Injectable
+ return create(binding, compilerOptions, elements).invoke(arguments.build(), requestingClass);
+ }
+
+ private static InjectionMethod constructorProxy(
+ ClassName proxyEnclosingClass, ExecutableElement constructor, DaggerElements elements) {
+ TypeElement enclosingType = MoreElements.asType(constructor.getEnclosingElement());
+ InjectionMethod.Builder injectionMethod =
+ InjectionMethod.builder(elements)
+ .name(methodName(constructor))
+ .returnType(enclosingType.asType())
+ .enclosingClass(proxyEnclosingClass);
+
+ injectionMethod
+ .copyTypeParameters(enclosingType)
+ .copyThrows(constructor);
+
+ CodeBlock arguments = injectionMethod.copyParameters(constructor);
+ injectionMethod
+ .methodBodyBuilder()
+ .addStatement("return new $T($L)", enclosingType, arguments);
+ return injectionMethod.build();
+ }
+
+ /**
+ * Returns {@code true} if injecting an instance of {@code binding} from {@code callingPackage}
+ * requires the use of an injection method.
+ */
+ static boolean requiresInjectionMethod(
+ ProvisionBinding binding,
+ ImmutableList<Expression> arguments,
+ CompilerOptions compilerOptions,
+ String callingPackage,
+ DaggerTypes types) {
+ ExecutableElement method = MoreElements.asExecutable(binding.bindingElement().get());
+ return !binding.injectionSites().isEmpty()
+ || binding.shouldCheckForNull(compilerOptions)
+ || !isElementAccessibleFrom(method, callingPackage)
+ || !areParametersAssignable(method, arguments, types)
+ // This check should be removable once we drop support for -source 7
+ || method.getParameters().stream()
+ .map(VariableElement::asType)
+ .anyMatch(type -> !isRawTypeAccessible(type, callingPackage));
+ }
+
+ private static boolean areParametersAssignable(
+ ExecutableElement element, ImmutableList<Expression> arguments, DaggerTypes types) {
+ List<? extends VariableElement> parameters = element.getParameters();
+ checkArgument(parameters.size() == arguments.size());
+ for (int i = 0; i < parameters.size(); i++) {
+ if (!types.isAssignable(arguments.get(i).type(), parameters.get(i).asType())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the name of the {@code static} method that wraps {@code method}. For methods that are
+ * associated with {@code @Inject} constructors, the method will also inject all {@link
+ * InjectionSite}s.
+ */
+ private static String methodName(ExecutableElement method) {
+ switch (method.getKind()) {
+ case CONSTRUCTOR:
+ return "newInstance";
+ case METHOD:
+ String methodName = method.getSimpleName().toString();
+ return BANNED_PROXY_NAMES.contains(methodName)
+ ? "proxy" + LOWER_CAMEL.to(UPPER_CAMEL, methodName)
+ : methodName;
+ default:
+ throw new AssertionError(method);
+ }
+ }
+ }
+
+ /**
+ * A static method that injects one member of an instance of a type. Its first parameter is an
+ * instance of the type to be injected. The remaining parameters match the dependency requests for
+ * the injection site.
+ *
+ * <p>Example:
+ *
+ * <pre><code>
+ * class Foo {
+ * {@literal @Inject} Bar bar;
+ * {@literal @Inject} void setThings(Baz baz, Qux qux) {}
+ * }
+ *
+ * public static injectBar(Foo instance, Bar bar) { … }
+ * public static injectSetThings(Foo instance, Baz baz, Qux qux) { … }
+ * </code></pre>
+ */
+ static final class InjectionSiteMethod {
+ /**
+ * When a type has an inaccessible member from a supertype (e.g. an @Inject field in a parent
+ * that's in a different package), a method in the supertype's package must be generated to give
+ * the subclass's members injector a way to inject it. Each potentially inaccessible member
+ * receives its own method, as the subclass may need to inject them in a different order from
+ * the parent class.
+ */
+ static InjectionMethod create(InjectionSite injectionSite, DaggerElements elements) {
+ String methodName = methodName(injectionSite);
+ ClassName proxyEnclosingClass = membersInjectorNameForType(
+ MoreElements.asType(injectionSite.element().getEnclosingElement()));
+ switch (injectionSite.kind()) {
+ case METHOD:
+ return methodProxy(
+ proxyEnclosingClass,
+ MoreElements.asExecutable(injectionSite.element()),
+ methodName,
+ ReceiverAccessibility.CAST_IF_NOT_PUBLIC,
+ CheckNotNullPolicy.IGNORE,
+ elements);
+ case FIELD:
+ return fieldProxy(
+ proxyEnclosingClass,
+ MoreElements.asVariable(injectionSite.element()),
+ methodName,
+ elements);
+ }
+ throw new AssertionError(injectionSite);
+ }
+
+ /**
+ * Invokes each of the injection methods for {@code injectionSites}, with the dependencies
+ * transformed using the {@code dependencyUsage} function.
+ *
+ * @param instanceType the type of the {@code instance} parameter
+ */
+ static CodeBlock invokeAll(
+ ImmutableSet<InjectionSite> injectionSites,
+ ClassName generatedTypeName,
+ CodeBlock instanceCodeBlock,
+ TypeMirror instanceType,
+ DaggerTypes types,
+ Function<DependencyRequest, CodeBlock> dependencyUsage,
+ DaggerElements elements) {
+ return injectionSites
+ .stream()
+ .map(
+ injectionSite -> {
+ TypeMirror injectSiteType =
+ types.erasure(injectionSite.element().getEnclosingElement().asType());
+
+ // If instance has been declared as Object because it is not accessible from the
+ // component, but the injectionSite is in a supertype of instanceType that is
+ // publicly accessible, the InjectionSiteMethod will request the actual type and not
+ // Object as the first parameter. If so, cast to the supertype which is accessible
+ // from within generatedTypeName
+ CodeBlock maybeCastedInstance =
+ !types.isSubtype(instanceType, injectSiteType)
+ && isTypeAccessibleFrom(injectSiteType, generatedTypeName.packageName())
+ ? CodeBlock.of("($T) $L", injectSiteType, instanceCodeBlock)
+ : instanceCodeBlock;
+ return CodeBlock.of(
+ "$L;",
+ invoke(
+ injectionSite,
+ generatedTypeName,
+ maybeCastedInstance,
+ dependencyUsage,
+ elements));
+ })
+ .collect(toConcatenatedCodeBlock());
+ }
+
+ /**
+ * Invokes the injection method for {@code injectionSite}, with the dependencies transformed
+ * using the {@code dependencyUsage} function.
+ */
+ private static CodeBlock invoke(
+ InjectionSite injectionSite,
+ ClassName generatedTypeName,
+ CodeBlock instanceCodeBlock,
+ Function<DependencyRequest, CodeBlock> dependencyUsage,
+ DaggerElements elements) {
+ List<CodeBlock> arguments = new ArrayList<>();
+ arguments.add(instanceCodeBlock);
+ if (!injectionSite.dependencies().isEmpty()) {
+ arguments.addAll(
+ injectionSite
+ .dependencies()
+ .stream()
+ .map(dependencyUsage)
+ .collect(toList()));
+ }
+ return create(injectionSite, elements).invoke(arguments, generatedTypeName);
+ }
+
+ /*
+ * TODO(ronshapiro): this isn't perfect, as collisions could still exist. Some examples:
+ *
+ * - @Inject void members() {} will generate a method that conflicts with the instance
+ * method `injectMembers(T)`
+ * - Adding the index could conflict with another member:
+ * @Inject void a(Object o) {}
+ * @Inject void a(String s) {}
+ * @Inject void a1(String s) {}
+ *
+ * Here, Method a(String) will add the suffix "1", which will conflict with the method
+ * generated for a1(String)
+ * - Members named "members" or "methods" could also conflict with the {@code static} injection
+ * method.
+ */
+ private static String methodName(InjectionSite injectionSite) {
+ int index = injectionSite.indexAmongAtInjectMembersWithSameSimpleName();
+ String indexString = index == 0 ? "" : String.valueOf(index + 1);
+ return "inject"
+ + LOWER_CAMEL.to(UPPER_CAMEL, injectionSite.element().getSimpleName().toString())
+ + indexString;
+ }
+ }
+
+ /**
+ * Returns an argument list suitable for calling an injection method. Down-casts any arguments
+ * that are {@code Object} (or {@code Provider<Object>}) at the caller but not the method.
+ *
+ * @param dependencies the dependencies used by the method
+ * @param dependencyUsage function to apply on each of {@code dependencies} before casting
+ * @param requestingClass the class calling the injection method
+ */
+ private static ImmutableList<CodeBlock> injectionMethodArguments(
+ ImmutableSet<DependencyRequest> dependencies,
+ Function<DependencyRequest, CodeBlock> dependencyUsage,
+ ClassName requestingClass) {
+ return dependencies.stream()
+ .map(dep -> injectionMethodArgument(dep, dependencyUsage.apply(dep), requestingClass))
+ .collect(toImmutableList());
+ }
+
+ private static CodeBlock injectionMethodArgument(
+ DependencyRequest dependency, CodeBlock argument, ClassName generatedTypeName) {
+ TypeMirror keyType = dependency.key().type();
+ CodeBlock.Builder codeBlock = CodeBlock.builder();
+ if (!isRawTypeAccessible(keyType, generatedTypeName.packageName())
+ && isTypeAccessibleFrom(keyType, generatedTypeName.packageName())) {
+ if (!dependency.kind().equals(RequestKind.INSTANCE)) {
+ TypeName usageTypeName = accessibleType(dependency);
+ codeBlock.add("($T) ($T)", usageTypeName, rawTypeName(usageTypeName));
+ } else if (dependency.requestElement().get().asType().getKind().equals(TypeKind.TYPEVAR)) {
+ codeBlock.add("($T)", keyType);
+ }
+ }
+ return codeBlock.add(argument).build();
+ }
+
+ /**
+ * Returns the parameter type for {@code dependency}. If the raw type is not accessible, returns
+ * {@link Object}.
+ */
+ private static TypeName accessibleType(DependencyRequest dependency) {
+ TypeName typeName = requestTypeName(dependency.kind(), accessibleType(dependency.key().type()));
+ return dependency
+ .requestElement()
+ .map(element -> element.asType().getKind().isPrimitive())
+ .orElse(false)
+ ? typeName.unbox()
+ : typeName;
+ }
+
+ /**
+ * Returns the accessible type for {@code type}. If the raw type is not accessible, returns {@link
+ * Object}.
+ */
+ private static TypeName accessibleType(TypeMirror type) {
+ return isRawTypePubliclyAccessible(type) ? TypeName.get(type) : TypeName.OBJECT;
+ }
+
+ /**
+ * Returns the accessible type for {@code type}. If the raw type is not accessible, returns {@link
+ * Object}.
+ */
+ // TODO(ronshapiro): Can we use DaggerTypes.publiclyAccessibleType in place of this method?
+ private static TypeMirror accessibleType(TypeMirror type, DaggerElements elements) {
+ return isRawTypePubliclyAccessible(type)
+ ? type
+ : elements.getTypeElement(Object.class).asType();
+ }
+
+ private enum ReceiverAccessibility {
+ CAST_IF_NOT_PUBLIC {
+ @Override
+ TypeMirror parameterType(TypeMirror type, DaggerElements elements) {
+ return accessibleType(type, elements);
+ }
+
+ @Override
+ CodeBlock potentiallyCast(CodeBlock instance, TypeMirror instanceType) {
+ return instanceWithPotentialCast(instance, instanceType);
+ }
+ },
+ IGNORE {
+ @Override
+ TypeMirror parameterType(TypeMirror type, DaggerElements elements) {
+ return type;
+ }
+
+ @Override
+ CodeBlock potentiallyCast(CodeBlock instance, TypeMirror instanceType) {
+ return instance;
+ }
+ },
+ ;
+
+ abstract TypeMirror parameterType(TypeMirror type, DaggerElements elements);
+ abstract CodeBlock potentiallyCast(CodeBlock instance, TypeMirror instanceType);
+ }
+
+ private static CodeBlock instanceWithPotentialCast(CodeBlock instance, TypeMirror instanceType) {
+ return isRawTypePubliclyAccessible(instanceType)
+ ? instance
+ : CodeBlock.of("(($T) $L)", instanceType, instance);
+ }
+
+ private enum CheckNotNullPolicy {
+ IGNORE, CHECK_FOR_NULL;
+ CodeBlock checkForNull(CodeBlock maybeNull) {
+ if (this.equals(IGNORE)) {
+ return maybeNull;
+ }
+ return checkNotNullProvidesMethod(maybeNull);
+ }
+
+ static CheckNotNullPolicy get(ProvisionBinding binding, CompilerOptions compilerOptions) {
+ return binding.shouldCheckForNull(compilerOptions) ? CHECK_FOR_NULL : IGNORE;
+ }
+ }
+
+ private static InjectionMethod methodProxy(
+ ClassName proxyEnclosingClass,
+ ExecutableElement method,
+ String methodName,
+ ReceiverAccessibility receiverAccessibility,
+ CheckNotNullPolicy checkNotNullPolicy,
+ DaggerElements elements) {
+ TypeElement enclosingType = MoreElements.asType(method.getEnclosingElement());
+ InjectionMethod.Builder injectionMethod =
+ InjectionMethod.builder(elements).name(methodName).enclosingClass(proxyEnclosingClass);
+ ParameterSpec instance = null;
+ if (!method.getModifiers().contains(STATIC)) {
+ instance =
+ injectionMethod.addParameter(
+ "instance", receiverAccessibility.parameterType(enclosingType.asType(), elements));
+ }
+
+ CodeBlock arguments = injectionMethod.copyParameters(method);
+ if (!method.getReturnType().getKind().equals(VOID)) {
+ injectionMethod
+ .returnType(method.getReturnType())
+ .nullableAnnotation(getNullableType(method));
+ injectionMethod.methodBodyBuilder().add("return ");
+ }
+ CodeBlock.Builder proxyInvocation = CodeBlock.builder();
+ if (method.getModifiers().contains(STATIC)) {
+ proxyInvocation.add("$T", rawTypeName(TypeName.get(enclosingType.asType())));
+ } else {
+ injectionMethod.copyTypeParameters(enclosingType);
+ proxyInvocation.add(
+ receiverAccessibility.potentiallyCast(
+ CodeBlock.of("$N", instance), enclosingType.asType()));
+ }
+
+ injectionMethod
+ .copyTypeParameters(method)
+ .copyThrows(method);
+
+ proxyInvocation.add(".$N($L)", method.getSimpleName(), arguments);
+ injectionMethod
+ .methodBodyBuilder()
+ .add(checkNotNullPolicy.checkForNull(proxyInvocation.build()))
+ .add(";\n");
+ return injectionMethod.build();
+ }
+
+ private static InjectionMethod fieldProxy(
+ ClassName proxyEnclosingClass,
+ VariableElement field,
+ String methodName,
+ DaggerElements elements) {
+ TypeElement enclosingType = MoreElements.asType(field.getEnclosingElement());
+ InjectionMethod.Builder injectionMethod =
+ InjectionMethod.builder(elements).name(methodName).enclosingClass(proxyEnclosingClass);
+ injectionMethod.copyTypeParameters(enclosingType);
+
+ ParameterSpec instance =
+ injectionMethod.addParameter("instance", accessibleType(enclosingType.asType(), elements));
+ CodeBlock parameter = injectionMethod.copyParameter(field);
+ injectionMethod
+ .methodBodyBuilder()
+ .addStatement(
+ "$L.$L = $L",
+ instanceWithPotentialCast(CodeBlock.of("$N", instance), enclosingType.asType()),
+ field.getSimpleName(),
+ parameter);
+ return injectionMethod.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
new file mode 100644
index 0000000..2d2e8cb
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectionOrProvisionProviderCreationExpression.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.model.BindingKind.INJECTION;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import javax.inject.Provider;
+
+/**
+ * A {@link Provider} creation expression for an {@link javax.inject.Inject @Inject}-constructed
+ * class or a {@link dagger.Provides @Provides}-annotated module method.
+ */
+// TODO(dpb): Resolve with ProducerCreationExpression.
+final class InjectionOrProvisionProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ContributionBinding binding;
+ private final ComponentBindingExpressions componentBindingExpressions;
+
+ InjectionOrProvisionProviderCreationExpression(
+ ContributionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ CodeBlock createFactory =
+ CodeBlock.of(
+ "$T.create($L)",
+ generatedClassNameForBinding(binding),
+ componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
+
+ // When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
+ // type properly, so cast to a raw framework type before scoping.
+ if (binding.kind().equals(INJECTION)
+ && binding.unresolved().isPresent()
+ && binding.scope().isPresent()) {
+ return CodeBlocks.cast(createFactory, Provider.class);
+ } else {
+ return createFactory;
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/InjectionSiteFactory.java b/java/dagger/internal/codegen/InjectionSiteFactory.java
new file mode 100644
index 0000000..d09f91d
--- /dev/null
+++ b/java/dagger/internal/codegen/InjectionSiteFactory.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 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.auto.common.MoreElements.isAnnotationPresent;
+import static dagger.internal.codegen.MembersInjectionBinding.InjectionSite.Kind.METHOD;
+import static dagger.internal.codegen.langmodel.DaggerElements.DECLARATION_ORDER;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.SetMultimap;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementVisitor;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementKindVisitor8;
+
+/** A factory for {@link Binding} objects. */
+final class InjectionSiteFactory {
+ private final ElementVisitor<Optional<InjectionSite>, DeclaredType> injectionSiteVisitor =
+ new ElementKindVisitor8<Optional<InjectionSite>, DeclaredType>(Optional.empty()) {
+ @Override
+ public Optional<InjectionSite> visitExecutableAsMethod(
+ ExecutableElement method, DeclaredType type) {
+ ExecutableType resolved = MoreTypes.asExecutable(types.asMemberOf(type, method));
+ return Optional.of(
+ InjectionSite.method(
+ method,
+ dependencyRequestFactory.forRequiredResolvedVariables(
+ method.getParameters(), resolved.getParameterTypes())));
+ }
+
+ @Override
+ public Optional<InjectionSite> visitVariableAsField(
+ VariableElement field, DeclaredType type) {
+ if (!isAnnotationPresent(field, Inject.class)
+ || field.getModifiers().contains(PRIVATE)
+ || field.getModifiers().contains(STATIC)) {
+ return Optional.empty();
+ }
+ TypeMirror resolved = types.asMemberOf(type, field);
+ return Optional.of(
+ InjectionSite.field(
+ field, dependencyRequestFactory.forRequiredResolvedVariable(field, resolved)));
+ }
+ };
+
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final DependencyRequestFactory dependencyRequestFactory;
+
+ @Inject
+ InjectionSiteFactory(
+ DaggerTypes types,
+ DaggerElements elements,
+ DependencyRequestFactory dependencyRequestFactory) {
+ this.types = types;
+ this.elements = elements;
+ this.dependencyRequestFactory = dependencyRequestFactory;
+ }
+
+ /** Returns the injection sites for a type. */
+ ImmutableSortedSet<InjectionSite> getInjectionSites(DeclaredType declaredType) {
+ Set<InjectionSite> injectionSites = new HashSet<>();
+ List<TypeElement> ancestors = new ArrayList<>();
+ SetMultimap<String, ExecutableElement> overriddenMethodMap = LinkedHashMultimap.create();
+ for (Optional<DeclaredType> currentType = Optional.of(declaredType);
+ currentType.isPresent();
+ currentType = types.nonObjectSuperclass(currentType.get())) {
+ DeclaredType type = currentType.get();
+ ancestors.add(MoreElements.asType(type.asElement()));
+ for (Element enclosedElement : type.asElement().getEnclosedElements()) {
+ Optional<InjectionSite> maybeInjectionSite =
+ injectionSiteVisitor.visit(enclosedElement, type);
+ if (maybeInjectionSite.isPresent()) {
+ InjectionSite injectionSite = maybeInjectionSite.get();
+ if (shouldBeInjected(injectionSite.element(), overriddenMethodMap)) {
+ injectionSites.add(injectionSite);
+ }
+ if (injectionSite.kind().equals(METHOD)) {
+ ExecutableElement injectionSiteMethod =
+ MoreElements.asExecutable(injectionSite.element());
+ overriddenMethodMap.put(
+ injectionSiteMethod.getSimpleName().toString(), injectionSiteMethod);
+ }
+ }
+ }
+ }
+ return ImmutableSortedSet.copyOf(
+ // supertypes before subtypes
+ Comparator.comparing(
+ (InjectionSite injectionSite) ->
+ ancestors.indexOf(injectionSite.element().getEnclosingElement()))
+ .reversed()
+ // fields before methods
+ .thenComparing(injectionSite -> injectionSite.element().getKind())
+ // then sort by whichever element comes first in the parent
+ // this isn't necessary, but makes the processor nice and predictable
+ .thenComparing(InjectionSite::element, DECLARATION_ORDER),
+ injectionSites);
+ }
+
+ private boolean shouldBeInjected(
+ Element injectionSite, SetMultimap<String, ExecutableElement> overriddenMethodMap) {
+ if (!isAnnotationPresent(injectionSite, Inject.class)
+ || injectionSite.getModifiers().contains(PRIVATE)
+ || injectionSite.getModifiers().contains(STATIC)) {
+ return false;
+ }
+
+ if (injectionSite.getKind().isField()) { // Inject all fields (self and ancestors)
+ return true;
+ }
+
+ // For each method with the same name belonging to any descendant class, return false if any
+ // method has already overridden the injectionSite method. To decrease the number of methods
+ // that are checked, we store the already injected methods in a SetMultimap and only
+ // check the methods with the same name.
+ ExecutableElement injectionSiteMethod = MoreElements.asExecutable(injectionSite);
+ TypeElement injectionSiteType = MoreElements.asType(injectionSite.getEnclosingElement());
+ for (ExecutableElement method :
+ overriddenMethodMap.get(injectionSiteMethod.getSimpleName().toString())) {
+ if (elements.overrides(method, injectionSiteMethod, injectionSiteType)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/java/dagger/internal/codegen/InnerSwitchingProviders.java b/java/dagger/internal/codegen/InnerSwitchingProviders.java
new file mode 100644
index 0000000..74c4366
--- /dev/null
+++ b/java/dagger/internal/codegen/InnerSwitchingProviders.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 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.squareup.javapoet.MethodSpec.constructorBuilder;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.model.RequestKind.INSTANCE;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Generates {@linkplain BindingExpression binding expressions} for a binding that is represented by
+ * an inner {@code SwitchingProvider} class.
+ */
+final class InnerSwitchingProviders extends SwitchingProviders {
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+
+ InnerSwitchingProviders(
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types) {
+ super(componentImplementation, types);
+ this.componentBindingExpressions = componentBindingExpressions;
+ this.types = types;
+ }
+
+ /**
+ * Returns the binding expression for a binding that satisfies a {@link Provider} requests with a
+ * inner {@code SwitchingProvider} class.
+ */
+ BindingExpression newBindingExpression(ContributionBinding binding) {
+ return new BindingExpression() {
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return getProviderExpression(new SwitchCase(binding, requestingClass));
+ }
+ };
+ }
+
+ @Override
+ protected TypeSpec createSwitchingProviderType(TypeSpec.Builder builder) {
+ return builder
+ .addModifiers(PRIVATE, FINAL)
+ .addField(TypeName.INT, "id", PRIVATE, FINAL)
+ .addMethod(
+ constructorBuilder()
+ .addParameter(TypeName.INT, "id")
+ .addStatement("this.id = id")
+ .build())
+ .build();
+ }
+
+ private final class SwitchCase implements SwitchingProviders.SwitchCase {
+ private final ContributionBinding binding;
+ private final ClassName requestingClass;
+
+ SwitchCase(ContributionBinding binding, ClassName requestingClass) {
+ this.binding = binding;
+ this.requestingClass = requestingClass;
+ }
+
+ @Override
+ public Key key() {
+ return binding.key();
+ }
+
+ @Override
+ public Expression getProviderExpression(ClassName switchingProviderClass, int switchId) {
+ TypeMirror instanceType = types.accessibleType(binding.contributedType(), requestingClass);
+ return Expression.create(
+ types.wrapType(instanceType, Provider.class),
+ CodeBlock.of("new $T<>($L)", switchingProviderClass, switchId));
+ }
+
+ @Override
+ public Expression getReturnExpression(ClassName switchingProviderClass) {
+ return componentBindingExpressions.getDependencyExpression(
+ bindingRequest(binding.key(), INSTANCE), switchingProviderClass);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/InstanceFactoryCreationExpression.java b/java/dagger/internal/codegen/InstanceFactoryCreationExpression.java
new file mode 100644
index 0000000..c9b26d7
--- /dev/null
+++ b/java/dagger/internal/codegen/InstanceFactoryCreationExpression.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.InstanceFactory;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import java.util.function.Supplier;
+
+/**
+ * A {@link FrameworkInstanceCreationExpression} that creates an {@link InstanceFactory} for an
+ * instance.
+ */
+final class InstanceFactoryCreationExpression implements FrameworkInstanceCreationExpression {
+
+ private final boolean nullable;
+ private final Supplier<CodeBlock> instanceExpression;
+
+ InstanceFactoryCreationExpression(Supplier<CodeBlock> instanceExpression) {
+ this(false, instanceExpression);
+ }
+
+ InstanceFactoryCreationExpression(boolean nullable, Supplier<CodeBlock> instanceExpression) {
+ this.nullable = nullable;
+ this.instanceExpression = checkNotNull(instanceExpression);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ return CodeBlock.of(
+ "$T.$L($L)",
+ InstanceFactory.class,
+ nullable ? "createNullable" : "create",
+ instanceExpression.get());
+ }
+
+ @Override
+ public boolean useInnerSwitchingProvider() {
+ return false;
+ }
+}
diff --git a/java/dagger/internal/codegen/JavacPluginModule.java b/java/dagger/internal/codegen/JavacPluginModule.java
new file mode 100644
index 0000000..bc5b66e
--- /dev/null
+++ b/java/dagger/internal/codegen/JavacPluginModule.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2017 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 dagger.internal.codegen.ValidationType.NONE;
+import static javax.tools.Diagnostic.Kind.NOTE;
+
+import com.sun.tools.javac.model.JavacElements;
+import com.sun.tools.javac.model.JavacTypes;
+import com.sun.tools.javac.util.Context;
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+/**
+ * A module that provides a {@link BindingGraphFactory} and {@link ComponentDescriptorFactory} for
+ * use in {@code javac} plugins. Requires a binding for the {@code javac} {@link Context}.
+ */
+@Module(includes = InjectBindingRegistryModule.class)
+abstract class JavacPluginModule {
+ @Provides
+ static CompilerOptions compilerOptions() {
+ return new CompilerOptions() {
+ @Override
+ boolean usesProducers() {
+ return true;
+ }
+
+ @Override
+ boolean fastInit() {
+ return false;
+ }
+
+ @Override
+ boolean formatGeneratedSource() {
+ return false;
+ }
+
+ @Override
+ boolean writeProducerNameInToken() {
+ return true;
+ }
+
+ @Override
+ Diagnostic.Kind nullableValidationKind() {
+ return NOTE;
+ }
+
+ @Override
+ Diagnostic.Kind privateMemberValidationKind() {
+ return NOTE;
+ }
+
+ @Override
+ Diagnostic.Kind staticMemberValidationKind() {
+ return NOTE;
+ }
+
+ @Override
+ boolean ignorePrivateAndStaticInjectionForComponent() {
+ return false;
+ }
+
+ @Override
+ ValidationType scopeCycleValidationType() {
+ return NONE;
+ }
+
+ @Override
+ boolean warnIfInjectionFactoryNotGeneratedUpstream() {
+ return false;
+ }
+
+ @Override
+ boolean headerCompilation() {
+ return false;
+ }
+
+ @Override
+ boolean aheadOfTimeSubcomponents() {
+ return false;
+ }
+
+ @Override
+ boolean forceUseSerializedComponentImplementations() {
+ return false;
+ }
+
+ @Override
+ boolean emitModifiableMetadataAnnotations() {
+ return false;
+ }
+
+ @Override
+ boolean useGradleIncrementalProcessing() {
+ return false;
+ }
+
+ @Override
+ ValidationType fullBindingGraphValidationType(TypeElement element) {
+ return NONE;
+ }
+
+ @Override
+ Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind() {
+ return NOTE;
+ }
+
+ @Override
+ ValidationType explicitBindingConflictsWithInjectValidationType() {
+ return NONE;
+ }
+ };
+ }
+
+ @Binds
+ abstract Messager messager(NullMessager nullMessager);
+
+ static final class NullMessager implements Messager {
+
+ @Inject
+ NullMessager() {}
+
+ @Override
+ public void printMessage(Diagnostic.Kind kind, CharSequence charSequence) {}
+
+ @Override
+ public void printMessage(Diagnostic.Kind kind, CharSequence charSequence, Element element) {}
+
+ @Override
+ public void printMessage(
+ Diagnostic.Kind kind,
+ CharSequence charSequence,
+ Element element,
+ AnnotationMirror annotationMirror) {}
+
+ @Override
+ public void printMessage(
+ Diagnostic.Kind kind,
+ CharSequence charSequence,
+ Element element,
+ AnnotationMirror annotationMirror,
+ AnnotationValue annotationValue) {}
+ }
+
+ @Provides
+ static DaggerElements daggerElements(Context javaContext) {
+ return new DaggerElements(
+ JavacElements.instance(javaContext), JavacTypes.instance(javaContext));
+ }
+
+ @Provides
+ static DaggerTypes daggerTypes(Context javaContext, DaggerElements elements) {
+ return new DaggerTypes(JavacTypes.instance(javaContext), elements);
+ }
+
+ @Binds abstract Types types(DaggerTypes daggerTypes);
+
+ private JavacPluginModule() {}
+}
diff --git a/java/dagger/internal/codegen/KeyFactory.java b/java/dagger/internal/codegen/KeyFactory.java
new file mode 100644
index 0000000..b6ac27f
--- /dev/null
+++ b/java/dagger/internal/codegen/KeyFactory.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.auto.common.MoreTypes.asExecutable;
+import static com.google.auto.common.MoreTypes.isType;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
+import static dagger.internal.codegen.MapKeys.getMapKey;
+import static dagger.internal.codegen.MapKeys.mapKeyType;
+import static dagger.internal.codegen.Optionals.firstPresent;
+import static dagger.internal.codegen.RequestKinds.extractKeyType;
+import static dagger.internal.codegen.RequestKinds.getRequestKind;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
+import static java.util.Arrays.asList;
+import static javax.lang.model.element.ElementKind.METHOD;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.Binds;
+import dagger.BindsOptionalOf;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.serialization.KeyProto;
+import dagger.model.Key;
+import dagger.model.Key.MultibindingContributionIdentifier;
+import dagger.model.RequestKind;
+import dagger.multibindings.Multibinds;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.Production;
+import dagger.producers.internal.ProductionImplementation;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+
+/** A factory for {@link Key}s. */
+final class KeyFactory {
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final TypeProtoConverter typeProtoConverter;
+ private final AnnotationProtoConverter annotationProtoConverter;
+
+ @Inject
+ KeyFactory(
+ DaggerTypes types,
+ DaggerElements elements,
+ TypeProtoConverter typeProtoConverter,
+ AnnotationProtoConverter annotationProtoConverter) {
+ this.types = checkNotNull(types);
+ this.elements = checkNotNull(elements);
+ this.typeProtoConverter = typeProtoConverter;
+ this.annotationProtoConverter = annotationProtoConverter;
+ }
+
+ private TypeMirror boxPrimitives(TypeMirror type) {
+ return type.getKind().isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type;
+ }
+
+ private DeclaredType setOf(TypeMirror elementType) {
+ return types.getDeclaredType(elements.getTypeElement(Set.class), boxPrimitives(elementType));
+ }
+
+ private DeclaredType mapOf(TypeMirror keyType, TypeMirror valueType) {
+ return types.getDeclaredType(
+ elements.getTypeElement(Map.class), boxPrimitives(keyType), boxPrimitives(valueType));
+ }
+
+ /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */
+ private TypeMirror mapOfFrameworkType(
+ TypeMirror keyType, TypeElement frameworkType, TypeMirror valueType) {
+ return mapOf(keyType, types.getDeclaredType(frameworkType, boxPrimitives(valueType)));
+ }
+
+ Key forComponentMethod(ExecutableElement componentMethod) {
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ return forMethod(componentMethod, componentMethod.getReturnType());
+ }
+
+ Key forProductionComponentMethod(ExecutableElement componentMethod) {
+ checkArgument(componentMethod.getKind().equals(METHOD));
+ TypeMirror returnType = componentMethod.getReturnType();
+ TypeMirror keyType =
+ isFutureType(returnType)
+ ? getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments())
+ : returnType;
+ return forMethod(componentMethod, keyType);
+ }
+
+ Key forSubcomponentCreatorMethod(
+ ExecutableElement subcomponentCreatorMethod, DeclaredType declaredContainer) {
+ checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD));
+ ExecutableType resolvedMethod =
+ asExecutable(types.asMemberOf(declaredContainer, subcomponentCreatorMethod));
+ return Key.builder(resolvedMethod.getReturnType()).build();
+ }
+
+ Key forSubcomponentCreator(TypeMirror creatorType) {
+ return Key.builder(creatorType).build();
+ }
+
+ Key forProvidesMethod(ExecutableElement method, TypeElement contributingModule) {
+ return forBindingMethod(
+ method, contributingModule, Optional.of(elements.getTypeElement(Provider.class)));
+ }
+
+ Key forProducesMethod(ExecutableElement method, TypeElement contributingModule) {
+ return forBindingMethod(
+ method, contributingModule, Optional.of(elements.getTypeElement(Producer.class)));
+ }
+
+ /** Returns the key bound by a {@link Binds} method. */
+ Key forBindsMethod(ExecutableElement method, TypeElement contributingModule) {
+ checkArgument(isAnnotationPresent(method, Binds.class));
+ return forBindingMethod(method, contributingModule, Optional.empty());
+ }
+
+ /** Returns the base key bound by a {@link BindsOptionalOf} method. */
+ Key forBindsOptionalOfMethod(ExecutableElement method, TypeElement contributingModule) {
+ checkArgument(isAnnotationPresent(method, BindsOptionalOf.class));
+ return forBindingMethod(method, contributingModule, Optional.empty());
+ }
+
+ private Key forBindingMethod(
+ ExecutableElement method,
+ TypeElement contributingModule,
+ Optional<TypeElement> frameworkType) {
+ checkArgument(method.getKind().equals(METHOD));
+ ExecutableType methodType =
+ MoreTypes.asExecutable(
+ types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), method));
+ ContributionType contributionType = ContributionType.fromBindingElement(method);
+ TypeMirror returnType = methodType.getReturnType();
+ if (frameworkType.isPresent()
+ && frameworkType.get().equals(elements.getTypeElement(Producer.class))
+ && isType(returnType)) {
+ if (isFutureType(methodType.getReturnType())) {
+ returnType = getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
+ } else if (contributionType.equals(ContributionType.SET_VALUES)
+ && SetType.isSet(returnType)) {
+ SetType setType = SetType.from(returnType);
+ if (isFutureType(setType.elementType())) {
+ returnType =
+ types.getDeclaredType(
+ elements.getTypeElement(Set.class), types.unwrapType(setType.elementType()));
+ }
+ }
+ }
+ TypeMirror keyType = bindingMethodKeyType(returnType, method, contributionType, frameworkType);
+ Key key = forMethod(method, keyType);
+ return contributionType.equals(ContributionType.UNIQUE)
+ ? key
+ : key.toBuilder()
+ .multibindingContributionIdentifier(
+ new MultibindingContributionIdentifier(method, contributingModule))
+ .build();
+ }
+
+ /**
+ * Returns the key for a {@link Multibinds @Multibinds} method.
+ *
+ * <p>The key's type is either {@code Set<T>} or {@code Map<K, Provider<V>>}. The latter works
+ * even for maps used by {@code Producer}s.
+ */
+ Key forMultibindsMethod(ExecutableType executableType, ExecutableElement method) {
+ checkArgument(method.getKind().equals(METHOD), "%s must be a method", method);
+ TypeMirror returnType = executableType.getReturnType();
+ TypeMirror keyType =
+ MapType.isMap(returnType)
+ ? mapOfFrameworkType(
+ MapType.from(returnType).keyType(),
+ elements.getTypeElement(Provider.class),
+ MapType.from(returnType).valueType())
+ : returnType;
+ return forMethod(method, keyType);
+ }
+
+ private TypeMirror bindingMethodKeyType(
+ TypeMirror returnType,
+ ExecutableElement method,
+ ContributionType contributionType,
+ Optional<TypeElement> frameworkType) {
+ switch (contributionType) {
+ case UNIQUE:
+ return returnType;
+ case SET:
+ return setOf(returnType);
+ case MAP:
+ TypeMirror mapKeyType = mapKeyType(getMapKey(method).get(), types);
+ return frameworkType.isPresent()
+ ? mapOfFrameworkType(mapKeyType, frameworkType.get(), returnType)
+ : mapOf(mapKeyType, returnType);
+ case SET_VALUES:
+ // TODO(gak): do we want to allow people to use "covariant return" here?
+ checkArgument(SetType.isSet(returnType));
+ return returnType;
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns the key for a binding associated with a {@link DelegateDeclaration}.
+ *
+ * <p>If {@code delegateDeclaration} is {@code @IntoMap}, transforms the {@code Map<K, V>} key
+ * from {@link DelegateDeclaration#key()} to {@code Map<K, FrameworkType<V>>}. If {@code
+ * delegateDeclaration} is not a map contribution, its key is returned.
+ */
+ Key forDelegateBinding(DelegateDeclaration delegateDeclaration, Class<?> frameworkType) {
+ return delegateDeclaration.contributionType().equals(ContributionType.MAP)
+ ? wrapMapValue(delegateDeclaration.key(), frameworkType)
+ : delegateDeclaration.key();
+ }
+
+ private Key forMethod(ExecutableElement method, TypeMirror keyType) {
+ return forQualifiedType(getQualifier(method), keyType);
+ }
+
+ Key forInjectConstructorWithResolvedType(TypeMirror type) {
+ return Key.builder(type).build();
+ }
+
+ // TODO(ronshapiro): Remove these conveniences which are simple wrappers around Key.Builder
+ Key forType(TypeMirror type) {
+ return Key.builder(type).build();
+ }
+
+ Key forMembersInjectedType(TypeMirror type) {
+ return Key.builder(type).build();
+ }
+
+ Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
+ return Key.builder(boxPrimitives(type)).qualifier(qualifier).build();
+ }
+
+ Key forProductionExecutor() {
+ return Key.builder(elements.getTypeElement(Executor.class).asType())
+ .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(Production.class)))
+ .build();
+ }
+
+ Key forProductionImplementationExecutor() {
+ return Key.builder(elements.getTypeElement(Executor.class).asType())
+ .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(ProductionImplementation.class)))
+ .build();
+ }
+
+ Key forProductionComponentMonitor() {
+ return Key.builder(elements.getTypeElement(ProductionComponentMonitor.class).asType()).build();
+ }
+
+ /**
+ * If {@code requestKey} is for a {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns keys
+ * for {@code Map<K, Provider<V>>} and {@code Map<K, Producer<V>>} (if Dagger-Producers is on
+ * the classpath).
+ */
+ ImmutableSet<Key> implicitFrameworkMapKeys(Key requestKey) {
+ return Stream.of(implicitMapProviderKeyFrom(requestKey), implicitMapProducerKeyFrom(requestKey))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Optionally extract a {@link Key} for the underlying provision binding(s) if such a valid key
+ * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code
+ * <K, V>} or {@code Map<K, Producer<V>>}, a key of {@code Map<K, Provider<V>>} will be
+ * returned.
+ */
+ Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
+ return firstPresent(
+ rewrapMapKey(possibleMapKey, Produced.class, Provider.class),
+ wrapMapKey(possibleMapKey, Provider.class));
+ }
+
+ /**
+ * Optionally extract a {@link Key} for the underlying production binding(s) if such a
+ * valid key can be inferred from the given key. Specifically, if the key represents a
+ * {@link Map}{@code <K, V>} or {@code Map<K, Produced<V>>}, a key of
+ * {@code Map<K, Producer<V>>} will be returned.
+ */
+ Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
+ return firstPresent(
+ rewrapMapKey(possibleMapKey, Produced.class, Producer.class),
+ wrapMapKey(possibleMapKey, Producer.class));
+ }
+
+ /**
+ * If {@code key}'s type is {@code Map<K, Provider<V>>}, {@code Map<K, Producer<V>>}, or {@code
+ * Map<K, Produced<V>>}, returns a key with the same qualifier and {@link
+ * Key#multibindingContributionIdentifier()} whose type is simply {@code Map<K, V>}.
+ *
+ * <p>Otherwise, returns {@code key}.
+ */
+ Key unwrapMapValueType(Key key) {
+ if (MapType.isMap(key)) {
+ MapType mapType = MapType.from(key);
+ if (!mapType.isRawType()) {
+ for (Class<?> frameworkClass : asList(Provider.class, Producer.class, Produced.class)) {
+ if (mapType.valuesAreTypeOf(frameworkClass)) {
+ return key.toBuilder()
+ .type(mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass)))
+ .build();
+ }
+ }
+ }
+ }
+ return key;
+ }
+
+ /**
+ * Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}.
+ */
+ private Key wrapMapValue(Key key, Class<?> newWrappingClass) {
+ checkArgument(
+ FrameworkTypes.isFrameworkType(elements.getTypeElement(newWrappingClass).asType()));
+ return wrapMapKey(key, newWrappingClass).get();
+ }
+
+ /**
+ * If {@code key}'s type is {@code Map<K, CurrentWrappingClass<Bar>>}, returns a key with type
+ * {@code Map<K, NewWrappingClass<Bar>>} with the same qualifier. Otherwise returns {@link
+ * Optional#empty()}.
+ *
+ * <p>Returns {@link Optional#empty()} if {@code newWrappingClass} is not in the classpath.
+ *
+ * @throws IllegalArgumentException if {@code newWrappingClass} is the same as {@code
+ * currentWrappingClass}
+ */
+ Optional<Key> rewrapMapKey(
+ Key possibleMapKey, Class<?> currentWrappingClass, Class<?> newWrappingClass) {
+ checkArgument(!currentWrappingClass.equals(newWrappingClass));
+ if (MapType.isMap(possibleMapKey)) {
+ MapType mapType = MapType.from(possibleMapKey);
+ if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClass)) {
+ TypeElement wrappingElement = elements.getTypeElement(newWrappingClass);
+ if (wrappingElement == null) {
+ // This target might not be compiled with Producers, so wrappingClass might not have an
+ // associated element.
+ return Optional.empty();
+ }
+ DeclaredType wrappedValueType =
+ types.getDeclaredType(
+ wrappingElement, mapType.unwrappedValueType(currentWrappingClass));
+ return Optional.of(
+ possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build());
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * If {@code key}'s type is {@code Map<K, Foo>} and {@code Foo} is not {@code WrappingClass
+ * <Bar>}, returns a key with type {@code Map<K, WrappingClass<Foo>>} with the same qualifier.
+ * Otherwise returns {@link Optional#empty()}.
+ *
+ * <p>Returns {@link Optional#empty()} if {@code WrappingClass} is not in the classpath.
+ */
+ private Optional<Key> wrapMapKey(Key possibleMapKey, Class<?> wrappingClass) {
+ if (MapType.isMap(possibleMapKey)) {
+ MapType mapType = MapType.from(possibleMapKey);
+ if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClass)) {
+ TypeElement wrappingElement = elements.getTypeElement(wrappingClass);
+ if (wrappingElement == null) {
+ // This target might not be compiled with Producers, so wrappingClass might not have an
+ // associated element.
+ return Optional.empty();
+ }
+ DeclaredType wrappedValueType = types.getDeclaredType(wrappingElement, mapType.valueType());
+ return Optional.of(
+ possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build());
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * If {@code key}'s type is {@code Set<WrappingClass<Bar>>}, returns a key with type {@code Set
+ * <Bar>} with the same qualifier. Otherwise returns {@link Optional#empty()}.
+ */
+ Optional<Key> unwrapSetKey(Key key, Class<?> wrappingClass) {
+ if (SetType.isSet(key)) {
+ SetType setType = SetType.from(key);
+ if (!setType.isRawType() && setType.elementsAreTypeOf(wrappingClass)) {
+ return Optional.of(
+ key.toBuilder().type(setOf(setType.unwrappedElementType(wrappingClass))).build());
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * If {@code key}'s type is {@code Optional<T>} for some {@code T}, returns a key with the same
+ * qualifier whose type is {@linkplain RequestKinds#extractKeyType(RequestKind, TypeMirror)}
+ * extracted} from {@code T}.
+ */
+ Optional<Key> unwrapOptional(Key key) {
+ if (!OptionalType.isOptional(key)) {
+ return Optional.empty();
+ }
+
+ TypeMirror optionalValueType = OptionalType.from(key).valueType();
+ return Optional.of(
+ key.toBuilder()
+ .type(extractKeyType(getRequestKind(optionalValueType), optionalValueType))
+ .build());
+ }
+
+ /** Translates a {@link Key} to a proto representation. */
+ static KeyProto toProto(Key key) {
+ KeyProto.Builder builder =
+ KeyProto.newBuilder().setType(TypeProtoConverter.toProto(key.type()));
+ key.qualifier().map(AnnotationProtoConverter::toProto).ifPresent(builder::setQualifier);
+ key.multibindingContributionIdentifier()
+ .ifPresent(
+ mci ->
+ builder
+ .getMultibindingContributionIdentifierBuilder()
+ .setModule(mci.module())
+ .setBindingElement(mci.bindingElement()));
+ return builder.build();
+ }
+
+ /** Creates a {@link Key} from its proto representation. */
+ Key fromProto(KeyProto key) {
+ Key.Builder builder = Key.builder(typeProtoConverter.fromProto(key.getType()));
+ if (key.hasQualifier()) {
+ builder.qualifier(annotationProtoConverter.fromProto(key.getQualifier()));
+ }
+ if (key.hasMultibindingContributionIdentifier()) {
+ KeyProto.MultibindingContributionIdentifier multibindingContributionIdentifier =
+ key.getMultibindingContributionIdentifier();
+ builder.multibindingContributionIdentifier(
+ new MultibindingContributionIdentifier(
+ multibindingContributionIdentifier.getBindingElement(),
+ multibindingContributionIdentifier.getModule()));
+ }
+ return builder.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/KeyVariableNamer.java b/java/dagger/internal/codegen/KeyVariableNamer.java
new file mode 100644
index 0000000..407f208
--- /dev/null
+++ b/java/dagger/internal/codegen/KeyVariableNamer.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static dagger.internal.codegen.SourceFiles.protectAgainstKeywords;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import java.util.Iterator;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * Suggests a variable name for a type based on a {@link Key}. Prefer {@link
+ * DependencyVariableNamer} for cases where a specific {@link DependencyRequest} is present.
+ */
+final class KeyVariableNamer {
+ /** Simple names that are very common. Inspired by https://errorprone.info/bugpattern/BadImport */
+ private static final ImmutableSet<String> VERY_SIMPLE_NAMES =
+ ImmutableSet.of(
+ "Builder",
+ "Factory",
+ "Component",
+ "Subcomponent",
+ "Injector");
+
+ private static final TypeVisitor<Void, StringBuilder> TYPE_NAMER =
+ new SimpleTypeVisitor8<Void, StringBuilder>() {
+ @Override
+ public Void visitDeclared(DeclaredType declaredType, StringBuilder builder) {
+ TypeElement element = MoreTypes.asTypeElement(declaredType);
+ if (element.getNestingKind().isNested()
+ && VERY_SIMPLE_NAMES.contains(element.getSimpleName().toString())) {
+ builder.append(element.getEnclosingElement().getSimpleName());
+ }
+
+ builder.append(element.getSimpleName());
+ Iterator<? extends TypeMirror> argumentIterator =
+ declaredType.getTypeArguments().iterator();
+ if (argumentIterator.hasNext()) {
+ builder.append("Of");
+ TypeMirror first = argumentIterator.next();
+ first.accept(this, builder);
+ while (argumentIterator.hasNext()) {
+ builder.append("And");
+ argumentIterator.next().accept(this, builder);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Void visitPrimitive(PrimitiveType type, StringBuilder builder) {
+ builder.append(LOWER_CAMEL.to(UPPER_CAMEL, type.toString()));
+ return null;
+ }
+
+ @Override
+ public Void visitArray(ArrayType type, StringBuilder builder) {
+ type.getComponentType().accept(this, builder);
+ builder.append("Array");
+ return null;
+ }
+ };
+
+ private KeyVariableNamer() {}
+
+ static String name(Key key) {
+ if (key.multibindingContributionIdentifier().isPresent()) {
+ return key.multibindingContributionIdentifier().get().bindingElement();
+ }
+
+ StringBuilder builder = new StringBuilder();
+
+ if (key.qualifier().isPresent()) {
+ // TODO(gak): Use a better name for fields with qualifiers with members.
+ builder.append(key.qualifier().get().getAnnotationType().asElement().getSimpleName());
+ }
+
+ key.type().accept(TYPE_NAMER, builder);
+
+ return protectAgainstKeywords(UPPER_CAMEL.to(LOWER_CAMEL, builder.toString()));
+ }
+}
diff --git a/java/dagger/internal/codegen/Keys.java b/java/dagger/internal/codegen/Keys.java
new file mode 100644
index 0000000..670fda7
--- /dev/null
+++ b/java/dagger/internal/codegen/Keys.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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 com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+/** Utility methods related to {@link Key}s. */
+final class Keys {
+ static boolean isValidMembersInjectionKey(Key key) {
+ return !key.qualifier().isPresent()
+ && !key.multibindingContributionIdentifier().isPresent()
+ && key.type().getKind().equals(TypeKind.DECLARED);
+ }
+
+ /**
+ * Returns {@code true} if this is valid as an implicit key (that is, if it's valid for a
+ * just-in-time binding by discovering an {@code @Inject} constructor).
+ */
+ static boolean isValidImplicitProvisionKey(Key key, DaggerTypes types) {
+ return isValidImplicitProvisionKey(key.qualifier(), key.type(), types);
+ }
+
+ /**
+ * Returns {@code true} if a key with {@code qualifier} and {@code type} is valid as an implicit
+ * key (that is, if it's valid for a just-in-time binding by discovering an {@code @Inject}
+ * constructor).
+ */
+ static boolean isValidImplicitProvisionKey(
+ Optional<? extends AnnotationMirror> qualifier, TypeMirror type, final DaggerTypes types) {
+ // Qualifiers disqualify implicit provisioning.
+ if (qualifier.isPresent()) {
+ return false;
+ }
+
+ return type.accept(
+ new SimpleTypeVisitor6<Boolean, Void>(false) {
+ @Override
+ public Boolean visitDeclared(DeclaredType type, Void ignored) {
+ // Non-classes or abstract classes aren't allowed.
+ TypeElement element = MoreElements.asType(type.asElement());
+ if (!element.getKind().equals(ElementKind.CLASS)
+ || element.getModifiers().contains(Modifier.ABSTRACT)) {
+ return false;
+ }
+
+ // If the key has type arguments, validate that each type argument is declared.
+ // Otherwise the type argument may be a wildcard (or other type), and we can't
+ // resolve that to actual types.
+ for (TypeMirror arg : type.getTypeArguments()) {
+ if (arg.getKind() != TypeKind.DECLARED) {
+ return false;
+ }
+ }
+
+ // Also validate that the key is not the erasure of a generic type.
+ // If it is, that means the user referred to Foo<T> as just 'Foo',
+ // which we don't allow. (This is a judgement call -- we *could*
+ // allow it and instantiate the type bounds... but we don't.)
+ return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
+ || !types.isSameType(types.erasure(element.asType()), type);
+ }
+ },
+ null);
+ }
+}
diff --git a/java/dagger/internal/codegen/MapBindingExpression.java b/java/dagger/internal/codegen/MapBindingExpression.java
new file mode 100644
index 0000000..526c493
--- /dev/null
+++ b/java/dagger/internal/codegen/MapBindingExpression.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.MapBuilder;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import java.util.Collections;
+import java.util.Optional;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/** A {@link BindingExpression} for multibound maps. */
+final class MapBindingExpression extends MultibindingExpression {
+ /** Maximum number of key-value pairs that can be passed to ImmutableMap.of(K, V, K, V, ...). */
+ private static final int MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS = 5;
+
+ private final ProvisionBinding binding;
+ private final ImmutableMap<DependencyRequest, ContributionBinding> dependencies;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ MapBindingExpression(
+ ResolvedBindings resolvedBindings,
+ ComponentImplementation componentImplementation,
+ BindingGraph graph,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types,
+ DaggerElements elements) {
+ super(resolvedBindings, componentImplementation);
+ this.binding = (ProvisionBinding) resolvedBindings.contributionBinding();
+ BindingKind bindingKind = this.binding.kind();
+ checkArgument(bindingKind.equals(MULTIBOUND_MAP), bindingKind);
+ this.componentBindingExpressions = componentBindingExpressions;
+ this.types = types;
+ this.elements = elements;
+ this.dependencies =
+ Maps.toMap(
+ binding.dependencies(),
+ dep -> graph.contributionBindings().get(dep.key()).contributionBinding());
+ }
+
+ @Override
+ protected Expression buildDependencyExpression(ClassName requestingClass) {
+ Optional<CodeBlock> superMethodCall = superMethodCall();
+ // TODO(ronshapiro): We should also make an ImmutableMap version of MapFactory
+ boolean isImmutableMapAvailable = isImmutableMapAvailable();
+ // TODO(ronshapiro, gak): Use Maps.immutableEnumMap() if it's available?
+ if (isImmutableMapAvailable
+ && dependencies.size() <= MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS
+ && !superMethodCall.isPresent()) {
+ return Expression.create(
+ immutableMapType(),
+ CodeBlock.builder()
+ .add("$T.", ImmutableMap.class)
+ .add(maybeTypeParameters(requestingClass))
+ .add(
+ "of($L)",
+ dependencies
+ .keySet()
+ .stream()
+ .map(dependency -> keyAndValueExpression(dependency, requestingClass))
+ .collect(toParametersCodeBlock()))
+ .build());
+ }
+ switch (dependencies.size()) {
+ case 0:
+ return collectionsStaticFactoryInvocation(requestingClass, CodeBlock.of("emptyMap()"));
+ case 1:
+ return collectionsStaticFactoryInvocation(
+ requestingClass,
+ CodeBlock.of(
+ "singletonMap($L)",
+ keyAndValueExpression(getOnlyElement(dependencies.keySet()), requestingClass)));
+ default:
+ CodeBlock.Builder instantiation = CodeBlock.builder();
+ instantiation
+ .add("$T.", isImmutableMapAvailable ? ImmutableMap.class : MapBuilder.class)
+ .add(maybeTypeParameters(requestingClass));
+ if (isImmutableMapBuilderWithExpectedSizeAvailable()) {
+ instantiation.add("builderWithExpectedSize($L)", dependencies.size());
+ } else if (isImmutableMapAvailable) {
+ instantiation.add("builder()");
+ } else {
+ instantiation.add("newMapBuilder($L)", dependencies.size());
+ }
+ for (DependencyRequest dependency : getNewContributions(dependencies.keySet())) {
+ instantiation.add(".put($L)", keyAndValueExpression(dependency, requestingClass));
+ }
+ if (superMethodCall.isPresent()) {
+ instantiation.add(CodeBlock.of(".putAll($L)", superMethodCall.get()));
+ }
+ return Expression.create(
+ isImmutableMapAvailable ? immutableMapType() : binding.key().type(),
+ instantiation.add(".build()").build());
+ }
+ }
+
+ private DeclaredType immutableMapType() {
+ MapType mapType = MapType.from(binding.key());
+ return types.getDeclaredType(
+ elements.getTypeElement(ImmutableMap.class), mapType.keyType(), mapType.valueType());
+ }
+
+ private CodeBlock keyAndValueExpression(DependencyRequest dependency, ClassName requestingClass) {
+ return CodeBlock.of(
+ "$L, $L",
+ getMapKeyExpression(dependencies.get(dependency), requestingClass, elements),
+ componentBindingExpressions
+ .getDependencyExpression(bindingRequest(dependency), requestingClass)
+ .codeBlock());
+ }
+
+ private Expression collectionsStaticFactoryInvocation(
+ ClassName requestingClass, CodeBlock methodInvocation) {
+ return Expression.create(
+ binding.key().type(),
+ CodeBlock.builder()
+ .add("$T.", Collections.class)
+ .add(maybeTypeParameters(requestingClass))
+ .add(methodInvocation)
+ .build());
+ }
+
+ private CodeBlock maybeTypeParameters(ClassName requestingClass) {
+ TypeMirror bindingKeyType = binding.key().type();
+ MapType mapType = MapType.from(binding.key());
+ return isTypeAccessibleFrom(bindingKeyType, requestingClass.packageName())
+ ? CodeBlock.of("<$T, $T>", mapType.keyType(), mapType.valueType())
+ : CodeBlock.of("");
+ }
+
+ private boolean isImmutableMapBuilderWithExpectedSizeAvailable() {
+ if (isImmutableMapAvailable()) {
+ return methodsIn(elements.getTypeElement(ImmutableMap.class).getEnclosedElements())
+ .stream()
+ .anyMatch(method -> method.getSimpleName().contentEquals("builderWithExpectedSize"));
+ }
+ return false;
+ }
+
+ private boolean isImmutableMapAvailable() {
+ return elements.getTypeElement(ImmutableMap.class) != null;
+ }
+}
diff --git a/java/dagger/internal/codegen/MapFactoryCreationExpression.java b/java/dagger/internal/codegen/MapFactoryCreationExpression.java
new file mode 100644
index 0000000..187b792
--- /dev/null
+++ b/java/dagger/internal/codegen/MapFactoryCreationExpression.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.MapKeys.getMapKeyExpression;
+import static dagger.internal.codegen.SourceFiles.mapFactoryClassName;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.model.DependencyRequest;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/** A factory creation expression for a multibound map. */
+final class MapFactoryCreationExpression extends MultibindingFactoryCreationExpression {
+
+ private final ComponentImplementation componentImplementation;
+ private final BindingGraph graph;
+ private final ContributionBinding binding;
+ private final DaggerElements elements;
+
+ MapFactoryCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions,
+ BindingGraph graph,
+ DaggerElements elements) {
+ super(binding, componentImplementation, componentBindingExpressions);
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.graph = checkNotNull(graph);
+ this.elements = checkNotNull(elements);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ CodeBlock.Builder builder = CodeBlock.builder().add("$T.", mapFactoryClassName(binding));
+ if (!useRawType()) {
+ MapType mapType = MapType.from(binding.key().type());
+ // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
+ // mapType.unwrappedValueType() method that doesn't require a framework type
+ TypeMirror valueType = mapType.valueType();
+ for (Class<?> frameworkClass :
+ ImmutableSet.of(Provider.class, Producer.class, Produced.class)) {
+ if (mapType.valuesAreTypeOf(frameworkClass)) {
+ valueType = mapType.unwrappedValueType(frameworkClass);
+ break;
+ }
+ }
+ builder.add("<$T, $T>", mapType.keyType(), valueType);
+ }
+
+ builder.add("builder($L)", binding.dependencies().size());
+
+ superContributions()
+ .ifPresent(superContributions -> builder.add(".putAll($L)", superContributions));
+
+ for (DependencyRequest dependency : dependenciesToImplement()) {
+ ContributionBinding contributionBinding =
+ graph.contributionBindings().get(dependency.key()).contributionBinding();
+ builder.add(
+ ".put($L, $L)",
+ getMapKeyExpression(contributionBinding, componentImplementation.name(), elements),
+ multibindingDependencyExpression(dependency));
+ }
+ builder.add(".build()");
+
+ componentImplementation.registerImplementedMultibinding(binding, bindingRequest());
+
+ return builder.build();
+ }
+}
diff --git a/java/dagger/internal/codegen/MapKeyAccessibility.java b/java/dagger/internal/codegen/MapKeyAccessibility.java
new file mode 100644
index 0000000..ce27877
--- /dev/null
+++ b/java/dagger/internal/codegen/MapKeyAccessibility.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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 dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import dagger.internal.codegen.langmodel.Accessibility;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Predicate;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+
+final class MapKeyAccessibility extends SimpleAnnotationValueVisitor8<Boolean, Void> {
+ private final Predicate<TypeMirror> accessibilityChecker;
+
+ private MapKeyAccessibility(Predicate<TypeMirror> accessibilityChecker) {
+ this.accessibilityChecker = accessibilityChecker;
+ }
+
+ @Override
+ public Boolean visitAnnotation(AnnotationMirror annotation, Void aVoid) {
+ // The annotation type is not checked, as the generated code will refer to the @AutoAnnotation
+ // generated type which is always public
+ return visitValues(annotation.getElementValues().values());
+ }
+
+ @Override
+ public Boolean visitArray(List<? extends AnnotationValue> values, Void aVoid) {
+ return visitValues(values);
+ }
+
+ private boolean visitValues(Collection<? extends AnnotationValue> values) {
+ return values.stream().allMatch(value -> value.accept(this, null));
+ }
+
+ @Override
+ public Boolean visitEnumConstant(VariableElement enumConstant, Void aVoid) {
+ return accessibilityChecker.test(enumConstant.getEnclosingElement().asType());
+ }
+
+ @Override
+ public Boolean visitType(TypeMirror type, Void aVoid) {
+ return accessibilityChecker.test(type);
+ }
+
+ @Override
+ protected Boolean defaultAction(Object o, Void aVoid) {
+ return true;
+ }
+
+ static boolean isMapKeyAccessibleFrom(AnnotationMirror annotation, String accessingPackage) {
+ return new MapKeyAccessibility(type -> isTypeAccessibleFrom(type, accessingPackage))
+ .visitAnnotation(annotation, null);
+ }
+
+ static boolean isMapKeyPubliclyAccessible(AnnotationMirror annotation) {
+ return new MapKeyAccessibility(Accessibility::isTypePubliclyAccessible)
+ .visitAnnotation(annotation, null);
+ }
+}
diff --git a/java/dagger/internal/codegen/MapKeyProcessingStep.java b/java/dagger/internal/codegen/MapKeyProcessingStep.java
index 50693da..19975a7 100644
--- a/java/dagger/internal/codegen/MapKeyProcessingStep.java
+++ b/java/dagger/internal/codegen/MapKeyProcessingStep.java
@@ -16,7 +16,7 @@
package dagger.internal.codegen;
-import static dagger.internal.codegen.binding.MapKeys.getUnwrappedMapKeyType;
+import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
import static javax.lang.model.element.ElementKind.ANNOTATION_TYPE;
import com.google.auto.common.MoreElements;
@@ -24,11 +24,6 @@
import com.google.common.collect.ImmutableSet;
import dagger.MapKey;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.validation.MapKeyValidator;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
-import dagger.internal.codegen.writing.AnnotationCreatorGenerator;
-import dagger.internal.codegen.writing.UnwrappedMapKeyGenerator;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.annotation.processing.Messager;
@@ -42,7 +37,7 @@
* The annotation processor responsible for validating the mapKey annotation and auto-generate
* implementation of annotations marked with {@link MapKey @MapKey} where necessary.
*/
-final class MapKeyProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
+public class MapKeyProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
private final Messager messager;
private final DaggerTypes types;
private final MapKeyValidator mapKeyValidator;
diff --git a/java/dagger/internal/codegen/MapKeyValidator.java b/java/dagger/internal/codegen/MapKeyValidator.java
new file mode 100644
index 0000000..f2568ef
--- /dev/null
+++ b/java/dagger/internal/codegen/MapKeyValidator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 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 javax.lang.model.util.ElementFilter.methodsIn;
+
+import dagger.MapKey;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.List;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+
+/**
+ * A validator for {@link MapKey} annotations.
+ */
+// TODO(dpb,gak): Should unwrapped MapKeys be required to have their single member be named "value"?
+final class MapKeyValidator {
+ private final DaggerElements elements;
+
+ @Inject
+ MapKeyValidator(DaggerElements elements) {
+ this.elements = elements;
+ }
+
+ ValidationReport<Element> validate(Element element) {
+ ValidationReport.Builder<Element> builder = ValidationReport.about(element);
+ List<ExecutableElement> members = methodsIn(((TypeElement) element).getEnclosedElements());
+ if (members.isEmpty()) {
+ builder.addError("Map key annotations must have members", element);
+ } else if (element.getAnnotation(MapKey.class).unwrapValue()) {
+ if (members.size() > 1) {
+ builder.addError(
+ "Map key annotations with unwrapped values must have exactly one member", element);
+ } else if (members.get(0).getReturnType().getKind() == TypeKind.ARRAY) {
+ builder.addError("Map key annotations with unwrapped values cannot use arrays", element);
+ }
+ } else if (autoAnnotationIsMissing()) {
+ builder.addError(
+ "@AutoAnnotation is a necessary dependency if @MapKey(unwrapValue = false). Add a "
+ + "dependency on com.google.auto.value:auto-value:<current version>");
+ }
+ return builder.build();
+ }
+
+ private boolean autoAnnotationIsMissing() {
+ return elements.getTypeElement("com.google.auto.value.AutoAnnotation") == null;
+ }
+}
diff --git a/java/dagger/internal/codegen/MapKeys.java b/java/dagger/internal/codegen/MapKeys.java
new file mode 100644
index 0000000..d8da6af
--- /dev/null
+++ b/java/dagger/internal/codegen/MapKeys.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.MapKeyAccessibility.isMapKeyPubliclyAccessible;
+import static dagger.internal.codegen.SourceFiles.elementBasedClassName;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.MapKey;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleTypeVisitor6;
+
+/**
+ * Methods for extracting {@link MapKey} annotations and key code blocks from binding elements.
+ */
+final class MapKeys {
+
+ /**
+ * If {@code bindingElement} is annotated with a {@link MapKey} annotation, returns it.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
+ * annotation
+ */
+ static Optional<AnnotationMirror> getMapKey(Element bindingElement) {
+ ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(bindingElement);
+ return mapKeys.isEmpty()
+ ? Optional.empty()
+ : Optional.<AnnotationMirror>of(getOnlyElement(mapKeys));
+ }
+
+ /**
+ * Returns all of the {@link MapKey} annotations that annotate {@code bindingElement}.
+ */
+ static ImmutableSet<? extends AnnotationMirror> getMapKeys(Element bindingElement) {
+ return getAnnotatedAnnotations(bindingElement, MapKey.class);
+ }
+
+ /**
+ * Returns the annotation value if {@code mapKey}'s type is annotated with
+ * {@link MapKey @MapKey(unwrapValue = true)}.
+ *
+ * @throws IllegalArgumentException if {@code mapKey}'s type is not annotated with
+ * {@link MapKey @MapKey} at all.
+ */
+ static Optional<? extends AnnotationValue> unwrapValue(AnnotationMirror mapKey) {
+ MapKey mapKeyAnnotation = mapKey.getAnnotationType().asElement().getAnnotation(MapKey.class);
+ checkArgument(
+ mapKeyAnnotation != null, "%s is not annotated with @MapKey", mapKey.getAnnotationType());
+ return mapKeyAnnotation.unwrapValue()
+ ? Optional.of(getOnlyElement(getAnnotationValuesWithDefaults(mapKey).values()))
+ : Optional.empty();
+ }
+
+ static TypeMirror mapKeyType(AnnotationMirror mapKeyAnnotation, DaggerTypes types) {
+ return unwrapValue(mapKeyAnnotation).isPresent()
+ ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
+ : mapKeyAnnotation.getAnnotationType();
+ }
+
+ /**
+ * Returns the map key type for an unwrapped {@link MapKey} annotation type. If the single member
+ * type is primitive, returns the boxed type.
+ *
+ * @throws IllegalArgumentException if {@code mapKeyAnnotationType} is not an annotation type or
+ * has more than one member, or if its single member is an array
+ * @throws NoSuchElementException if the annotation has no members
+ */
+ static DeclaredType getUnwrappedMapKeyType(
+ final DeclaredType mapKeyAnnotationType, final DaggerTypes types) {
+ checkArgument(
+ MoreTypes.asTypeElement(mapKeyAnnotationType).getKind() == ElementKind.ANNOTATION_TYPE,
+ "%s is not an annotation type",
+ mapKeyAnnotationType);
+
+ final ExecutableElement onlyElement =
+ getOnlyElement(methodsIn(mapKeyAnnotationType.asElement().getEnclosedElements()));
+
+ SimpleTypeVisitor6<DeclaredType, Void> keyTypeElementVisitor =
+ new SimpleTypeVisitor6<DeclaredType, Void>() {
+
+ @Override
+ public DeclaredType visitArray(ArrayType t, Void p) {
+ throw new IllegalArgumentException(
+ mapKeyAnnotationType + "." + onlyElement.getSimpleName() + " cannot be an array");
+ }
+
+ @Override
+ public DeclaredType visitPrimitive(PrimitiveType t, Void p) {
+ return MoreTypes.asDeclared(types.boxedClass(t).asType());
+ }
+
+ @Override
+ public DeclaredType visitDeclared(DeclaredType t, Void p) {
+ return t;
+ }
+ };
+ return keyTypeElementVisitor.visit(onlyElement.getReturnType());
+ }
+
+ /**
+ * Returns a code block for {@code binding}'s {@link ContributionBinding#mapKeyAnnotation() map
+ * key}. If for whatever reason the map key is not accessible from within {@code requestingClass}
+ * (i.e. it has a package-private {@code enum} from a different package), this will return an
+ * invocation of a proxy-method giving it access.
+ *
+ * @throws IllegalStateException if {@code binding} is not a {@link dagger.multibindings.IntoMap
+ * map} contribution.
+ */
+ static CodeBlock getMapKeyExpression(
+ ContributionBinding binding, ClassName requestingClass, DaggerElements elements) {
+ AnnotationMirror mapKeyAnnotation = binding.mapKeyAnnotation().get();
+ return MapKeyAccessibility.isMapKeyAccessibleFrom(
+ mapKeyAnnotation, requestingClass.packageName())
+ ? directMapKeyExpression(mapKeyAnnotation, elements)
+ : CodeBlock.of("$T.create()", mapKeyProxyClassName(binding));
+ }
+
+ /**
+ * Returns a code block for the map key annotation {@code mapKey}.
+ *
+ * <p>This method assumes the map key will be accessible in the context that the returned {@link
+ * CodeBlock} is used. Use {@link #getMapKeyExpression(ContributionBinding, ClassName,
+ * DaggerElements)} when that assumption is not guaranteed.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
+ * annotation
+ * @throws IllegalStateException if {@code bindingElement} is not annotated with a {@code MapKey}
+ * annotation
+ */
+ private static CodeBlock directMapKeyExpression(
+ AnnotationMirror mapKey, DaggerElements elements) {
+ Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
+ AnnotationExpression annotationExpression = new AnnotationExpression(mapKey);
+
+ if (MoreTypes.asTypeElement(mapKey.getAnnotationType())
+ .getQualifiedName()
+ .contentEquals("dagger.android.AndroidInjectionKey")) {
+ TypeElement unwrappedType =
+ elements.checkTypePresent((String) unwrappedValue.get().getValue());
+ return CodeBlock.of(
+ "$T.of($S)",
+ ClassName.get("dagger.android.internal", "AndroidInjectionKeys"),
+ ClassName.get(unwrappedType).reflectionName());
+ }
+
+ if (unwrappedValue.isPresent()) {
+ TypeMirror unwrappedValueType =
+ getOnlyElement(getAnnotationValuesWithDefaults(mapKey).keySet()).getReturnType();
+ return annotationExpression.getValueExpression(unwrappedValueType, unwrappedValue.get());
+ } else {
+ return annotationExpression.getAnnotationInstanceExpression();
+ }
+ }
+
+ /**
+ * Returns the {@link ClassName} in which {@link #mapKeyFactoryMethod(ContributionBinding,
+ * DaggerTypes, DaggerElements)} is generated.
+ */
+ static ClassName mapKeyProxyClassName(ContributionBinding binding) {
+ return elementBasedClassName(
+ MoreElements.asExecutable(binding.bindingElement().get()), "MapKey");
+ }
+
+ /**
+ * A {@code static create()} method to be added to {@link
+ * #mapKeyProxyClassName(ContributionBinding)} when the {@code @MapKey} annotation is not publicly
+ * accessible.
+ */
+ static Optional<MethodSpec> mapKeyFactoryMethod(
+ ContributionBinding binding, DaggerTypes types, DaggerElements elements) {
+ return binding
+ .mapKeyAnnotation()
+ .filter(mapKey -> !isMapKeyPubliclyAccessible(mapKey))
+ .map(
+ mapKey ->
+ methodBuilder("create")
+ .addModifiers(PUBLIC, STATIC)
+ .returns(TypeName.get(mapKeyType(mapKey, types)))
+ .addStatement("return $L", directMapKeyExpression(mapKey, elements))
+ .build());
+ }
+
+ private MapKeys() {}
+}
diff --git a/java/dagger/internal/codegen/MapMultibindingValidator.java b/java/dagger/internal/codegen/MapMultibindingValidator.java
new file mode 100644
index 0000000..346d271
--- /dev/null
+++ b/java/dagger/internal/codegen/MapMultibindingValidator.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Multimaps.filterKeys;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSetMultimap;
+import static dagger.internal.codegen.Formatter.INDENT;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import dagger.model.BindingGraph;
+import dagger.model.Key;
+import dagger.producers.Producer;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.lang.model.type.DeclaredType;
+
+/**
+ * Reports an error for any map binding with either more than one contribution with the same map key
+ * or contributions with inconsistent map key annotation types.
+ */
+final class MapMultibindingValidator implements BindingGraphPlugin {
+
+ private final BindingDeclarationFormatter bindingDeclarationFormatter;
+ private final KeyFactory keyFactory;
+
+ @Inject
+ MapMultibindingValidator(
+ BindingDeclarationFormatter bindingDeclarationFormatter, KeyFactory keyFactory) {
+ this.bindingDeclarationFormatter = bindingDeclarationFormatter;
+ this.keyFactory = keyFactory;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/MapKeys";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ mapMultibindings(bindingGraph)
+ .forEach(
+ binding -> {
+ ImmutableSet<ContributionBinding> contributions =
+ mapBindingContributions(binding, bindingGraph);
+ checkForDuplicateMapKeys(binding, contributions, diagnosticReporter);
+ checkForInconsistentMapKeyAnnotationTypes(binding, contributions, diagnosticReporter);
+ });
+ }
+
+ /**
+ * Returns the map multibindings in the binding graph. If a graph contains bindings for more than
+ * one of the following for the same {@code K} and {@code V}, then only the first one found will
+ * be returned so we don't report the same map contribution problem more than once.
+ *
+ * <ol>
+ * <li>{@code Map<K, V>}
+ * <li>{@code Map<K, Provider<V>>}
+ * <li>{@code Map<K, Producer<V>>}
+ * </ol>
+ */
+ private ImmutableSet<dagger.model.Binding> mapMultibindings(BindingGraph bindingGraph) {
+ ImmutableSetMultimap<Key, dagger.model.Binding> mapMultibindings =
+ bindingGraph.bindings().stream()
+ .filter(node -> node.kind().equals(MULTIBOUND_MAP))
+ .collect(toImmutableSetMultimap(dagger.model.Binding::key, node -> node));
+
+ // Mutlbindings for Map<K, V>
+ SetMultimap<Key, dagger.model.Binding> plainValueMapMultibindings =
+ filterKeys(mapMultibindings, key -> !MapType.from(key).valuesAreFrameworkType());
+
+ // Multibindings for Map<K, Provider<V>> where Map<K, V> isn't in plainValueMapMultibindings
+ SetMultimap<Key, dagger.model.Binding> providerValueMapMultibindings =
+ filterKeys(
+ mapMultibindings,
+ key ->
+ MapType.from(key).valuesAreTypeOf(Provider.class)
+ && !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key)));
+
+ // Multibindings for Map<K, Producer<V>> where Map<K, V> isn't in plainValueMapMultibindings and
+ // Map<K, Provider<V>> isn't in providerValueMapMultibindings
+ SetMultimap<Key, dagger.model.Binding> producerValueMapMultibindings =
+ filterKeys(
+ mapMultibindings,
+ key ->
+ MapType.from(key).valuesAreTypeOf(Producer.class)
+ && !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key))
+ && !providerValueMapMultibindings.containsKey(
+ keyFactory.rewrapMapKey(key, Producer.class, Provider.class).get()));
+
+ return new ImmutableSet.Builder<dagger.model.Binding>()
+ .addAll(plainValueMapMultibindings.values())
+ .addAll(providerValueMapMultibindings.values())
+ .addAll(producerValueMapMultibindings.values())
+ .build();
+ }
+
+ private ImmutableSet<ContributionBinding> mapBindingContributions(
+ dagger.model.Binding binding, BindingGraph bindingGraph) {
+ checkArgument(binding.kind().equals(MULTIBOUND_MAP));
+ return bindingGraph.requestedBindings(binding).stream()
+ .map(b -> (BindingNode) b)
+ .map(b -> (ContributionBinding) b.delegate())
+ .collect(toImmutableSet());
+ }
+
+ private void checkForDuplicateMapKeys(
+ dagger.model.Binding multiboundMapBinding,
+ ImmutableSet<ContributionBinding> contributions,
+ DiagnosticReporter diagnosticReporter) {
+ ImmutableSetMultimap<Object, ContributionBinding> contributionsByMapKey =
+ ImmutableSetMultimap.copyOf(Multimaps.index(contributions, ContributionBinding::mapKey));
+
+ for (Set<ContributionBinding> contributionsForOneMapKey :
+ Multimaps.asMap(contributionsByMapKey).values()) {
+ if (contributionsForOneMapKey.size() > 1) {
+ diagnosticReporter.reportBinding(
+ ERROR,
+ multiboundMapBinding,
+ duplicateMapKeyErrorMessage(contributionsForOneMapKey, multiboundMapBinding.key()));
+ }
+ }
+ }
+
+ private void checkForInconsistentMapKeyAnnotationTypes(
+ dagger.model.Binding multiboundMapBinding,
+ ImmutableSet<ContributionBinding> contributions,
+ DiagnosticReporter diagnosticReporter) {
+ ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ contributionsByMapKeyAnnotationType = indexByMapKeyAnnotationType(contributions);
+
+ if (contributionsByMapKeyAnnotationType.keySet().size() > 1) {
+ diagnosticReporter.reportBinding(
+ ERROR,
+ multiboundMapBinding,
+ inconsistentMapKeyAnnotationTypesErrorMessage(
+ contributionsByMapKeyAnnotationType, multiboundMapBinding.key()));
+ }
+ }
+
+ private static ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ indexByMapKeyAnnotationType(ImmutableSet<ContributionBinding> contributions) {
+ return ImmutableSetMultimap.copyOf(
+ Multimaps.index(
+ contributions,
+ mapBinding ->
+ MoreTypes.equivalence()
+ .wrap(mapBinding.mapKeyAnnotation().get().getAnnotationType())));
+ }
+
+ private String inconsistentMapKeyAnnotationTypesErrorMessage(
+ ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
+ contributionsByMapKeyAnnotationType,
+ Key mapBindingKey) {
+ StringBuilder message =
+ new StringBuilder(mapBindingKey.toString())
+ .append(" uses more than one @MapKey annotation type");
+ Multimaps.asMap(contributionsByMapKeyAnnotationType)
+ .forEach(
+ (annotationType, contributions) -> {
+ message.append('\n').append(INDENT).append(annotationType.get()).append(':');
+ bindingDeclarationFormatter.formatIndentedList(message, contributions, 2);
+ });
+ return message.toString();
+ }
+
+ private String duplicateMapKeyErrorMessage(
+ Set<ContributionBinding> contributionsForOneMapKey, Key mapBindingKey) {
+ StringBuilder message =
+ new StringBuilder("The same map key is bound more than once for ").append(mapBindingKey);
+ bindingDeclarationFormatter.formatIndentedList(message, contributionsForOneMapKey, 1);
+ return message.toString();
+ }
+}
diff --git a/java/dagger/internal/codegen/MapType.java b/java/dagger/internal/codegen/MapType.java
new file mode 100644
index 0000000..73ecdbf
--- /dev/null
+++ b/java/dagger/internal/codegen/MapType.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import dagger.model.Key;
+import java.util.Map;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Information about a {@link Map} {@link TypeMirror}.
+ */
+@AutoValue
+abstract class MapType {
+ /**
+ * The map type itself, wrapped using {@link MoreTypes#equivalence()}. Use
+ * {@link #declaredMapType()} instead.
+ */
+ protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredMapType();
+
+ /**
+ * The map type itself.
+ */
+ DeclaredType declaredMapType() {
+ return wrappedDeclaredMapType().get();
+ }
+
+ /**
+ * {@code true} if the map type is the raw {@link Map} type.
+ */
+ boolean isRawType() {
+ return declaredMapType().getTypeArguments().isEmpty();
+ }
+
+ /**
+ * The map key type.
+ *
+ * @throws IllegalStateException if {@link #isRawType()} is true.
+ */
+ TypeMirror keyType() {
+ checkState(!isRawType());
+ return declaredMapType().getTypeArguments().get(0);
+ }
+
+ /**
+ * The map value type.
+ *
+ * @throws IllegalStateException if {@link #isRawType()} is true.
+ */
+ TypeMirror valueType() {
+ checkState(!isRawType());
+ return declaredMapType().getTypeArguments().get(1);
+ }
+
+ /**
+ * {@code true} if {@link #valueType()} is a {@code clazz}.
+ *
+ * @throws IllegalStateException if {@link #isRawType()} is true.
+ */
+ boolean valuesAreTypeOf(Class<?> clazz) {
+ return MoreTypes.isType(valueType()) && MoreTypes.isTypeOf(clazz, valueType());
+ }
+
+ /**
+ * Returns {@code true} if the {@linkplain #valueType() value type} of the {@link Map} is a
+ * {@linkplain FrameworkTypes#isFrameworkType(TypeMirror) framework type}.
+ */
+ boolean valuesAreFrameworkType() {
+ return FrameworkTypes.isFrameworkType(valueType());
+ }
+
+ /**
+ * {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code
+ * Producer<V>}.
+ *
+ * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
+ * framework type
+ */
+ TypeMirror unwrappedFrameworkValueType() {
+ checkState(
+ valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", declaredMapType());
+ return uncheckedUnwrappedValueType();
+ }
+
+ /**
+ * {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}.
+ *
+ * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
+ * {@code WrappingClass<V>}
+ * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
+ * parameter
+ */
+ TypeMirror unwrappedValueType(Class<?> wrappingClass) {
+ checkArgument(
+ wrappingClass.getTypeParameters().length == 1,
+ "%s must have exactly one type parameter",
+ wrappingClass);
+ checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this);
+ return uncheckedUnwrappedValueType();
+ }
+
+ private TypeMirror uncheckedUnwrappedValueType() {
+ return MoreTypes.asDeclared(valueType()).getTypeArguments().get(0);
+ }
+
+ /**
+ * {@code true} if {@code type} is a {@link Map} type.
+ */
+ static boolean isMap(TypeMirror type) {
+ return MoreTypes.isType(type) && MoreTypes.isTypeOf(Map.class, type);
+ }
+
+ /**
+ * {@code true} if {@code key.type()} is a {@link Map} type.
+ */
+ static boolean isMap(Key key) {
+ return isMap(key.type());
+ }
+
+ /**
+ * Returns a {@link MapType} for {@code type}.
+ *
+ * @throws IllegalArgumentException if {@code type} is not a {@link Map} type
+ */
+ static MapType from(TypeMirror type) {
+ checkArgument(isMap(type), "%s is not a Map", type);
+ return new AutoValue_MapType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
+ }
+
+ /**
+ * Returns a {@link MapType} for {@code key}'s {@link Key#type() type}.
+ *
+ * @throws IllegalArgumentException if {@code key.type()} is not a {@link Map} type
+ */
+ static MapType from(Key key) {
+ return from(key.type());
+ }
+}
diff --git a/java/dagger/internal/codegen/MemberSelect.java b/java/dagger/internal/codegen/MemberSelect.java
new file mode 100644
index 0000000..c42c7c9
--- /dev/null
+++ b/java/dagger/internal/codegen/MemberSelect.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
+import static dagger.internal.codegen.SourceFiles.bindingTypeElementTypeVariableNames;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.SourceFiles.setFactoryClassName;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
+import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static javax.lang.model.type.TypeKind.DECLARED;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableList;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import java.util.List;
+import java.util.Optional;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Represents a {@link com.sun.source.tree.MemberSelectTree} as a {@link CodeBlock}.
+ */
+abstract class MemberSelect {
+
+ /**
+ * Returns a {@link MemberSelect} that accesses the field given by {@code fieldName} owned by
+ * {@code owningClass}. In this context "local" refers to the fact that the field is owned by the
+ * type (or an enclosing type) from which the code block will be used. The returned
+ * {@link MemberSelect} will not be valid for accessing the field from a different class
+ * (regardless of accessibility).
+ */
+ static MemberSelect localField(ClassName owningClass, String fieldName) {
+ return new LocalField(owningClass, fieldName);
+ }
+
+ private static final class LocalField extends MemberSelect {
+ final String fieldName;
+
+ LocalField(ClassName owningClass, String fieldName) {
+ super(owningClass, false);
+ this.fieldName = checkNotNull(fieldName);
+ }
+
+ @Override
+ CodeBlock getExpressionFor(ClassName usingClass) {
+ return owningClass().equals(usingClass)
+ ? CodeBlock.of("$N", fieldName)
+ : CodeBlock.of("$T.this.$N", owningClass(), fieldName);
+ }
+ }
+
+ /**
+ * Returns a {@link MemberSelect} that accesses the method given by {@code methodName} owned by
+ * {@code owningClass}. In this context "local" refers to the fact that the method is owned by the
+ * type (or an enclosing type) from which the code block will be used. The returned {@link
+ * MemberSelect} will not be valid for accessing the method from a different class (regardless of
+ * accessibility).
+ */
+ static MemberSelect localMethod(ClassName owningClass, String methodName) {
+ return new LocalMethod(owningClass, methodName);
+ }
+
+ private static final class LocalMethod extends MemberSelect {
+ final String methodName;
+
+ LocalMethod(ClassName owningClass, String methodName) {
+ super(owningClass, false);
+ this.methodName = checkNotNull(methodName);
+ }
+
+ @Override
+ CodeBlock getExpressionFor(ClassName usingClass) {
+ return owningClass().equals(usingClass)
+ ? CodeBlock.of("$N()", methodName)
+ : CodeBlock.of("$T.this.$N()", owningClass(), methodName);
+ }
+ }
+
+ /**
+ * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments or a
+ * no-op members injection binding, then we don't need a field to hold its factory. In that case,
+ * this method returns the static member select that returns the factory or no-op members
+ * injector.
+ */
+ static Optional<MemberSelect> staticFactoryCreation(ResolvedBindings resolvedBindings) {
+ if (resolvedBindings.contributionBindings().isEmpty()) {
+ throw new AssertionError(
+ "Expected a contribution binding, but none found. *THIS IS A DAGGER BUG* - please "
+ + "report it on Github with as much context as you can provide. Thanks!"
+ + "\n\nKey: "
+ + resolvedBindings.key()
+ + "\nMultibinding declarations: "
+ + resolvedBindings.multibindingDeclarations()
+ + "\nSubcomponent declarations: "
+ + resolvedBindings.subcomponentDeclarations()
+ + "\nOptional binding declarations: "
+ + resolvedBindings.optionalBindingDeclarations());
+ }
+ ContributionBinding contributionBinding = resolvedBindings.contributionBinding();
+ if (contributionBinding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)
+ && !contributionBinding.scope().isPresent()) {
+ switch (contributionBinding.kind()) {
+ case MULTIBOUND_MAP:
+ return Optional.of(emptyMapFactory(contributionBinding));
+
+ case MULTIBOUND_SET:
+ return Optional.of(emptySetFactory(contributionBinding));
+
+ case INJECTION:
+ case PROVISION:
+ TypeMirror keyType = resolvedBindings.key().type();
+ if (keyType.getKind().equals(DECLARED)) {
+ ImmutableList<TypeVariableName> typeVariables =
+ bindingTypeElementTypeVariableNames(contributionBinding);
+ if (!typeVariables.isEmpty()) {
+ List<? extends TypeMirror> typeArguments =
+ ((DeclaredType) keyType).getTypeArguments();
+ return Optional.of(
+ MemberSelect.parameterizedFactoryCreateMethod(
+ generatedClassNameForBinding(contributionBinding), typeArguments));
+ }
+ }
+ // fall through
+
+ default:
+ return Optional.of(
+ new StaticMethod(
+ generatedClassNameForBinding(contributionBinding), CodeBlock.of("create()")));
+ }
+ }
+
+ return Optional.empty();
+ }
+
+ /**
+ * Returns a {@link MemberSelect} for the instance of a {@code create()} method on a factory. This
+ * only applies for factories that do not have any dependencies.
+ */
+ private static MemberSelect parameterizedFactoryCreateMethod(
+ ClassName owningClass, List<? extends TypeMirror> parameters) {
+ return new ParameterizedStaticMethod(
+ owningClass, ImmutableList.copyOf(parameters), CodeBlock.of("create()"), FACTORY);
+ }
+
+ private static final class StaticMethod extends MemberSelect {
+ final CodeBlock methodCodeBlock;
+
+ StaticMethod(ClassName owningClass, CodeBlock methodCodeBlock) {
+ super(owningClass, true);
+ this.methodCodeBlock = checkNotNull(methodCodeBlock);
+ }
+
+ @Override
+ CodeBlock getExpressionFor(ClassName usingClass) {
+ return owningClass().equals(usingClass)
+ ? methodCodeBlock
+ : CodeBlock.of("$T.$L", owningClass(), methodCodeBlock);
+ }
+ }
+
+ /** A {@link MemberSelect} for a factory of an empty map. */
+ private static MemberSelect emptyMapFactory(ContributionBinding contributionBinding) {
+ BindingType bindingType = contributionBinding.bindingType();
+ ImmutableList<TypeMirror> typeParameters =
+ ImmutableList.copyOf(
+ MoreTypes.asDeclared(contributionBinding.key().type()).getTypeArguments());
+ if (bindingType.equals(BindingType.PRODUCTION)) {
+ return new ParameterizedStaticMethod(
+ PRODUCERS, typeParameters, CodeBlock.of("emptyMapProducer()"), PRODUCER);
+ } else {
+ return new ParameterizedStaticMethod(
+ MAP_FACTORY, typeParameters, CodeBlock.of("emptyMapProvider()"), PROVIDER);
+ }
+ }
+
+ /**
+ * A static member select for an empty set factory. Calls {@link
+ * dagger.internal.SetFactory#empty()}, {@link dagger.producers.internal.SetProducer#empty()}, or
+ * {@link dagger.producers.internal.SetOfProducedProducer#empty()}, depending on the set bindings.
+ */
+ private static MemberSelect emptySetFactory(ContributionBinding binding) {
+ return new ParameterizedStaticMethod(
+ setFactoryClassName(binding),
+ ImmutableList.of(SetType.from(binding.key()).elementType()),
+ CodeBlock.of("empty()"),
+ FACTORY);
+ }
+
+ private static final class ParameterizedStaticMethod extends MemberSelect {
+ final ImmutableList<TypeMirror> typeParameters;
+ final CodeBlock methodCodeBlock;
+ final ClassName rawReturnType;
+
+ ParameterizedStaticMethod(
+ ClassName owningClass,
+ ImmutableList<TypeMirror> typeParameters,
+ CodeBlock methodCodeBlock,
+ ClassName rawReturnType) {
+ super(owningClass, true);
+ this.typeParameters = typeParameters;
+ this.methodCodeBlock = methodCodeBlock;
+ this.rawReturnType = rawReturnType;
+ }
+
+ @Override
+ CodeBlock getExpressionFor(ClassName usingClass) {
+ boolean accessible = true;
+ for (TypeMirror typeParameter : typeParameters) {
+ accessible &= isTypeAccessibleFrom(typeParameter, usingClass.packageName());
+ }
+
+ if (accessible) {
+ return CodeBlock.of(
+ "$T.<$L>$L",
+ owningClass(),
+ typeParameters.stream().map(CodeBlocks::type).collect(toParametersCodeBlock()),
+ methodCodeBlock);
+ } else {
+ return CodeBlock.of("(($T) $T.$L)", rawReturnType, owningClass(), methodCodeBlock);
+ }
+ }
+ }
+
+ private final ClassName owningClass;
+ private final boolean staticMember;
+
+ MemberSelect(ClassName owningClass, boolean staticMemeber) {
+ this.owningClass = owningClass;
+ this.staticMember = staticMemeber;
+ }
+
+ /** Returns the class that owns the member being selected. */
+ ClassName owningClass() {
+ return owningClass;
+ }
+
+ /**
+ * Returns true if the member being selected is static and does not require an instance of
+ * {@link #owningClass()}.
+ */
+ boolean staticMember() {
+ return staticMember;
+ }
+
+ /**
+ * Returns a {@link CodeBlock} suitable for accessing the member from the given {@code
+ * usingClass}.
+ */
+ abstract CodeBlock getExpressionFor(ClassName usingClass);
+}
diff --git a/java/dagger/internal/codegen/MembersInjectionBinding.java b/java/dagger/internal/codegen/MembersInjectionBinding.java
new file mode 100644
index 0000000..4918fa1
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectionBinding.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreElements.isAnnotationPresent;
+import static java.util.stream.Collectors.toList;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import java.util.Optional;
+import javax.inject.Inject;
+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;
+
+/**
+ * Represents the full members injection of a particular type.
+ */
+@AutoValue
+abstract class MembersInjectionBinding extends Binding {
+ @Override
+ public final Optional<Element> bindingElement() {
+ return Optional.of(membersInjectedType());
+ }
+
+ abstract TypeElement membersInjectedType();
+
+ @Override
+ abstract Optional<MembersInjectionBinding> unresolved();
+
+ @Override
+ public Optional<TypeElement> contributingModule() {
+ return Optional.empty();
+ }
+
+ /** The set of individual sites where {@link Inject} is applied. */
+ abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+ @Override
+ BindingType bindingType() {
+ return BindingType.MEMBERS_INJECTION;
+ }
+
+ @Override
+ public BindingKind kind() {
+ return BindingKind.MEMBERS_INJECTION;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if any of this binding's injection sites are directly on the bound type.
+ */
+ boolean hasLocalInjectionSites() {
+ return injectionSites()
+ .stream()
+ .anyMatch(
+ injectionSite ->
+ injectionSite.element().getEnclosingElement().equals(membersInjectedType()));
+ }
+
+ @Override
+ boolean requiresModuleInstance() {
+ return false;
+ }
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ // TODO(ronshapiro,dpb): simplify the equality semantics
+ @Override
+ public abstract boolean equals(Object obj);
+
+ @AutoValue
+ abstract static class InjectionSite {
+ enum Kind {
+ FIELD,
+ METHOD,
+ }
+
+ abstract Kind kind();
+
+ abstract Element element();
+
+ abstract ImmutableSet<DependencyRequest> dependencies();
+
+ /**
+ * Returns the index of {@link #element()} in its parents {@code @Inject} members that have the
+ * same simple name. This method filters out private elements so that the results will be
+ * consistent independent of whether the build system uses header jars or not.
+ */
+ @Memoized
+ int indexAmongAtInjectMembersWithSameSimpleName() {
+ return element()
+ .getEnclosingElement()
+ .getEnclosedElements()
+ .stream()
+ .filter(element -> isAnnotationPresent(element, Inject.class))
+ .filter(element -> !element.getModifiers().contains(Modifier.PRIVATE))
+ .filter(element -> element.getSimpleName().equals(this.element().getSimpleName()))
+ .collect(toList())
+ .indexOf(element());
+ }
+
+ static InjectionSite field(VariableElement element, DependencyRequest dependency) {
+ return new AutoValue_MembersInjectionBinding_InjectionSite(
+ Kind.FIELD, element, ImmutableSet.of(dependency));
+ }
+
+ static InjectionSite method(
+ ExecutableElement element, Iterable<DependencyRequest> dependencies) {
+ return new AutoValue_MembersInjectionBinding_InjectionSite(
+ Kind.METHOD, element, ImmutableSet.copyOf(dependencies));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/MembersInjectionBindingExpression.java b/java/dagger/internal/codegen/MembersInjectionBindingExpression.java
new file mode 100644
index 0000000..e9a8ffc
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectionBindingExpression.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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.collect.Iterables.getOnlyElement;
+import static javax.lang.model.type.TypeKind.VOID;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.ParameterSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.javapoet.Expression;
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ * A binding expression for members injection component methods. See {@link
+ * MembersInjectionMethods}.
+ */
+final class MembersInjectionBindingExpression extends BindingExpression {
+ private final MembersInjectionBinding binding;
+ private final MembersInjectionMethods membersInjectionMethods;
+
+ MembersInjectionBindingExpression(
+ ResolvedBindings resolvedBindings, MembersInjectionMethods membersInjectionMethods) {
+ this.binding = resolvedBindings.membersInjectionBinding().get();
+ this.membersInjectionMethods = membersInjectionMethods;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ throw new UnsupportedOperationException(binding.toString());
+ }
+
+ // TODO(ronshapiro): This class doesn't need to be a BindingExpression, as
+ // getDependencyExpression() should never be called for members injection methods. It's probably
+ // better suited as a method on MembersInjectionMethods
+ @Override
+ protected CodeBlock getComponentMethodImplementation(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ ExecutableElement methodElement = componentMethod.methodElement();
+ ParameterSpec parameter = ParameterSpec.get(getOnlyElement(methodElement.getParameters()));
+
+ if (binding.injectionSites().isEmpty()) {
+ return methodElement.getReturnType().getKind().equals(VOID)
+ ? CodeBlock.of("")
+ : CodeBlock.of("return $N;", parameter);
+ } else {
+ return methodElement.getReturnType().getKind().equals(VOID)
+ ? CodeBlock.of("$L;", membersInjectionInvocation(parameter))
+ : CodeBlock.of("return $L;", membersInjectionInvocation(parameter));
+ }
+ }
+
+ CodeBlock membersInjectionInvocation(ParameterSpec target) {
+ return CodeBlock.of("$N($N)", membersInjectionMethods.getOrCreate(binding.key()), target);
+ }
+}
diff --git a/java/dagger/internal/codegen/MembersInjectionMethods.java b/java/dagger/internal/codegen/MembersInjectionMethods.java
new file mode 100644
index 0000000..1e04669
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectionMethods.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.MEMBERS_INJECTION_METHOD;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.InjectionMethods.InjectionSiteMethod;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/** Manages the member injection methods for a component. */
+final class MembersInjectionMethods {
+ private final Map<Key, MethodSpec> membersInjectionMethods = new LinkedHashMap<>();
+ private final ComponentImplementation componentImplementation;
+ private final ComponentBindingExpressions bindingExpressions;
+ private final BindingGraph graph;
+ private final DaggerElements elements;
+ private final DaggerTypes types;
+
+ MembersInjectionMethods(
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions bindingExpressions,
+ BindingGraph graph,
+ DaggerElements elements,
+ DaggerTypes types) {
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.bindingExpressions = checkNotNull(bindingExpressions);
+ this.graph = checkNotNull(graph);
+ this.elements = checkNotNull(elements);
+ this.types = checkNotNull(types);
+ }
+
+ /**
+ * Returns the members injection {@link MethodSpec} for the given {@link Key}, creating it if
+ * necessary.
+ */
+ MethodSpec getOrCreate(Key key) {
+ return reentrantComputeIfAbsent(membersInjectionMethods, key, this::membersInjectionMethod);
+ }
+
+ private MethodSpec membersInjectionMethod(Key key) {
+ ResolvedBindings resolvedBindings =
+ graph.membersInjectionBindings().getOrDefault(key, graph.contributionBindings().get(key));
+ Binding binding = resolvedBindings.binding();
+ TypeMirror keyType = binding.key().type();
+ TypeMirror membersInjectedType =
+ isTypeAccessibleFrom(keyType, componentImplementation.name().packageName())
+ ? keyType
+ : elements.getTypeElement(Object.class).asType();
+ TypeName membersInjectedTypeName = TypeName.get(membersInjectedType);
+ Name bindingTypeName = binding.bindingTypeElement().get().getSimpleName();
+ // TODO(ronshapiro): include type parameters in this name e.g. injectFooOfT, and outer class
+ // simple names Foo.Builder -> injectFooBuilder
+ String methodName = componentImplementation.getUniqueMethodName("inject" + bindingTypeName);
+ ParameterSpec parameter = ParameterSpec.builder(membersInjectedTypeName, "instance").build();
+ MethodSpec.Builder methodBuilder =
+ methodBuilder(methodName)
+ .addModifiers(PRIVATE)
+ .returns(membersInjectedTypeName)
+ .addParameter(parameter);
+ TypeElement canIgnoreReturnValue =
+ elements.getTypeElement("com.google.errorprone.annotations.CanIgnoreReturnValue");
+ if (canIgnoreReturnValue != null) {
+ methodBuilder.addAnnotation(ClassName.get(canIgnoreReturnValue));
+ }
+ CodeBlock instance = CodeBlock.of("$N", parameter);
+ methodBuilder.addCode(
+ InjectionSiteMethod.invokeAll(
+ injectionSites(binding),
+ componentImplementation.name(),
+ instance,
+ membersInjectedType,
+ types,
+ request ->
+ bindingExpressions
+ .getDependencyArgumentExpression(request, componentImplementation.name())
+ .codeBlock(),
+ elements));
+ methodBuilder.addStatement("return $L", instance);
+
+ MethodSpec method = methodBuilder.build();
+ componentImplementation.addMethod(MEMBERS_INJECTION_METHOD, method);
+ return method;
+ }
+
+ private static ImmutableSet<InjectionSite> injectionSites(Binding binding) {
+ if (binding instanceof ProvisionBinding) {
+ return ((ProvisionBinding) binding).injectionSites();
+ } else if (binding instanceof MembersInjectionBinding) {
+ return ((MembersInjectionBinding) binding).injectionSites();
+ }
+ throw new IllegalArgumentException(binding.key().toString());
+ }
+}
diff --git a/java/dagger/internal/codegen/MembersInjectionValidator.java b/java/dagger/internal/codegen/MembersInjectionValidator.java
new file mode 100644
index 0000000..036315e
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectionValidator.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifiers;
+
+import com.google.auto.common.MoreElements;
+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.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.PrimitiveType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * Validates members injection requests (members injection methods on components and requests for
+ * {@code MembersInjector<Foo>}).
+ */
+final class MembersInjectionValidator {
+
+ @Inject
+ MembersInjectionValidator() {}
+
+ /** Reports errors if a request for a {@code MembersInjector<Foo>}) is invalid. */
+ ValidationReport<Element> validateMembersInjectionRequest(
+ Element requestElement, TypeMirror membersInjectedType) {
+ ValidationReport.Builder<Element> report = ValidationReport.about(requestElement);
+ checkQualifiers(report, requestElement);
+ membersInjectedType.accept(VALIDATE_MEMBERS_INJECTED_TYPE, report);
+ return report.build();
+ }
+
+ /**
+ * Reports errors if a members injection method on a component is invalid.
+ *
+ * @throws IllegalArgumentException if the method doesn't have exactly one parameter
+ */
+ ValidationReport<ExecutableElement> validateMembersInjectionMethod(
+ ExecutableElement method, TypeMirror membersInjectedType) {
+ checkArgument(
+ method.getParameters().size() == 1, "expected a method with one parameter: %s", method);
+
+ ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(method);
+ checkQualifiers(report, method);
+ checkQualifiers(report, method.getParameters().get(0));
+ membersInjectedType.accept(VALIDATE_MEMBERS_INJECTED_TYPE, report);
+ return report.build();
+ }
+
+ private void checkQualifiers(ValidationReport.Builder<?> report, Element element) {
+ for (AnnotationMirror qualifier : getQualifiers(element)) {
+ report.addError("Cannot inject members into qualified types", element, qualifier);
+ break; // just report on the first qualifier, in case there is more than one
+ }
+ }
+
+ private static final TypeVisitor<Void, ValidationReport.Builder<?>>
+ VALIDATE_MEMBERS_INJECTED_TYPE =
+ new SimpleTypeVisitor8<Void, ValidationReport.Builder<?>>() {
+ // Only declared types can be members-injected.
+ @Override
+ protected Void defaultAction(TypeMirror type, ValidationReport.Builder<?> report) {
+ report.addError("Cannot inject members into " + type);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType type, ValidationReport.Builder<?> report) {
+ if (type.getTypeArguments().isEmpty()) {
+ // If the type is the erasure of a generic type, that means the user referred to
+ // Foo<T> as just 'Foo', which we don't allow. (This is a judgement call; we
+ // *could* allow it and instantiate the type bounds, but we don't.)
+ if (!MoreElements.asType(type.asElement()).getTypeParameters().isEmpty()) {
+ report.addError("Cannot inject members into raw type " + type);
+ }
+ } else {
+ // If the type has arguments, validate that each type argument is declared.
+ // Otherwise the type argument may be a wildcard (or other type), and we can't
+ // resolve that to actual types. For array type arguments, validate the type of the
+ // array.
+ for (TypeMirror arg : type.getTypeArguments()) {
+ if (!arg.accept(DECLARED_OR_ARRAY, null)) {
+ report.addError(
+ "Cannot inject members into types with unbounded type arguments: " + type);
+ }
+ }
+ }
+ return null;
+ }
+ };
+
+ // TODO(dpb): Can this be inverted so it explicitly rejects wildcards or type variables?
+ // This logic is hard to describe.
+ private static final TypeVisitor<Boolean, Void> DECLARED_OR_ARRAY =
+ new SimpleTypeVisitor8<Boolean, Void>(false) {
+ @Override
+ public Boolean visitArray(ArrayType arrayType, Void p) {
+ return arrayType
+ .getComponentType()
+ .accept(
+ new SimpleTypeVisitor8<Boolean, Void>(false) {
+ @Override
+ public Boolean visitDeclared(DeclaredType declaredType, Void p) {
+ for (TypeMirror arg : declaredType.getTypeArguments()) {
+ if (!arg.accept(this, null)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Boolean visitArray(ArrayType arrayType, Void p) {
+ return arrayType.getComponentType().accept(this, null);
+ }
+
+ @Override
+ public Boolean visitPrimitive(PrimitiveType primitiveType, Void p) {
+ return true;
+ }
+ },
+ null);
+ }
+
+ @Override
+ public Boolean visitDeclared(DeclaredType t, Void p) {
+ return true;
+ }
+ };
+}
diff --git a/java/dagger/internal/codegen/MembersInjectorGenerator.java b/java/dagger/internal/codegen/MembersInjectorGenerator.java
new file mode 100644
index 0000000..4360af7
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectorGenerator.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.GwtCompatibility.gwtIncompatibleAnnotation;
+import static dagger.internal.codegen.SourceFiles.bindingTypeElementTypeVariableNames;
+import static dagger.internal.codegen.SourceFiles.frameworkFieldUsages;
+import static dagger.internal.codegen.SourceFiles.generateBindingFieldsForDependencies;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.SourceFiles.parameterizedGeneratedTypeNameForBinding;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.membersInjectorOf;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+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.MembersInjector;
+import dagger.internal.codegen.InjectionMethods.InjectionSiteMethod;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import java.util.Map.Entry;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+
+/**
+ * Generates {@link MembersInjector} implementations from {@link MembersInjectionBinding} instances.
+ */
+final class MembersInjectorGenerator extends SourceFileGenerator<MembersInjectionBinding> {
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ @Inject
+ MembersInjectorGenerator(
+ Filer filer, DaggerElements elements, DaggerTypes types, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ this.types = types;
+ this.elements = elements;
+ }
+
+ @Override
+ ClassName nameGeneratedType(MembersInjectionBinding binding) {
+ return membersInjectorNameForType(binding.membersInjectedType());
+ }
+
+ @Override
+ Element originatingElement(MembersInjectionBinding binding) {
+ return binding.membersInjectedType();
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, MembersInjectionBinding binding) {
+ // Empty members injection bindings are special and don't need source files.
+ if (binding.injectionSites().isEmpty()) {
+ return Optional.empty();
+ }
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkState(
+ !binding.unresolved().isPresent(),
+ "tried to generate a MembersInjector for a binding of a resolved generic type: %s",
+ binding);
+
+ ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding);
+ TypeSpec.Builder injectorTypeBuilder =
+ classBuilder(generatedTypeName)
+ .addModifiers(PUBLIC, FINAL)
+ .addTypeVariables(typeParameters);
+
+ TypeName injectedTypeName = TypeName.get(binding.key().type());
+ TypeName implementedType = membersInjectorOf(injectedTypeName);
+ injectorTypeBuilder.addSuperinterface(implementedType);
+
+ MethodSpec.Builder injectMembersBuilder =
+ methodBuilder("injectMembers")
+ .addModifiers(PUBLIC)
+ .addAnnotation(Override.class)
+ .addParameter(injectedTypeName, "instance");
+
+ ImmutableMap<Key, FrameworkField> fields = generateBindingFieldsForDependencies(binding);
+
+ ImmutableMap.Builder<Key, FieldSpec> dependencyFieldsBuilder = ImmutableMap.builder();
+
+ MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PUBLIC);
+
+ // We use a static create method so that generated components can avoid having
+ // to refer to the generic types of the factory.
+ // (Otherwise they may have visibility problems referring to the types.)
+ MethodSpec.Builder createMethodBuilder =
+ methodBuilder("create")
+ .returns(implementedType)
+ .addModifiers(PUBLIC, STATIC)
+ .addTypeVariables(typeParameters);
+
+ createMethodBuilder.addCode(
+ "return new $T(", parameterizedGeneratedTypeNameForBinding(binding));
+ ImmutableList.Builder<CodeBlock> constructorInvocationParameters = ImmutableList.builder();
+
+ boolean usesRawFrameworkTypes = false;
+ UniqueNameSet fieldNames = new UniqueNameSet();
+ for (Entry<Key, FrameworkField> fieldEntry : fields.entrySet()) {
+ Key dependencyKey = fieldEntry.getKey();
+ FrameworkField bindingField = fieldEntry.getValue();
+
+ // If the dependency type is not visible to this members injector, then use the raw framework
+ // type for the field.
+ boolean useRawFrameworkType =
+ !isTypeAccessibleFrom(dependencyKey.type(), generatedTypeName.packageName());
+
+ String fieldName = fieldNames.getUniqueName(bindingField.name());
+ TypeName fieldType = useRawFrameworkType ? bindingField.type().rawType : bindingField.type();
+ FieldSpec.Builder fieldBuilder = FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL);
+ ParameterSpec.Builder parameterBuilder = ParameterSpec.builder(fieldType, fieldName);
+
+ // If we're using the raw type for the field, then suppress the injectMembers method's
+ // unchecked-type warning and the field's and the constructor and create-method's
+ // parameters' raw-type warnings.
+ if (useRawFrameworkType) {
+ usesRawFrameworkTypes = true;
+ fieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
+ parameterBuilder.addAnnotation(suppressWarnings(RAWTYPES));
+ }
+ constructorBuilder.addParameter(parameterBuilder.build());
+ createMethodBuilder.addParameter(parameterBuilder.build());
+
+ FieldSpec field = fieldBuilder.build();
+ injectorTypeBuilder.addField(field);
+ constructorBuilder.addStatement("this.$1N = $1N", field);
+ dependencyFieldsBuilder.put(dependencyKey, field);
+ constructorInvocationParameters.add(CodeBlock.of("$N", field));
+ }
+
+ createMethodBuilder.addCode(
+ constructorInvocationParameters.build().stream().collect(toParametersCodeBlock()));
+ createMethodBuilder.addCode(");");
+
+ injectorTypeBuilder.addMethod(constructorBuilder.build());
+ injectorTypeBuilder.addMethod(createMethodBuilder.build());
+
+ ImmutableMap<Key, FieldSpec> dependencyFields = dependencyFieldsBuilder.build();
+
+ injectMembersBuilder.addCode(
+ InjectionSiteMethod.invokeAll(
+ binding.injectionSites(),
+ generatedTypeName,
+ CodeBlock.of("instance"),
+ binding.key().type(),
+ types,
+ frameworkFieldUsages(binding.dependencies(), dependencyFields)::get,
+ elements));
+
+ if (usesRawFrameworkTypes) {
+ injectMembersBuilder.addAnnotation(suppressWarnings(UNCHECKED));
+ }
+ injectorTypeBuilder.addMethod(injectMembersBuilder.build());
+
+ for (InjectionSite injectionSite : binding.injectionSites()) {
+ if (injectionSite.element().getEnclosingElement().equals(binding.membersInjectedType())) {
+ injectorTypeBuilder.addMethod(
+ InjectionSiteMethod.create(injectionSite, elements).toMethodSpec());
+ }
+ }
+
+ gwtIncompatibleAnnotation(binding).ifPresent(injectorTypeBuilder::addAnnotation);
+
+ return Optional.of(injectorTypeBuilder);
+ }
+}
diff --git a/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java b/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java
new file mode 100644
index 0000000..8e863e5
--- /dev/null
+++ b/java/dagger/internal/codegen/MembersInjectorProviderCreationExpression.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.SourceFiles.membersInjectorNameForType;
+import static dagger.internal.codegen.javapoet.TypeNames.INSTANCE_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.MEMBERS_INJECTORS;
+
+import com.google.auto.common.MoreTypes;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import javax.lang.model.type.TypeMirror;
+
+/** A {@code Provider<MembersInjector<Foo>>} creation expression. */
+final class MembersInjectorProviderCreationExpression
+ implements FrameworkInstanceCreationExpression {
+
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ProvisionBinding binding;
+
+ MembersInjectorProviderCreationExpression(
+ ProvisionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ TypeMirror membersInjectedType =
+ getOnlyElement(MoreTypes.asDeclared(binding.key().type()).getTypeArguments());
+
+ CodeBlock membersInjector =
+ binding.injectionSites().isEmpty()
+ ? CodeBlock.of("$T.<$T>noOp()", MEMBERS_INJECTORS, membersInjectedType)
+ : CodeBlock.of(
+ "$T.create($L)",
+ membersInjectorNameForType(MoreTypes.asTypeElement(membersInjectedType)),
+ componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
+
+ // TODO(ronshapiro): consider adding a MembersInjectorBindingExpression to return this directly
+ // (as it's rarely requested as a Provider).
+ return CodeBlock.of("$T.create($L)", INSTANCE_FACTORY, membersInjector);
+ }
+
+ @Override
+ public boolean useInnerSwitchingProvider() {
+ return !binding.injectionSites().isEmpty();
+ }
+}
diff --git a/java/dagger/internal/codegen/MethodBindingExpression.java b/java/dagger/internal/codegen/MethodBindingExpression.java
new file mode 100644
index 0000000..2120e80
--- /dev/null
+++ b/java/dagger/internal/codegen/MethodBindingExpression.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.ComponentImplementation.FieldSpecKind.PRIVATE_METHOD_SCOPED_FIELD;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.VOLATILE;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.DoubleCheck;
+import dagger.internal.MemoizedSentinel;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.RequestKind;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/** A binding expression that wraps another in a nullary method on the component. */
+abstract class MethodBindingExpression extends BindingExpression {
+ private final BindingRequest request;
+ private final ResolvedBindings resolvedBindings;
+ private final ContributionBinding binding;
+ private final BindingMethodImplementation bindingMethodImplementation;
+ private final ComponentImplementation componentImplementation;
+ private final ProducerEntryPointView producerEntryPointView;
+ private final BindingExpression wrappedBindingExpression;
+ private final DaggerTypes types;
+
+ protected MethodBindingExpression(
+ BindingRequest request,
+ ResolvedBindings resolvedBindings,
+ MethodImplementationStrategy methodImplementationStrategy,
+ BindingExpression wrappedBindingExpression,
+ ComponentImplementation componentImplementation,
+ DaggerTypes types) {
+ this.request = checkNotNull(request);
+ this.resolvedBindings = resolvedBindings;
+ this.binding = resolvedBindings.contributionBinding();
+ this.bindingMethodImplementation = bindingMethodImplementation(methodImplementationStrategy);
+ this.wrappedBindingExpression = checkNotNull(wrappedBindingExpression);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.producerEntryPointView = new ProducerEntryPointView(types);
+ this.types = checkNotNull(types);
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ if (request.frameworkType().isPresent()) {
+ // Initializing a framework instance that participates in a cycle requires that the underlying
+ // FrameworkInstanceBindingExpression is invoked in order for a cycle to be detected properly.
+ // When a MethodBindingExpression wraps a FrameworkInstanceBindingExpression, the wrapped
+ // expression will only be invoked once to implement the method body. This is a hack to work
+ // around that weirdness - methodImplementation.body() will invoke the framework instance
+ // initialization again in case the field is not fully initialized.
+ // TODO(b/121196706): use a less hacky approach to fix this bug
+ Object unused = methodBody();
+ }
+
+ addMethod();
+ return Expression.create(
+ returnType(),
+ requestingClass.equals(componentImplementation.name())
+ ? CodeBlock.of("$N()", methodName())
+ : CodeBlock.of("$T.this.$N()", componentImplementation.name(), methodName()));
+ }
+
+ @Override
+ final CodeBlock getModifiableBindingMethodImplementation(
+ ModifiableBindingMethod modifiableBindingMethod,
+ ComponentImplementation component,
+ DaggerTypes types) {
+ // A matching modifiable binding method means that we have previously created the binding method
+ // and we are now implementing it. If there is no matching method we need to first create the
+ // method. We create the method by deferring to getDependencyExpression (defined above) via a
+ // call to super.getModifiableBindingMethodImplementation().
+ if (supertypeModifiableBindingMethod().isPresent()) {
+ checkState(
+ supertypeModifiableBindingMethod().get().fulfillsSameRequestAs(modifiableBindingMethod));
+ return methodBody();
+ }
+ return super.getModifiableBindingMethodImplementation(
+ modifiableBindingMethod, component, types);
+ }
+
+ protected final Optional<ModifiableBindingMethod> supertypeModifiableBindingMethod() {
+ return componentImplementation.supertypeModifiableBindingMethod(request);
+ }
+
+ @Override
+ Expression getDependencyExpressionForComponentMethod(ComponentMethodDescriptor componentMethod,
+ ComponentImplementation component) {
+ return producerEntryPointView
+ .getProducerEntryPointField(this, componentMethod, component)
+ .orElseGet(
+ () -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
+ }
+
+ /** Adds the method to the component (if necessary) the first time it's called. */
+ protected abstract void addMethod();
+
+ /** Returns the name of the method to call. */
+ protected abstract String methodName();
+
+ /**
+ * Returns {@code true} if the method of this binding expression is modifiable and is not a
+ * component method.
+ */
+ protected boolean isModifiableImplementationMethod() {
+ return false;
+ }
+
+ /** The method's body. */
+ protected final CodeBlock methodBody() {
+ return implementation(
+ wrappedBindingExpression.getDependencyExpression(componentImplementation.name())
+ ::codeBlock);
+ }
+
+ /** The method's body if this method is a component method. */
+ protected final CodeBlock methodBodyForComponentMethod(
+ ComponentMethodDescriptor componentMethod) {
+ return implementation(
+ wrappedBindingExpression.getDependencyExpressionForComponentMethod(
+ componentMethod, componentImplementation)
+ ::codeBlock);
+ }
+
+ private CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
+ return bindingMethodImplementation.implementation(simpleBindingExpression);
+ }
+
+ private BindingMethodImplementation bindingMethodImplementation(
+ MethodImplementationStrategy methodImplementationStrategy) {
+ switch (methodImplementationStrategy) {
+ case SIMPLE:
+ return new SimpleMethodImplementation();
+ case SINGLE_CHECK:
+ return new SingleCheckedMethodImplementation();
+ case DOUBLE_CHECK:
+ return new DoubleCheckedMethodImplementation();
+ }
+ throw new AssertionError(methodImplementationStrategy);
+ }
+
+ /** Returns the return type for the dependency request. */
+ protected TypeMirror returnType() {
+ if (request.isRequestKind(RequestKind.INSTANCE)
+ && binding.contributedPrimitiveType().isPresent()) {
+ return binding.contributedPrimitiveType().get();
+ }
+
+ if (matchingComponentMethod().isPresent()) {
+ // Component methods are part of the user-defined API, and thus we must use the user-defined
+ // type.
+ return matchingComponentMethod().get().resolvedReturnType(types);
+ }
+
+ // If the component is abstract, this method may be overridden by another implementation in a
+ // different package for which requestedType is inaccessible. In order to make that method
+ // overridable, we use the publicly accessible type. If the method is private, we don't need to
+ // worry about this, and instead just need to check accessibility of the file we're about to
+ // write
+ TypeMirror requestedType = request.requestedType(binding.contributedType(), types);
+ return isModifiableImplementationMethod()
+ ? types.publiclyAccessibleType(requestedType)
+ : types.accessibleType(requestedType, componentImplementation.name());
+ }
+
+ private Optional<ComponentMethodDescriptor> matchingComponentMethod() {
+ return componentImplementation.componentDescriptor().firstMatchingComponentMethod(request);
+ }
+
+ /** Strateg for implementing the body of this method. */
+ enum MethodImplementationStrategy {
+ SIMPLE,
+ SINGLE_CHECK,
+ DOUBLE_CHECK,
+ ;
+ }
+
+ private abstract static class BindingMethodImplementation {
+ /**
+ * Returns the method body, which contains zero or more statements (including semicolons).
+ *
+ * <p>If the implementation has a non-void return type, the body will also include the {@code
+ * return} statement.
+ *
+ * @param simpleBindingExpression the expression to retrieve an instance of this binding without
+ * the wrapping method.
+ */
+ abstract CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression);
+ }
+
+ /** Returns the {@code wrappedBindingExpression} directly. */
+ private static final class SimpleMethodImplementation extends BindingMethodImplementation {
+ @Override
+ CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
+ return CodeBlock.of("return $L;", simpleBindingExpression.get());
+ }
+ }
+
+ /**
+ * Defines a method body for single checked caching of the given {@code wrappedBindingExpression}.
+ */
+ private final class SingleCheckedMethodImplementation extends BindingMethodImplementation {
+ private final Supplier<FieldSpec> field = Suppliers.memoize(this::createField);
+
+ @Override
+ CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
+ String fieldExpression = field.get().name.equals("local") ? "this.local" : field.get().name;
+
+ CodeBlock.Builder builder = CodeBlock.builder()
+ .addStatement("Object local = $N", fieldExpression);
+
+ if (isNullable()) {
+ builder.beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class);
+ } else {
+ builder.beginControlFlow("if (local == null)");
+ }
+
+ return builder
+ .addStatement("local = $L", simpleBindingExpression.get())
+ .addStatement("$N = ($T) local", fieldExpression, returnType())
+ .endControlFlow()
+ .addStatement("return ($T) local", returnType())
+ .build();
+ }
+
+ FieldSpec createField() {
+ String name =
+ componentImplementation.getUniqueFieldName(
+ request.isRequestKind(RequestKind.INSTANCE)
+ ? KeyVariableNamer.name(binding.key())
+ // TODO(ronshapiro): Use KeyVariableNamer directly so we don't need to use a
+ // ResolvedBindings instance and construct a whole framework field just to get the
+ // name
+ : FrameworkField.forResolvedBindings(resolvedBindings, Optional.empty()).name());
+
+ FieldSpec.Builder builder = FieldSpec.builder(fieldType(), name, PRIVATE, VOLATILE);
+ if (isNullable()) {
+ builder.initializer("new $T()", MemoizedSentinel.class);
+ }
+
+ FieldSpec field = builder.build();
+ componentImplementation.addField(PRIVATE_METHOD_SCOPED_FIELD, field);
+ return field;
+ }
+
+ TypeName fieldType() {
+ if (isNullable()) {
+ // Nullable instances use `MemoizedSentinel` instead of `null` as the initialization value,
+ // so the field type must accept that and the return type
+ return TypeName.OBJECT;
+ }
+ TypeName returnType = TypeName.get(returnType());
+ return returnType.isPrimitive() ? returnType.box() : returnType;
+ }
+
+ private boolean isNullable() {
+ return request.isRequestKind(RequestKind.INSTANCE) && binding.isNullable();
+ }
+ }
+
+ /**
+ * Defines a method body for double checked caching of the given {@code wrappedBindingExpression}.
+ */
+ private final class DoubleCheckedMethodImplementation extends BindingMethodImplementation {
+ private final Supplier<String> fieldName = Suppliers.memoize(this::createField);
+
+ @Override
+ CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
+ String fieldExpression = fieldName.get().equals("local") ? "this.local" : fieldName.get();
+ return CodeBlock.builder()
+ .addStatement("$T local = $L", TypeName.OBJECT, fieldExpression)
+ .beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
+ .beginControlFlow("synchronized (local)")
+ .addStatement("local = $L", fieldExpression)
+ .beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
+ .addStatement("local = $L", simpleBindingExpression.get())
+ .addStatement("$1L = $2T.reentrantCheck($1L, local)", fieldExpression, DoubleCheck.class)
+ .endControlFlow()
+ .endControlFlow()
+ .endControlFlow()
+ .addStatement("return ($T) local", returnType())
+ .build();
+ }
+
+ private String createField() {
+ String name =
+ componentImplementation.getUniqueFieldName(KeyVariableNamer.name(binding.key()));
+ componentImplementation.addField(
+ PRIVATE_METHOD_SCOPED_FIELD,
+ FieldSpec.builder(TypeName.OBJECT, name, PRIVATE, VOLATILE)
+ .initializer("new $T()", MemoizedSentinel.class)
+ .build());
+ return name;
+ }
+ }
+
+}
diff --git a/java/dagger/internal/codegen/MethodSignature.java b/java/dagger/internal/codegen/MethodSignature.java
new file mode 100644
index 0000000..ef5c9c5
--- /dev/null
+++ b/java/dagger/internal/codegen/MethodSignature.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.DaggerStreams.toImmutableList;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableList;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.List;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+@AutoValue
+abstract class MethodSignature {
+
+ abstract String name();
+
+ abstract ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>> parameterTypes();
+
+ abstract ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>> thrownTypes();
+
+ static MethodSignature forComponentMethod(
+ ComponentMethodDescriptor componentMethod, DeclaredType componentType, DaggerTypes types) {
+ ExecutableType methodType =
+ MoreTypes.asExecutable(types.asMemberOf(componentType, componentMethod.methodElement()));
+ return new AutoValue_MethodSignature(
+ componentMethod.methodElement().getSimpleName().toString(),
+ wrapInEquivalence(methodType.getParameterTypes()),
+ wrapInEquivalence(methodType.getThrownTypes()));
+ }
+
+ private static ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>>
+ wrapInEquivalence(List<? extends TypeMirror> types) {
+ return types.stream().map(MoreTypes.equivalence()::wrap).collect(toImmutableList());
+ }
+}
diff --git a/java/dagger/internal/codegen/MethodSignatureFormatter.java b/java/dagger/internal/codegen/MethodSignatureFormatter.java
new file mode 100644
index 0000000..012d5b0
--- /dev/null
+++ b/java/dagger/internal/codegen/MethodSignatureFormatter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static dagger.internal.codegen.DiagnosticFormatting.stripCommonTypePrefixes;
+import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import javax.inject.Inject;
+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.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Formats the signature of an {@link ExecutableElement} suitable for use in error messages.
+ */
+final class MethodSignatureFormatter extends Formatter<ExecutableElement> {
+ private final DaggerTypes types;
+
+ @Inject
+ MethodSignatureFormatter(DaggerTypes types) {
+ this.types = types;
+ }
+
+ /**
+ * A formatter that uses the type where the method is declared for the annotations and name of the
+ * method, but the method's resolved type as a member of {@code declaredType} for the key.
+ */
+ Formatter<ExecutableElement> typedFormatter(DeclaredType declaredType) {
+ return new Formatter<ExecutableElement>() {
+ @Override
+ public String format(ExecutableElement method) {
+ return MethodSignatureFormatter.this.format(
+ method,
+ MoreTypes.asExecutable(types.asMemberOf(declaredType, method)),
+ MoreElements.asType(method.getEnclosingElement()));
+ }
+ };
+ }
+
+ @Override public String format(ExecutableElement method) {
+ return format(method, Optional.empty());
+ }
+
+ /**
+ * Formats an ExecutableElement as if it were contained within the container, if the container is
+ * present.
+ */
+ public String format(ExecutableElement method, Optional<DeclaredType> container) {
+ TypeElement type = MoreElements.asType(method.getEnclosingElement());
+ ExecutableType executableType = MoreTypes.asExecutable(method.asType());
+ if (container.isPresent()) {
+ executableType = MoreTypes.asExecutable(types.asMemberOf(container.get(), method));
+ type = MoreElements.asType(container.get().asElement());
+ }
+ return format(method, executableType, type);
+ }
+
+ private String format(
+ ExecutableElement method, ExecutableType methodType, TypeElement declaringType) {
+ StringBuilder builder = new StringBuilder();
+ // TODO(cgruber): AnnotationMirror formatter.
+ List<? extends AnnotationMirror> annotations = method.getAnnotationMirrors();
+ if (!annotations.isEmpty()) {
+ Iterator<? extends AnnotationMirror> annotationIterator = annotations.iterator();
+ for (int i = 0; annotationIterator.hasNext(); i++) {
+ if (i > 0) {
+ builder.append(' ');
+ }
+ builder.append(formatAnnotation(annotationIterator.next()));
+ }
+ builder.append(' ');
+ }
+ if (method.getSimpleName().contentEquals("<init>")) {
+ builder.append(declaringType.getQualifiedName());
+ } else {
+ builder
+ .append(nameOfType(methodType.getReturnType()))
+ .append(' ')
+ .append(declaringType.getQualifiedName())
+ .append('.')
+ .append(method.getSimpleName());
+ }
+ builder.append('(');
+ checkState(method.getParameters().size() == methodType.getParameterTypes().size());
+ Iterator<? extends VariableElement> parameters = method.getParameters().iterator();
+ Iterator<? extends TypeMirror> parameterTypes = methodType.getParameterTypes().iterator();
+ for (int i = 0; parameters.hasNext(); i++) {
+ if (i > 0) {
+ builder.append(", ");
+ }
+ appendParameter(builder, parameters.next(), parameterTypes.next());
+ }
+ builder.append(')');
+ return builder.toString();
+ }
+
+ private static void appendParameter(StringBuilder builder, VariableElement parameter,
+ TypeMirror type) {
+ getQualifier(parameter)
+ .ifPresent(
+ qualifier -> {
+ builder.append(formatAnnotation(qualifier)).append(' ');
+ });
+ builder.append(nameOfType(type));
+ }
+
+ private static String nameOfType(TypeMirror type) {
+ return stripCommonTypePrefixes(type.toString());
+ }
+
+ private static String formatAnnotation(AnnotationMirror annotation) {
+ return stripCommonTypePrefixes(annotation.toString());
+ }
+}
diff --git a/java/dagger/internal/codegen/MissingBindingExpression.java b/java/dagger/internal/codegen/MissingBindingExpression.java
new file mode 100644
index 0000000..610d052
--- /dev/null
+++ b/java/dagger/internal/codegen/MissingBindingExpression.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A {@link ModifiableAbstractMethodBindingExpression} for a binding that is missing when generating
+ * the abstract base class implementation of a subcomponent. The (unimplemented) method is added to
+ * the {@link ComponentImplementation} when the dependency expression is requested. The method is
+ * overridden when generating the implementation of an ancestor component.
+ */
+final class MissingBindingExpression extends ModifiableAbstractMethodBindingExpression {
+ private final ComponentImplementation componentImplementation;
+ private final BindingRequest request;
+
+ MissingBindingExpression(
+ ComponentImplementation componentImplementation,
+ BindingRequest request,
+ Optional<ModifiableBindingMethod> matchingModifiableBindingMethod,
+ Optional<ComponentMethodDescriptor> matchingComponentMethod,
+ DaggerTypes types) {
+ super(
+ componentImplementation,
+ ModifiableBindingType.MISSING,
+ request,
+ matchingModifiableBindingMethod,
+ matchingComponentMethod,
+ types);
+ this.componentImplementation = componentImplementation;
+ this.request = request;
+ }
+
+ @Override
+ String chooseMethodName() {
+ return componentImplementation.getUniqueMethodName(request);
+ }
+
+ @Override
+ protected TypeMirror contributedType() {
+ return request.key().type();
+ }
+}
diff --git a/java/dagger/internal/codegen/MissingBindingValidator.java b/java/dagger/internal/codegen/MissingBindingValidator.java
new file mode 100644
index 0000000..f39361d
--- /dev/null
+++ b/java/dagger/internal/codegen/MissingBindingValidator.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.Keys.isValidImplicitProvisionKey;
+import static dagger.internal.codegen.Keys.isValidMembersInjectionKey;
+import static dagger.internal.codegen.RequestKinds.canBeSatisfiedByProductionBinding;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.BindingGraph.MissingBinding;
+import dagger.model.BindingGraph.Node;
+import dagger.model.Key;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import javax.inject.Inject;
+import javax.lang.model.type.TypeKind;
+
+/** Reports errors for missing bindings. */
+final class MissingBindingValidator implements BindingGraphPlugin {
+
+ private final DaggerTypes types;
+ private final InjectBindingRegistry injectBindingRegistry;
+
+ @Inject
+ MissingBindingValidator(
+ DaggerTypes types, InjectBindingRegistry injectBindingRegistry) {
+ this.types = types;
+ this.injectBindingRegistry = injectBindingRegistry;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/MissingBinding";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph graph, DiagnosticReporter diagnosticReporter) {
+ // Don't report missing bindings when validating a full binding graph or a graph built from a
+ // subcomponent.
+ if (graph.isFullBindingGraph() || graph.rootComponentNode().isSubcomponent()) {
+ return;
+ }
+ graph
+ .missingBindings()
+ .forEach(missingBinding -> reportMissingBinding(missingBinding, graph, diagnosticReporter));
+ }
+
+ private void reportMissingBinding(
+ MissingBinding missingBinding, BindingGraph graph, DiagnosticReporter diagnosticReporter) {
+ diagnosticReporter.reportBinding(
+ ERROR, missingBinding, missingBindingErrorMessage(missingBinding, graph));
+ }
+
+ private String missingBindingErrorMessage(MissingBinding missingBinding, BindingGraph graph) {
+ Key key = missingBinding.key();
+ StringBuilder errorMessage = new StringBuilder();
+ // Wildcards should have already been checked by DependencyRequestValidator.
+ verify(!key.type().getKind().equals(TypeKind.WILDCARD), "unexpected wildcard request: %s", key);
+ // TODO(ronshapiro): replace "provided" with "satisfied"?
+ errorMessage.append(key).append(" cannot be provided without ");
+ if (isValidImplicitProvisionKey(key, types)) {
+ errorMessage.append("an @Inject constructor or ");
+ }
+ errorMessage.append("an @Provides-"); // TODO(dpb): s/an/a
+ if (allIncomingDependenciesCanUseProduction(missingBinding, graph)) {
+ errorMessage.append(" or @Produces-");
+ }
+ errorMessage.append("annotated method.");
+ if (isValidMembersInjectionKey(key) && typeHasInjectionSites(key)) {
+ errorMessage.append(
+ " This type supports members injection but cannot be implicitly provided.");
+ }
+ graph.bindings(key).stream()
+ .map(binding -> binding.componentPath().currentComponent())
+ .distinct()
+ .forEach(
+ component ->
+ errorMessage
+ .append("\nA binding with matching key exists in component: ")
+ .append(component.getQualifiedName()));
+ return errorMessage.toString();
+ }
+
+ private boolean allIncomingDependenciesCanUseProduction(
+ MissingBinding missingBinding, BindingGraph graph) {
+ return graph.network().inEdges(missingBinding).stream()
+ .flatMap(instancesOf(DependencyEdge.class))
+ .allMatch(edge -> dependencyCanBeProduction(edge, graph));
+ }
+
+ // TODO(ronshapiro): merge with
+ // ProvisionDependencyOnProduerBindingValidator.dependencyCanUseProduction
+ private boolean dependencyCanBeProduction(DependencyEdge edge, BindingGraph graph) {
+ Node source = graph.network().incidentNodes(edge).source();
+ if (source instanceof ComponentNode) {
+ return canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind());
+ }
+ if (source instanceof dagger.model.Binding) {
+ return ((dagger.model.Binding) source).isProduction();
+ }
+ throw new IllegalArgumentException(
+ "expected a dagger.model.Binding or ComponentNode: " + source);
+ }
+
+ private boolean typeHasInjectionSites(Key key) {
+ return injectBindingRegistry
+ .getOrFindMembersInjectionBinding(key)
+ .map(binding -> !binding.injectionSites().isEmpty())
+ .orElse(false);
+ }
+}
diff --git a/java/dagger/internal/codegen/ModifiableAbstractMethodBindingExpression.java b/java/dagger/internal/codegen/ModifiableAbstractMethodBindingExpression.java
new file mode 100644
index 0000000..412acae
--- /dev/null
+++ b/java/dagger/internal/codegen/ModifiableAbstractMethodBindingExpression.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2018 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 javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PROTECTED;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.Accessibility;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A {@link BindingExpression} that invokes a method that encapsulates a binding that cannot be
+ * satisfied when generating the abstract base class implementation of a subcomponent. The
+ * (unimplemented) method is added to the {@link ComponentImplementation} when the dependency
+ * expression is requested. The method is overridden when generating the implementation of an
+ * ancestor component.
+ */
+abstract class ModifiableAbstractMethodBindingExpression extends BindingExpression {
+ private final ComponentImplementation componentImplementation;
+ private final ModifiableBindingType modifiableBindingType;
+ private final BindingRequest request;
+ private final Optional<ComponentMethodDescriptor> matchingComponentMethod;
+ private final DaggerTypes types;
+ private Optional<String> methodName;
+
+ ModifiableAbstractMethodBindingExpression(
+ ComponentImplementation componentImplementation,
+ ModifiableBindingType modifiableBindingType,
+ BindingRequest request,
+ Optional<ModifiableBindingMethod> matchingModifiableBindingMethod,
+ Optional<ComponentMethodDescriptor> matchingComponentMethod,
+ DaggerTypes types) {
+ this.componentImplementation = componentImplementation;
+ this.modifiableBindingType = modifiableBindingType;
+ this.request = request;
+ this.matchingComponentMethod = matchingComponentMethod;
+ this.types = types;
+ this.methodName =
+ initializeMethodName(matchingComponentMethod, matchingModifiableBindingMethod);
+ }
+
+ /**
+ * If this binding corresponds to an existing component method, or a known modifiable binding
+ * method, use them to initialize the method name, which is a signal to call the existing method
+ * rather than emit an abstract method.
+ */
+ private static Optional<String> initializeMethodName(
+ Optional<ComponentMethodDescriptor> matchingComponentMethod,
+ Optional<ModifiableBindingMethod> matchingModifiableBindingMethod) {
+ if (matchingComponentMethod.isPresent()) {
+ return Optional.of(matchingComponentMethod.get().methodElement().getSimpleName().toString());
+ }
+ if (matchingModifiableBindingMethod.isPresent()) {
+ return Optional.of(matchingModifiableBindingMethod.get().methodSpec().name);
+ }
+ return Optional.empty();
+ }
+
+ @Override
+ final Expression getDependencyExpression(ClassName requestingClass) {
+ addUnimplementedMethod();
+ return Expression.create(
+ returnType(),
+ componentImplementation.name().equals(requestingClass)
+ ? CodeBlock.of("$N()", methodName.get())
+ : CodeBlock.of("$T.this.$N()", componentImplementation.name(), methodName.get()));
+ }
+
+ private void addUnimplementedMethod() {
+ if (!methodName.isPresent()) {
+ // Only add the method once in case of repeated references to the missing binding.
+ methodName = Optional.of(chooseMethodName());
+ TypeMirror returnType = returnType();
+ componentImplementation.addModifiableBindingMethod(
+ modifiableBindingType,
+ request,
+ returnType,
+ MethodSpec.methodBuilder(methodName.get())
+ .addModifiers(PROTECTED, ABSTRACT)
+ .returns(TypeName.get(returnType))
+ .build(),
+ false /* finalized */);
+ }
+ }
+
+ /**
+ * The return type of this abstract method expression:
+ *
+ * <ul>
+ * <li>If there's a {@code matchingComponentMethod}, use its return type.
+ * <li>Otherwise, use the {@linkplain DaggerTypes#publiclyAccessibleType(TypeMirror) publicly
+ * accessible type} of the request. We can't use the {@linkplain
+ * Accessibility#isTypeAccessibleFrom(TypeMirror, String) type accessible from the current
+ * implementation's package} because a subclass implementation may be in a different package
+ * from which the request type is not accessible.
+ * </ul>
+ */
+ private TypeMirror returnType() {
+ if (matchingComponentMethod.isPresent()) {
+ return matchingComponentMethod.get().resolvedReturnType(types);
+ }
+
+ TypeMirror requestedType = request.requestedType(contributedType(), types);
+ return types.publiclyAccessibleType(requestedType);
+ }
+
+ /**
+ * The {@link ContributionBinding#contributedType() type contributed} by the binding of this
+ * expression. For missing bindings, this will be the key type.
+ */
+ protected abstract TypeMirror contributedType();
+
+ /** Returns a unique 'getter' method name for the current component. */
+ abstract String chooseMethodName();
+}
diff --git a/java/dagger/internal/codegen/ModifiableBindingExpressions.java b/java/dagger/internal/codegen/ModifiableBindingExpressions.java
new file mode 100644
index 0000000..76bcb8b
--- /dev/null
+++ b/java/dagger/internal/codegen/ModifiableBindingExpressions.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static java.util.stream.Collectors.toList;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.MethodSpec;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.ComponentImplementation.MethodSpecKind;
+import dagger.internal.codegen.MethodBindingExpression.MethodImplementationStrategy;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import java.util.Optional;
+
+/**
+ * A central repository of code expressions used to access modifiable bindings available to a
+ * component. A binding is modifiable if it can be modified across implementations of a
+ * subcomponent. This is only relevant for ahead-of-time subcomponents.
+ */
+final class ModifiableBindingExpressions {
+ private final Optional<ModifiableBindingExpressions> parent;
+ private final ComponentBindingExpressions bindingExpressions;
+ private final BindingGraph graph;
+ private final ComponentImplementation componentImplementation;
+ private final CompilerOptions compilerOptions;
+ private final DaggerTypes types;
+
+ ModifiableBindingExpressions(
+ Optional<ModifiableBindingExpressions> parent,
+ ComponentBindingExpressions bindingExpressions,
+ BindingGraph graph,
+ ComponentImplementation componentImplementation,
+ CompilerOptions compilerOptions,
+ DaggerTypes types) {
+ this.parent = parent;
+ this.bindingExpressions = bindingExpressions;
+ this.graph = graph;
+ this.componentImplementation = componentImplementation;
+ this.compilerOptions = compilerOptions;
+ this.types = types;
+ }
+
+ /**
+ * Adds {@code method} to the component implementation. If the binding for the method is
+ * modifiable, also registers the relevant modifiable binding information.
+ */
+ void addPossiblyModifiableComponentMethod(
+ ComponentMethodDescriptor componentMethod, MethodSpec method) {
+ BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
+ ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
+ if (modifiableBindingType.isModifiable()) {
+ componentImplementation.addModifiableComponentMethod(
+ modifiableBindingType,
+ request,
+ componentMethod.resolvedReturnType(types),
+ method,
+ newModifiableBindingWillBeFinalized(modifiableBindingType, request));
+ } else {
+ componentImplementation.addMethod(MethodSpecKind.COMPONENT_METHOD, method);
+ }
+ }
+
+ /**
+ * Returns the implementation of a modifiable binding method originally defined in a supertype
+ * implementation of this subcomponent. Returns {@link Optional#empty()} when the binding cannot
+ * or should not be modified by the current binding graph.
+ */
+ Optional<ModifiableBindingMethod> possiblyReimplementedMethod(
+ ModifiableBindingMethod modifiableBindingMethod) {
+ checkState(componentImplementation.superclassImplementation().isPresent());
+ BindingRequest request = modifiableBindingMethod.request();
+ ModifiableBindingType newModifiableBindingType = getModifiableBindingType(request);
+ ModifiableBindingType oldModifiableBindingType = modifiableBindingMethod.type();
+ boolean modifiableBindingTypeChanged =
+ !newModifiableBindingType.equals(oldModifiableBindingType);
+
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ // Don't reimplement modifiable bindings that were perceived to be provision bindings in a
+ // superclass implementation but are now production bindings.
+ if ((modifiableBindingTypeChanged
+ // Optional bindings don't need the same treatment since the only transition they can
+ // make is empty -> present. In that case, the Producer<Optional<T>> will be overridden
+ // and the absentOptionalProvider() will be a dangling reference that is never attempted
+ // to be overridden.
+ || newModifiableBindingType.equals(ModifiableBindingType.MULTIBINDING))
+ && resolvedBindings != null
+ && resolvedBindings.bindingType().equals(BindingType.PRODUCTION)
+ && !request.canBeSatisfiedByProductionBinding()) {
+ return oldModifiableBindingType.hasBaseClassImplementation()
+ ? Optional.empty()
+ : Optional.of(
+ reimplementedMethod(
+ modifiableBindingMethod,
+ newModifiableBindingType,
+ new PrunedConcreteMethodBindingExpression(),
+ componentImplementation.isAbstract()));
+ }
+
+ if (modifiableBindingTypeChanged
+ && !newModifiableBindingType.hasBaseClassImplementation()
+ && (oldModifiableBindingType.hasBaseClassImplementation()
+ || componentImplementation.isAbstract())) {
+ // We don't want to override one abstract method with another one. However, If the component
+ // is not abstract (such as a transition from GENERATED_INSTANCE -> MISSING), we must provide
+ // an implementation like normal.
+ return Optional.empty();
+ }
+
+ if (modifiableBindingTypeChanged
+ || shouldModifyImplementation(newModifiableBindingType, request)) {
+ boolean markMethodFinal =
+ knownModifiableBindingWillBeFinalized(modifiableBindingMethod)
+ // no need to mark the method final if the component implementation will be final
+ && componentImplementation.isAbstract();
+ return Optional.of(
+ reimplementedMethod(
+ modifiableBindingMethod,
+ newModifiableBindingType,
+ bindingExpressions.getBindingExpression(request),
+ markMethodFinal));
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Returns a new {@link ModifiableBindingMethod} that overrides {@code supertypeMethod} and is
+ * implemented with {@code bindingExpression}.
+ */
+ private ModifiableBindingMethod reimplementedMethod(
+ ModifiableBindingMethod supertypeMethod,
+ ModifiableBindingType newModifiableBindingType,
+ BindingExpression bindingExpression,
+ boolean markMethodFinal) {
+ MethodSpec baseMethod = supertypeMethod.methodSpec();
+ return supertypeMethod.reimplement(
+ newModifiableBindingType,
+ MethodSpec.methodBuilder(baseMethod.name)
+ .addModifiers(baseMethod.modifiers.contains(PUBLIC) ? PUBLIC : PROTECTED)
+ .addModifiers(markMethodFinal ? ImmutableSet.of(FINAL) : ImmutableSet.of())
+ .returns(baseMethod.returnType)
+ .addAnnotation(Override.class)
+ .addCode(
+ bindingExpression.getModifiableBindingMethodImplementation(
+ supertypeMethod, componentImplementation, types))
+ .build(),
+ markMethodFinal);
+ }
+
+ /**
+ * Returns true if a modifiable binding method that was registered in a superclass implementation
+ * of this subcomponent should be marked as "finalized" if it is being overridden by this
+ * subcomponent implementation. "Finalized" means we should not attempt to modify the binding in
+ * any subcomponent subclass.
+ */
+ private boolean knownModifiableBindingWillBeFinalized(
+ ModifiableBindingMethod modifiableBindingMethod) {
+ ModifiableBindingType newModifiableBindingType =
+ getModifiableBindingType(modifiableBindingMethod.request());
+ if (!newModifiableBindingType.isModifiable()) {
+ // If a modifiable binding has become non-modifiable it is final by definition.
+ return true;
+ }
+ return modifiableBindingWillBeFinalized(
+ newModifiableBindingType,
+ shouldModifyImplementation(newModifiableBindingType, modifiableBindingMethod.request()));
+ }
+
+ /**
+ * Returns true if a newly discovered modifiable binding method, once it is defined in this
+ * subcomponent implementation, should be marked as "finalized", meaning we should not attempt to
+ * modify the binding in any subcomponent subclass.
+ */
+ private boolean newModifiableBindingWillBeFinalized(
+ ModifiableBindingType modifiableBindingType, BindingRequest request) {
+ return modifiableBindingWillBeFinalized(
+ modifiableBindingType, shouldModifyImplementation(modifiableBindingType, request));
+ }
+
+ /**
+ * Returns true if we shouldn't attempt to further modify a modifiable binding once we complete
+ * the implementation for the current subcomponent.
+ */
+ private boolean modifiableBindingWillBeFinalized(
+ ModifiableBindingType modifiableBindingType, boolean modifyingBinding) {
+ switch (modifiableBindingType) {
+ case MISSING:
+ case BINDS_METHOD_WITH_MISSING_DEPENDENCY:
+ case GENERATED_INSTANCE:
+ case OPTIONAL:
+ case INJECTION:
+ // Once we modify any of the above a single time, then they are finalized.
+ return modifyingBinding;
+ case MULTIBINDING:
+ return false;
+ default:
+ throw new IllegalStateException(
+ String.format(
+ "Building binding expression for unsupported ModifiableBindingType [%s].",
+ modifiableBindingType));
+ }
+ }
+
+ /**
+ * Creates a binding expression for a binding if it may be modified across implementations of a
+ * subcomponent.
+ */
+ Optional<BindingExpression> maybeCreateModifiableBindingExpression(BindingRequest request) {
+ ModifiableBindingType type = getModifiableBindingType(request);
+ if (!type.isModifiable()) {
+ return Optional.empty();
+ }
+ return Optional.of(createModifiableBindingExpression(type, request));
+ }
+
+ /** Creates a binding expression for a modifiable binding. */
+ private BindingExpression createModifiableBindingExpression(
+ ModifiableBindingType type, BindingRequest request) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ Optional<ModifiableBindingMethod> matchingModifiableBindingMethod =
+ componentImplementation.getModifiableBindingMethod(request);
+ Optional<ComponentMethodDescriptor> matchingComponentMethod =
+ graph.componentDescriptor().firstMatchingComponentMethod(request);
+ switch (type) {
+ case GENERATED_INSTANCE:
+ // If the subcomponent is abstract then we need to define an (un-implemented)
+ // DeferredModifiableBindingExpression.
+ if (componentImplementation.isAbstract()) {
+ return new DeferredModifiableBindingExpression(
+ componentImplementation,
+ type,
+ resolvedBindings.contributionBinding(),
+ request,
+ matchingModifiableBindingMethod,
+ matchingComponentMethod,
+ types);
+ }
+ // Otherwise return a concrete implementation.
+ return bindingExpressions.createBindingExpression(resolvedBindings, request);
+
+ case MISSING:
+ // If we need an expression for a missing binding and the current implementation is
+ // abstract, then we need an (un-implemented) MissingBindingExpression.
+ if (componentImplementation.isAbstract()) {
+ return new MissingBindingExpression(
+ componentImplementation,
+ request,
+ matchingModifiableBindingMethod,
+ matchingComponentMethod,
+ types);
+ }
+ // Otherwise we assume that it is valid to have a missing binding as it is part of a
+ // dependency chain that has been passively pruned.
+ // TODO(b/117833324): Identify pruned bindings when generating the subcomponent
+ // implementation in which the bindings are pruned. If we hold a reference to the binding
+ // graph used to generate a given implementation then we can compare a implementation's
+ // graph with its superclass implementation's graph to detect pruned dependency branches.
+ return new PrunedConcreteMethodBindingExpression();
+
+ case BINDS_METHOD_WITH_MISSING_DEPENDENCY:
+ checkState(componentImplementation.isAbstract());
+ return new DeferredModifiableBindingExpression(
+ componentImplementation,
+ type,
+ resolvedBindings.contributionBinding(),
+ request,
+ matchingModifiableBindingMethod,
+ matchingComponentMethod,
+ types);
+
+ case OPTIONAL:
+ case MULTIBINDING:
+ case INJECTION:
+ return bindingExpressions.wrapInMethod(
+ resolvedBindings,
+ request,
+ bindingExpressions.createBindingExpression(resolvedBindings, request));
+ default:
+ throw new IllegalStateException(
+ String.format(
+ "Building binding expression for unsupported ModifiableBindingType [%s].", type));
+ }
+ }
+
+ /**
+ * The reason why a binding may need to be modified across implementations of a subcomponent, if
+ * at all.
+ */
+ ModifiableBindingType getModifiableBindingType(BindingRequest request) {
+ if (!compilerOptions.aheadOfTimeSubcomponents()) {
+ return ModifiableBindingType.NONE;
+ }
+
+ // When generating a component the binding is not considered modifiable. Bindings are modifiable
+ // only across subcomponent implementations.
+ if (!componentImplementation.componentDescriptor().isSubcomponent()) {
+ return ModifiableBindingType.NONE;
+ }
+
+ if (request.requestKind().filter(RequestKinds::isDerivedFromProvider).isPresent()) {
+ return ModifiableBindingType.NONE;
+ }
+
+ if (resolvedInThisComponent(request)) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ if (resolvedBindings.contributionBindings().isEmpty()) {
+ // TODO(ronshapiro): Confirm whether a resolved binding must have a single contribution
+ // binding.
+ return ModifiableBindingType.NONE;
+ }
+
+ ContributionBinding binding = resolvedBindings.contributionBinding();
+ if (binding.requiresGeneratedInstance()) {
+ return ModifiableBindingType.GENERATED_INSTANCE;
+ }
+
+ if (binding.kind().equals(BindingKind.DELEGATE)
+ && graph
+ .contributionBindings()
+ .get(getOnlyElement(binding.dependencies()).key())
+ .isEmpty()) {
+ return ModifiableBindingType.BINDS_METHOD_WITH_MISSING_DEPENDENCY;
+ }
+
+ if (binding.kind().equals(BindingKind.OPTIONAL) && binding.dependencies().isEmpty()) {
+ // only empty optional bindings can be modified
+ return ModifiableBindingType.OPTIONAL;
+ }
+
+ if (binding.isSyntheticMultibinding()) {
+ return ModifiableBindingType.MULTIBINDING;
+ }
+
+ if (binding.kind().equals(BindingKind.INJECTION)) {
+ return ModifiableBindingType.INJECTION;
+ }
+ } else if (!resolvableBinding(request)) {
+ return ModifiableBindingType.MISSING;
+ }
+
+ return ModifiableBindingType.NONE;
+ }
+
+ /**
+ * Returns true if the current binding graph can, and should, modify a binding by overriding a
+ * modifiable binding method.
+ */
+ private boolean shouldModifyImplementation(
+ ModifiableBindingType modifiableBindingType, BindingRequest request) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ if (request.requestKind().isPresent()) {
+ switch (request.requestKind().get()) {
+ case FUTURE:
+ // Futures backed by production bindings are always requested by a Producer.get() call, so
+ // if the binding is modifiable, the producer will be wrapped in a modifiable method and
+ // the future can refer to that method; even if the producer binding is modified,
+ // getModifiableProducer().get() will never need to be modified. Furthermore, because
+ // cancellation is treated by wrapped producers, and those producers point to the
+ // modifiable producer wrapper methods, we never need or want to change the access of
+ // these wrapped producers for entry methods
+ //
+ // Futures backed by provision bindings are inlined and contain no wrapping producer, so
+ // if the binding is modifiable and is resolved as a provision binding in a superclass
+ // but later resolved as a production binding, we can't take the same shortcut as before.
+ Optional<ComponentImplementation> superclassImplementation =
+ componentImplementation.superclassImplementation();
+ if (superclassImplementation.isPresent()) {
+ if (superclassImplementation.get().isDeserializedImplementation()) {
+ // TODO(b/117833324): consider serializing the binding type so that we don't need to
+ // branch here. Or, instead, consider removing this optimization entirely if there
+ // aren't that many FUTURE entry point methods to justify the extra code.
+ break;
+ } else {
+ return bindingTypeChanged(request, resolvedBindings);
+ }
+ }
+ return false;
+
+ case LAZY:
+ case PROVIDER_OF_LAZY:
+ // Lazy and ProviderOfLazy are always created from a Provider, and therefore this request
+ // never needs to be modifiable. It will refer (via DoubleCheck.lazy() or
+ // ProviderOfLazy.create()) to the modifiable method and not the framework instance.
+ return false;
+
+ case MEMBERS_INJECTION:
+ case PRODUCED:
+ // MEMBERS_INJECTION has a completely different code path for binding expressions, and
+ // PRODUCED requests are only requestable in @Produces methods, which are hidden from
+ // generated components inside Producer factories
+ throw new AssertionError(request);
+
+ case INSTANCE:
+ case PROVIDER:
+ case PRODUCER:
+ // These may be modifiable, so run through the regular logic. They're spelled out
+ // explicitly so that ErrorProne will detect if a new enum value is created and missing
+ // from this list.
+ break;
+ }
+ }
+
+ switch (modifiableBindingType) {
+ case GENERATED_INSTANCE:
+ return !componentImplementation.isAbstract();
+
+ case MISSING:
+ // TODO(b/117833324): investigate beder@'s comment about having intermediate component
+ // ancestors satisfy missing bindings of their children with their own missing binding
+ // methods so that we can minimize the cases where we need to reach into doubly-nested
+ // descendant component implementations.
+
+ // Implement a missing binding if it is resolvable, or if we're generating a concrete
+ // subcomponent implementation. If a binding is still missing when the subcomponent
+ // implementation is concrete then it is assumed to be part of a dependency that would have
+ // been passively pruned when implementing the full component hierarchy.
+ return resolvableBinding(request) || !componentImplementation.isAbstract();
+
+ case BINDS_METHOD_WITH_MISSING_DEPENDENCY:
+ DependencyRequest dependency =
+ getOnlyElement(resolvedBindings.contributionBinding().dependencies());
+ return !graph.contributionBindings().get(dependency.key()).isEmpty();
+
+ case OPTIONAL:
+ // Only override optional binding methods if we have a non-empty binding.
+ return !resolvedBindings.contributionBinding().dependencies().isEmpty();
+
+ case MULTIBINDING:
+ // Only modify a multibinding if there are new contributions.
+ return !componentImplementation
+ .superclassContributionsMade(request)
+ .containsAll(
+ resolvedBindings.contributionBinding().dependencies().stream()
+ .map(DependencyRequest::key)
+ .collect(toList()));
+
+ case INJECTION:
+ return !resolvedBindings.contributionBinding().kind().equals(BindingKind.INJECTION);
+
+ default:
+ throw new IllegalStateException(
+ String.format(
+ "Overriding modifiable binding method with unsupported ModifiableBindingType [%s].",
+ modifiableBindingType));
+ }
+ }
+
+ /**
+ * Returns {@code true} if the {@link BindingType} for {@code request} is not the same in this
+ * implementation and it's superclass implementation.
+ */
+ private boolean bindingTypeChanged(BindingRequest request, ResolvedBindings resolvedBindings) {
+ BindingGraph superclassGraph =
+ componentImplementation.superclassImplementation().get().graph();
+ ResolvedBindings superclassBindings = superclassGraph.resolvedBindings(request);
+ return superclassBindings != null
+ && resolvedBindings != null
+ && !superclassBindings.bindingType().equals(resolvedBindings.bindingType());
+ }
+
+ /**
+ * Returns true if the binding can be resolved by the graph for this component or any parent
+ * component.
+ */
+ private boolean resolvableBinding(BindingRequest request) {
+ for (ModifiableBindingExpressions expressions = this;
+ expressions != null;
+ expressions = expressions.parent.orElse(null)) {
+ if (expressions.resolvedInThisComponent(request)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Returns true if the binding can be resolved by the graph for this component. */
+ private boolean resolvedInThisComponent(BindingRequest request) {
+ ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
+ return resolvedBindings != null
+ && !resolvedBindings.bindingsOwnedBy(graph.componentDescriptor()).isEmpty();
+ }
+
+ /**
+ * Wraps a modifiable binding expression in a method that can be overridden in a subclass
+ * implementation.
+ */
+ BindingExpression wrapInModifiableMethodBindingExpression(
+ BindingRequest request,
+ ResolvedBindings resolvedBindings,
+ MethodImplementationStrategy methodImplementationStrategy,
+ BindingExpression wrappedBindingExpression) {
+ ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
+ checkState(modifiableBindingType.isModifiable());
+ return new ModifiableConcreteMethodBindingExpression(
+ request,
+ resolvedBindings,
+ methodImplementationStrategy,
+ wrappedBindingExpression,
+ modifiableBindingType,
+ componentImplementation,
+ newModifiableBindingWillBeFinalized(modifiableBindingType, request),
+ types);
+ }
+}
diff --git a/java/dagger/internal/codegen/ModifiableBindingMethods.java b/java/dagger/internal/codegen/ModifiableBindingMethods.java
new file mode 100644
index 0000000..ead708d
--- /dev/null
+++ b/java/dagger/internal/codegen/ModifiableBindingMethods.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Verify.verify;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.squareup.javapoet.MethodSpec;
+import java.util.Map;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A registry for those methods which each wrap a binding whose definition may be modified across
+ * each class in the class hierarchy implementing a subcomponent. Subcomponent implementations are
+ * spread across a class hierarchy when generating ahead-of-time subcomponents. There is one
+ * subcomponent implementation class for each of the subcomponent's ancestor components. An instance
+ * of {@link ModifiableBindingMethod} is associated with a single class in this hierarchy. For a
+ * given subcomponent implementation class we can use the {@link ModifiableBindingMethod}s of its
+ * superclasses to know what binding methods to attempt to modify.
+ */
+final class ModifiableBindingMethods {
+ private final Map<BindingRequest, ModifiableBindingMethod> methods = Maps.newLinkedHashMap();
+
+ /** Registers a new method encapsulating a modifiable binding. */
+ void addModifiableMethod(
+ ModifiableBindingType type,
+ BindingRequest request,
+ TypeMirror returnType,
+ MethodSpec method,
+ boolean finalized) {
+ // It's ok for the type to not be modifiable, since it could be overriding a previously
+ // modifiable method (such as with addReimplementedMethod).
+ addMethod(ModifiableBindingMethod.create(type, request, returnType, method, finalized));
+ }
+
+ /** Registers a reimplemented modifiable method. */
+ void addReimplementedMethod(ModifiableBindingMethod method) {
+ addMethod(method);
+ }
+
+ private void addMethod(ModifiableBindingMethod method) {
+ ModifiableBindingMethod previousMethod = methods.put(method.request(), method);
+ verify(
+ previousMethod == null,
+ "registering %s but %s is already registered for the same binding request",
+ method,
+ previousMethod);
+ }
+
+ /** Returns all {@link ModifiableBindingMethod}s that have not been marked as finalized. */
+ ImmutableMap<BindingRequest, ModifiableBindingMethod> getNonFinalizedMethods() {
+ return ImmutableMap.copyOf(Maps.filterValues(methods, m -> !m.finalized()));
+ }
+
+ /** Returns the {@link ModifiableBindingMethod} for the given binding if present. */
+ Optional<ModifiableBindingMethod> getMethod(BindingRequest request) {
+ return Optional.ofNullable(methods.get(request));
+ }
+
+ /** Returns all of the {@link ModifiableBindingMethod}s. */
+ ImmutableList<ModifiableBindingMethod> allMethods() {
+ return ImmutableList.copyOf(methods.values());
+ }
+
+ /** Whether a given binding has been marked as finalized. */
+ // TODO(ronshapiro): possibly rename this to something that indicates that the BindingRequest for
+ // `method` has been finalized in *this* component implementation?
+ boolean finalized(ModifiableBindingMethod method) {
+ ModifiableBindingMethod storedMethod = methods.get(method.request());
+ return storedMethod != null && storedMethod.finalized();
+ }
+
+ @AutoValue
+ abstract static class ModifiableBindingMethod {
+ private static ModifiableBindingMethod create(
+ ModifiableBindingType type,
+ BindingRequest request,
+ TypeMirror returnType,
+ MethodSpec methodSpec,
+ boolean finalized) {
+ return new AutoValue_ModifiableBindingMethods_ModifiableBindingMethod(
+ type, request, MoreTypes.equivalence().wrap(returnType), methodSpec, finalized);
+ }
+
+ /** Creates a {@ModifiableBindingMethod} that reimplements the current method. */
+ ModifiableBindingMethod reimplement(
+ ModifiableBindingType newModifiableBindingType,
+ MethodSpec newImplementation,
+ boolean finalized) {
+ return new AutoValue_ModifiableBindingMethods_ModifiableBindingMethod(
+ newModifiableBindingType, request(), returnTypeWrapper(), newImplementation, finalized);
+ }
+
+ abstract ModifiableBindingType type();
+
+ abstract BindingRequest request();
+
+ final TypeMirror returnType() {
+ return returnTypeWrapper().get();
+ }
+
+ abstract Equivalence.Wrapper<TypeMirror> returnTypeWrapper();
+
+ abstract MethodSpec methodSpec();
+
+ abstract boolean finalized();
+
+ /** Whether a {@link ModifiableBindingMethod} is for the same binding request. */
+ boolean fulfillsSameRequestAs(ModifiableBindingMethod other) {
+ return request().equals(other.request());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ModifiableBindingType.java b/java/dagger/internal/codegen/ModifiableBindingType.java
new file mode 100644
index 0000000..7e43ec1
--- /dev/null
+++ b/java/dagger/internal/codegen/ModifiableBindingType.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 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 com.google.common.collect.ImmutableSet;
+
+/**
+ * A label for a binding indicating whether, and how, it may be redefined across implementations of
+ * a subcomponent.
+ *
+ * <p>A subcomponent has multiple implementations only when generating ahead-of-time subcomponents.
+ * Specifically, each subcomponent type in a component hierarchy is implemented as an abstract
+ * class, and descendent components are implemented as abstract inner classes. A consequence of this
+ * is that a given subcomponent has an implementation for each ancestor component. Each
+ * implementation represents a different sub-binding-graph of the full subcomponent. A binding is
+ * modifiable if it's definition may change depending on the characteristics of its ancestor
+ * components.
+ */
+enum ModifiableBindingType {
+ /** A binding that is not modifiable */
+ NONE,
+
+ /**
+ * A binding that is missing when generating the abstract base class implementation of a
+ * subcomponent.
+ */
+ MISSING,
+
+ /**
+ * A binding that requires an instance of a generated type. These binding are modifiable in the
+ * sense that they are encapsulated in a method when they are first required, possibly in an
+ * abstract implementation of a subcomponent, where, in general, no concrete instances of
+ * generated types are available, and the method is satisfied in a final concrete implementation.
+ */
+ GENERATED_INSTANCE,
+
+ /**
+ * Multibindings may have contributions come from any ancestor component. Therefore, each
+ * implementation of a subcomponent may have newly available contributions, and so the binding
+ * method is reimplemented with each subcomponent implementation.
+ */
+ MULTIBINDING,
+
+ /**
+ * A Optional binding that may be empty when looking at a partial binding graph, but bound to a
+ * value when considering the complete binding graph, thus modifiable across subcomponent
+ * implementations.
+ */
+ OPTIONAL,
+
+ /**
+ * If a binding is defined according to an {@code @Inject} annotated constructor on the object it
+ * is valid for that binding to be redefined a single time by an {@code @Provides} annotated
+ * module method. It is possible that the {@code @Provides} binding isn't available in a partial
+ * binding graph, but becomes available when considering a more complete binding graph, therefore
+ * such bindings are modifiable across subcomponent implementations.
+ */
+ INJECTION,
+
+ /**
+ * A {@link dagger.Binds} method whose dependency is {@link #MISSING}.
+ *
+ * <p>There's not much to do for @Binds bindings if the dependency is missing - at best, if the
+ * dependency is a weaker scope/unscoped, we save only a few lines that implement the scoping. But
+ * it's also possible, if the dependency is the same or stronger scope, that no extra code is
+ * necessary, in which case we'd be overriding a method that just returns another.
+ */
+ BINDS_METHOD_WITH_MISSING_DEPENDENCY,
+ ;
+
+ private static final ImmutableSet<ModifiableBindingType> TYPES_WITH_BASE_CLASS_IMPLEMENTATIONS =
+ ImmutableSet.of(NONE, INJECTION, MULTIBINDING, OPTIONAL);
+
+ boolean isModifiable() {
+ return !equals(NONE);
+ }
+
+ /**
+ * Returns true if the method encapsulating the modifiable binding should have a concrete
+ * implementation in the abstract base class for a subcomponent.
+ */
+ boolean hasBaseClassImplementation() {
+ return TYPES_WITH_BASE_CLASS_IMPLEMENTATIONS.contains(this);
+ }
+}
diff --git a/java/dagger/internal/codegen/ModifiableConcreteMethodBindingExpression.java b/java/dagger/internal/codegen/ModifiableConcreteMethodBindingExpression.java
new file mode 100644
index 0000000..907466b
--- /dev/null
+++ b/java/dagger/internal/codegen/ModifiableConcreteMethodBindingExpression.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.util.Optional;
+
+/**
+ * A binding expression that wraps a modifiable binding expression in a public, no-arg method.
+ *
+ * <p>Dependents of this binding expression will just call the modifiable binding method.
+ */
+final class ModifiableConcreteMethodBindingExpression extends MethodBindingExpression {
+
+ private final BindingRequest request;
+ private final ModifiableBindingType modifiableBindingType;
+ private final ComponentImplementation componentImplementation;
+ private final boolean bindingCannotBeModified;
+ private Optional<String> methodName = Optional.empty();
+
+ ModifiableConcreteMethodBindingExpression(
+ BindingRequest request,
+ ResolvedBindings resolvedBindings,
+ MethodImplementationStrategy methodImplementationStrategy,
+ BindingExpression wrappedBindingExpression,
+ ModifiableBindingType modifiableBindingType,
+ ComponentImplementation componentImplementation,
+ boolean bindingCannotBeModified,
+ DaggerTypes types) {
+ super(
+ request,
+ resolvedBindings,
+ methodImplementationStrategy,
+ wrappedBindingExpression,
+ componentImplementation,
+ types);
+ this.request = checkNotNull(request);
+ this.modifiableBindingType = checkNotNull(modifiableBindingType);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.bindingCannotBeModified = bindingCannotBeModified;
+ }
+
+ @Override
+ protected void addMethod() {
+ if (methodName.isPresent()) {
+ return;
+ }
+
+ if (supertypeModifiableBindingMethod().isPresent()) {
+ methodName = supertypeModifiableBindingMethod().map(method -> method.methodSpec().name);
+ return;
+ }
+
+ // Add the modifiable binding method to the component if we haven't already.
+ methodName = Optional.of(componentImplementation.getUniqueMethodName(request));
+ componentImplementation.addModifiableBindingMethod(
+ modifiableBindingType,
+ request,
+ returnType(),
+ methodBuilder(methodName.get())
+ .addModifiers(bindingCannotBeModified ? PRIVATE : PROTECTED)
+ .returns(TypeName.get(returnType()))
+ .addCode(methodBody())
+ .build(),
+ bindingCannotBeModified);
+ }
+
+ @Override
+ protected String methodName() {
+ checkState(methodName.isPresent(), "addMethod() must be called before methodName().");
+ return methodName.get();
+ }
+
+ @Override
+ protected boolean isModifiableImplementationMethod() {
+ return true;
+ }
+}
diff --git a/java/dagger/internal/codegen/ModuleAnnotation.java b/java/dagger/internal/codegen/ModuleAnnotation.java
new file mode 100644
index 0000000..27dd071
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleAnnotation.java
@@ -0,0 +1,135 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreTypes.asTypeElement;
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
+
+import com.google.auto.common.MoreTypes;
+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.ImmutableSet;
+import dagger.Module;
+import dagger.producers.ProducerModule;
+import java.lang.annotation.Annotation;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.TypeElement;
+
+/** A {@code @Module} or {@code @ProducerModule} annotation. */
+@AutoValue
+abstract class ModuleAnnotation {
+ private static final ImmutableSet<Class<? extends Annotation>> MODULE_ANNOTATIONS =
+ ImmutableSet.of(Module.class, ProducerModule.class);
+
+ /** The annotation itself. */
+ // This does not use AnnotationMirrors.equivalence() because we want the actual annotation
+ // instance.
+ abstract AnnotationMirror annotation();
+
+ /** The type of the annotation. */
+ @Memoized
+ Class<?> annotationClass() {
+ try {
+ return Class.forName(
+ asTypeElement(annotation().getAnnotationType()).getQualifiedName().toString());
+ } catch (ClassNotFoundException e) {
+ AssertionError assertionError = new AssertionError();
+ assertionError.initCause(e);
+ throw assertionError;
+ }
+ }
+
+ /**
+ * The types specified in the {@code includes} attribute.
+ *
+ * @throws IllegalArgumentException if any of the values are error types
+ */
+ @Memoized
+ ImmutableList<TypeElement> includes() {
+ return includesAsAnnotationValues().stream()
+ .map(MoreAnnotationValues::asType)
+ .map(MoreTypes::asTypeElement)
+ .collect(toImmutableList());
+ }
+
+ /** The values specified in the {@code includes} attribute. */
+ @Memoized
+ ImmutableList<AnnotationValue> includesAsAnnotationValues() {
+ return asAnnotationValues(getAnnotationValue(annotation(), "includes"));
+ }
+
+ /**
+ * The types specified in the {@code subcomponents} attribute.
+ *
+ * @throws IllegalArgumentException if any of the values are error types
+ */
+ @Memoized
+ ImmutableList<TypeElement> subcomponents() {
+ return subcomponentsAsAnnotationValues().stream()
+ .map(MoreAnnotationValues::asType)
+ .map(MoreTypes::asTypeElement)
+ .collect(toImmutableList());
+ }
+
+ /** The values specified in the {@code subcomponents} attribute. */
+ @Memoized
+ ImmutableList<AnnotationValue> subcomponentsAsAnnotationValues() {
+ return asAnnotationValues(getAnnotationValue(annotation(), "subcomponents"));
+ }
+
+ /** Returns {@code true} if the argument is a {@code @Module} or {@code @ProducerModule}. */
+ static boolean isModuleAnnotation(AnnotationMirror annotation) {
+ return MODULE_ANNOTATIONS.stream()
+ .map(Class::getCanonicalName)
+ .anyMatch(asTypeElement(annotation.getAnnotationType()).getQualifiedName()::contentEquals);
+ }
+
+ /** The module annotation types. */
+ static ImmutableSet<Class<? extends Annotation>> moduleAnnotations() {
+ return MODULE_ANNOTATIONS;
+ }
+
+ /**
+ * Creates an object that represents a {@code @Module} or {@code @ProducerModule}.
+ *
+ * @throws IllegalArgumentException if {@link #isModuleAnnotation(AnnotationMirror)} returns
+ * {@code false}
+ */
+ static ModuleAnnotation moduleAnnotation(AnnotationMirror annotation) {
+ checkArgument(
+ isModuleAnnotation(annotation),
+ "%s is not a Module or ProducerModule annotation",
+ annotation);
+ return new AutoValue_ModuleAnnotation(annotation);
+ }
+
+ /**
+ * Returns an object representing the {@code @Module} or {@code @ProducerModule} annotation if one
+ * annotates {@code typeElement}.
+ */
+ static Optional<ModuleAnnotation> moduleAnnotation(TypeElement typeElement) {
+ return getAnyAnnotation(typeElement, Module.class, ProducerModule.class)
+ .map(ModuleAnnotation::moduleAnnotation);
+ }
+}
diff --git a/java/dagger/internal/codegen/ModuleConstructorProxyGenerator.java b/java/dagger/internal/codegen/ModuleConstructorProxyGenerator.java
new file mode 100644
index 0000000..5f0d687
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleConstructorProxyGenerator.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.ModuleKind.checkIsModule;
+import static dagger.internal.codegen.ModuleProxies.nonPublicNullaryConstructor;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Generates a {@code public static} method that calls {@code new SomeModule()} for modules that
+ * don't have {@linkplain ModuleProxies#nonPublicNullaryConstructor(TypeElement,
+ * DaggerElements) publicly accessible constructors}.
+ */
+// TODO(dpb): See if this can become a SourceFileGenerator<ModuleDescriptor> instead. Doing so may
+// cause ModuleProcessingStep to defer elements multiple times.
+final class ModuleConstructorProxyGenerator extends SourceFileGenerator<TypeElement> {
+ private final DaggerElements elements;
+
+ @Inject
+ ModuleConstructorProxyGenerator(
+ Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ this.elements = elements;
+ }
+
+ @Override
+ ClassName nameGeneratedType(TypeElement moduleElement) {
+ return ModuleProxies.constructorProxyTypeName(moduleElement);
+ }
+
+ @Override
+ Element originatingElement(TypeElement moduleElement) {
+ return moduleElement;
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, TypeElement moduleElement) {
+ checkIsModule(moduleElement);
+ return nonPublicNullaryConstructor(moduleElement, elements).isPresent()
+ ? Optional.of(buildProxy(generatedTypeName, moduleElement))
+ : Optional.empty();
+ }
+
+ private TypeSpec.Builder buildProxy(ClassName generatedTypeName, TypeElement moduleElement) {
+ return classBuilder(generatedTypeName)
+ .addModifiers(PUBLIC, FINAL)
+ .addMethod(constructorBuilder().addModifiers(PRIVATE).build())
+ .addMethod(
+ methodBuilder("newInstance")
+ .addModifiers(PUBLIC, STATIC)
+ .returns(ClassName.get(moduleElement))
+ .addStatement("return new $T()", moduleElement)
+ .build());
+ }
+}
diff --git a/java/dagger/internal/codegen/ModuleDescriptor.java b/java/dagger/internal/codegen/ModuleDescriptor.java
new file mode 100644
index 0000000..ac7a4b7
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleDescriptor.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.MoreElements.getPackage;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.transform;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
+import static dagger.internal.codegen.SourceFiles.classFileName;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent;
+import static javax.lang.model.type.TypeKind.DECLARED;
+import static javax.lang.model.type.TypeKind.NONE;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.graph.Traverser;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.squareup.javapoet.ClassName;
+import dagger.Binds;
+import dagger.BindsOptionalOf;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.model.Key;
+import dagger.multibindings.Multibinds;
+import dagger.producers.Produces;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+@AutoValue
+abstract class ModuleDescriptor {
+
+ abstract TypeElement moduleElement();
+
+ abstract ImmutableSet<TypeElement> includedModules();
+
+ abstract ImmutableSet<ContributionBinding> bindings();
+
+ /** The multibinding declarations contained in this module. */
+ abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
+
+ /** The {@link Module#subcomponents() subcomponent declarations} contained in this module. */
+ abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
+
+ /** The {@link Binds} method declarations that define delegate bindings. */
+ abstract ImmutableSet<DelegateDeclaration> delegateDeclarations();
+
+ /** The {@link BindsOptionalOf} method declarations that define optional bindings. */
+ abstract ImmutableSet<OptionalBindingDeclaration> optionalDeclarations();
+
+ /** The kind of the module. */
+ abstract ModuleKind kind();
+
+ /** Returns all of the bindings declared in this module. */
+ @Memoized
+ ImmutableSet<BindingDeclaration> allBindingDeclarations() {
+ return ImmutableSet.<BindingDeclaration>builder()
+ .addAll(bindings())
+ .addAll(delegateDeclarations())
+ .addAll(multibindingDeclarations())
+ .addAll(optionalDeclarations())
+ .addAll(subcomponentDeclarations())
+ .build();
+ }
+
+ /** Returns the keys of all bindings declared by this module. */
+ ImmutableSet<Key> allBindingKeys() {
+ return allBindingDeclarations().stream().map(BindingDeclaration::key).collect(toImmutableSet());
+ }
+
+ @Singleton
+ static final class Factory implements ClearableCache {
+ private final DaggerElements elements;
+ private final BindingFactory bindingFactory;
+ private final MultibindingDeclaration.Factory multibindingDeclarationFactory;
+ private final DelegateDeclaration.Factory bindingDelegateDeclarationFactory;
+ private final SubcomponentDeclaration.Factory subcomponentDeclarationFactory;
+ private final OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory;
+ private final Map<TypeElement, ModuleDescriptor> cache = new HashMap<>();
+
+ @Inject
+ Factory(
+ DaggerElements elements,
+ BindingFactory bindingFactory,
+ MultibindingDeclaration.Factory multibindingDeclarationFactory,
+ DelegateDeclaration.Factory bindingDelegateDeclarationFactory,
+ SubcomponentDeclaration.Factory subcomponentDeclarationFactory,
+ OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory) {
+ this.elements = elements;
+ this.bindingFactory = bindingFactory;
+ this.multibindingDeclarationFactory = multibindingDeclarationFactory;
+ this.bindingDelegateDeclarationFactory = bindingDelegateDeclarationFactory;
+ this.subcomponentDeclarationFactory = subcomponentDeclarationFactory;
+ this.optionalBindingDeclarationFactory = optionalBindingDeclarationFactory;
+ }
+
+ ModuleDescriptor create(TypeElement moduleElement) {
+ return reentrantComputeIfAbsent(cache, moduleElement, this::createUncached);
+ }
+
+ ModuleDescriptor createUncached(TypeElement moduleElement) {
+ ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
+ ImmutableSet.Builder<DelegateDeclaration> delegates = ImmutableSet.builder();
+ ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations =
+ ImmutableSet.builder();
+ ImmutableSet.Builder<OptionalBindingDeclaration> optionalDeclarations =
+ ImmutableSet.builder();
+
+ for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
+ if (isAnnotationPresent(moduleMethod, Provides.class)) {
+ bindings.add(bindingFactory.providesMethodBinding(moduleMethod, moduleElement));
+ }
+ if (isAnnotationPresent(moduleMethod, Produces.class)) {
+ bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement));
+ }
+ if (isAnnotationPresent(moduleMethod, Binds.class)) {
+ delegates.add(bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement));
+ }
+ if (isAnnotationPresent(moduleMethod, Multibinds.class)) {
+ multibindingDeclarations.add(
+ multibindingDeclarationFactory.forMultibindsMethod(moduleMethod, moduleElement));
+ }
+ if (isAnnotationPresent(moduleMethod, BindsOptionalOf.class)) {
+ optionalDeclarations.add(
+ optionalBindingDeclarationFactory.forMethod(moduleMethod, moduleElement));
+ }
+ }
+
+ return new AutoValue_ModuleDescriptor(
+ moduleElement,
+ ImmutableSet.copyOf(collectIncludedModules(new LinkedHashSet<>(), moduleElement)),
+ bindings.build(),
+ multibindingDeclarations.build(),
+ subcomponentDeclarationFactory.forModule(moduleElement),
+ delegates.build(),
+ optionalDeclarations.build(),
+ ModuleKind.forAnnotatedElement(moduleElement).get());
+ }
+
+ /** Returns all the modules transitively included by given modules, including the arguments. */
+ ImmutableSet<ModuleDescriptor> transitiveModules(Iterable<TypeElement> modules) {
+ return ImmutableSet.copyOf(
+ Traverser.forGraph(
+ (ModuleDescriptor module) -> transform(module.includedModules(), this::create))
+ .depthFirstPreOrder(transform(modules, this::create)));
+ }
+
+ @CanIgnoreReturnValue
+ private Set<TypeElement> collectIncludedModules(
+ Set<TypeElement> includedModules, TypeElement moduleElement) {
+ TypeMirror superclass = moduleElement.getSuperclass();
+ if (!superclass.getKind().equals(NONE)) {
+ verify(superclass.getKind().equals(DECLARED));
+ TypeElement superclassElement = MoreTypes.asTypeElement(superclass);
+ if (!superclassElement.getQualifiedName().contentEquals(Object.class.getCanonicalName())) {
+ collectIncludedModules(includedModules, superclassElement);
+ }
+ }
+ moduleAnnotation(moduleElement)
+ .ifPresent(
+ moduleAnnotation -> {
+ includedModules.addAll(moduleAnnotation.includes());
+ includedModules.addAll(implicitlyIncludedModules(moduleElement));
+ });
+ return includedModules;
+ }
+
+ // @ContributesAndroidInjector generates a module that is implicitly included in the enclosing
+ // module
+ private ImmutableSet<TypeElement> implicitlyIncludedModules(TypeElement moduleElement) {
+ TypeElement contributesAndroidInjector =
+ elements.getTypeElement("dagger.android.ContributesAndroidInjector");
+ if (contributesAndroidInjector == null) {
+ return ImmutableSet.of();
+ }
+ return methodsIn(moduleElement.getEnclosedElements()).stream()
+ .filter(method -> isAnnotationPresent(method, contributesAndroidInjector.asType()))
+ .map(method -> elements.checkTypePresent(implicitlyIncludedModuleName(method)))
+ .collect(toImmutableSet());
+ }
+
+ private String implicitlyIncludedModuleName(ExecutableElement method) {
+ return getPackage(method).getQualifiedName()
+ + "."
+ + classFileName(ClassName.get(MoreElements.asType(method.getEnclosingElement())))
+ + "_"
+ + LOWER_CAMEL.to(UPPER_CAMEL, method.getSimpleName().toString());
+ }
+
+ @Override
+ public void clearCache() {
+ cache.clear();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ModuleGenerator.java b/java/dagger/internal/codegen/ModuleGenerator.java
new file mode 100644
index 0000000..161b47b
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleGenerator.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+/** Qualifier for a {@link SourceFileGenerator} for modules. */
+@Qualifier
+@Retention(RUNTIME)
+@interface ModuleGenerator {}
diff --git a/java/dagger/internal/codegen/ModuleKind.java b/java/dagger/internal/codegen/ModuleKind.java
new file mode 100644
index 0000000..c93d8ce
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleKind.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import dagger.Module;
+import dagger.producers.ProducerModule;
+import java.lang.annotation.Annotation;
+import java.util.EnumSet;
+import java.util.Optional;
+import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.TypeElement;
+
+/** Enumeration of the kinds of modules. */
+enum ModuleKind {
+ /** {@code @Module} */
+ MODULE(Module.class),
+
+ /** {@code @ProducerModule} */
+ PRODUCER_MODULE(ProducerModule.class);
+
+ /** Returns the annotations for modules of the given kinds. */
+ static ImmutableSet<Class<? extends Annotation>> annotationsFor(Set<ModuleKind> kinds) {
+ return kinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the kind of an annotated element if it is annotated with one of the module {@linkplain
+ * #annotation() annotations}.
+ *
+ * @throws IllegalArgumentException if the element is annotated with more than one of the module
+ * annotations
+ */
+ static Optional<ModuleKind> forAnnotatedElement(TypeElement element) {
+ Set<ModuleKind> kinds = EnumSet.noneOf(ModuleKind.class);
+ for (ModuleKind kind : values()) {
+ if (MoreElements.isAnnotationPresent(element, kind.annotation())) {
+ kinds.add(kind);
+ }
+ }
+
+ if (kinds.size() > 1) {
+ throw new IllegalArgumentException(
+ element + " cannot be annotated with more than one of " + annotationsFor(kinds));
+ }
+ return kinds.stream().findAny();
+ }
+
+ static void checkIsModule(TypeElement moduleElement) {
+ checkArgument(forAnnotatedElement(moduleElement).isPresent());
+ }
+
+ private final Class<? extends Annotation> moduleAnnotation;
+
+ ModuleKind(Class<? extends Annotation> moduleAnnotation) {
+ this.moduleAnnotation = moduleAnnotation;
+ }
+
+ /**
+ * Returns the annotation mirror for this module kind on the given type.
+ *
+ * @throws IllegalArgumentException if the annotation is not present on the type
+ */
+ AnnotationMirror getModuleAnnotation(TypeElement element) {
+ Optional<AnnotationMirror> result = getAnnotationMirror(element, moduleAnnotation);
+ checkArgument(
+ result.isPresent(), "annotation %s is not present on type %s", moduleAnnotation, element);
+ return result.get();
+ }
+
+ /** Returns the annotation that marks a module of this kind. */
+ Class<? extends Annotation> annotation() {
+ return moduleAnnotation;
+ }
+
+ /** Returns the kinds of modules that a module of this kind is allowed to include. */
+ ImmutableSet<ModuleKind> legalIncludedModuleKinds() {
+ switch (this) {
+ case MODULE:
+ return Sets.immutableEnumSet(MODULE);
+ case PRODUCER_MODULE:
+ return Sets.immutableEnumSet(MODULE, PRODUCER_MODULE);
+ }
+ throw new AssertionError(this);
+ }
+}
diff --git a/java/dagger/internal/codegen/ModuleProcessingStep.java b/java/dagger/internal/codegen/ModuleProcessingStep.java
index 2bf3354..27cd531 100644
--- a/java/dagger/internal/codegen/ModuleProcessingStep.java
+++ b/java/dagger/internal/codegen/ModuleProcessingStep.java
@@ -28,19 +28,7 @@
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.BindingFactory;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.DelegateDeclaration;
-import dagger.internal.codegen.binding.DelegateDeclaration.Factory;
-import dagger.internal.codegen.binding.ProductionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.validation.ModuleValidator;
-import dagger.internal.codegen.validation.TypeCheckingProcessingStep;
-import dagger.internal.codegen.validation.ValidationReport;
-import dagger.internal.codegen.writing.InaccessibleMapKeyProxyGenerator;
-import dagger.internal.codegen.writing.ModuleGenerator;
+import dagger.internal.codegen.DelegateDeclaration.Factory;
import dagger.producers.ProducerModule;
import dagger.producers.Produces;
import java.lang.annotation.Annotation;
@@ -65,7 +53,6 @@
private final SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator;
private final InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator;
private final DelegateDeclaration.Factory delegateDeclarationFactory;
- private final KotlinMetadataUtil metadataUtil;
private final Set<TypeElement> processedModuleElements = Sets.newLinkedHashSet();
@Inject
@@ -77,8 +64,7 @@
SourceFileGenerator<ProductionBinding> producerFactoryGenerator,
@ModuleGenerator SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator,
InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator,
- Factory delegateDeclarationFactory,
- KotlinMetadataUtil metadataUtil) {
+ Factory delegateDeclarationFactory) {
super(MoreElements::asType);
this.messager = messager;
this.moduleValidator = moduleValidator;
@@ -88,7 +74,6 @@
this.moduleConstructorProxyGenerator = moduleConstructorProxyGenerator;
this.inaccessibleMapKeyProxyGenerator = inaccessibleMapKeyProxyGenerator;
this.delegateDeclarationFactory = delegateDeclarationFactory;
- this.metadataUtil = metadataUtil;
}
@Override
@@ -110,38 +95,23 @@
if (processedModuleElements.contains(module)) {
return;
}
- // For backwards compatibility, we allow a companion object to be annotated with @Module even
- // though it's no longer required. However, we skip processing the companion object itself
- // because it will now be processed when processing the companion object's enclosing class.
- if (metadataUtil.isCompanionObjectClass(module)) {
- // TODO(danysantiago): Be strict about annotating companion objects with @Module,
- // i.e. tell user to annotate parent instead.
- return;
- }
ValidationReport<TypeElement> report = moduleValidator.validate(module);
report.printMessagesTo(messager);
if (report.isClean()) {
- generateForMethodsIn(module);
- if (metadataUtil.hasEnclosedCompanionObject(module)) {
- generateForMethodsIn(metadataUtil.getEnclosedCompanionObject(module));
+ for (ExecutableElement method : methodsIn(module.getEnclosedElements())) {
+ if (isAnnotationPresent(method, Provides.class)) {
+ generate(factoryGenerator, bindingFactory.providesMethodBinding(method, module));
+ } else if (isAnnotationPresent(method, Produces.class)) {
+ generate(producerFactoryGenerator, bindingFactory.producesMethodBinding(method, module));
+ } else if (isAnnotationPresent(method, Binds.class)) {
+ inaccessibleMapKeyProxyGenerator.generate(bindsMethodBinding(module, method), messager);
+ }
}
+ moduleConstructorProxyGenerator.generate(module, messager);
}
processedModuleElements.add(module);
}
- private void generateForMethodsIn(TypeElement module) {
- for (ExecutableElement method : methodsIn(module.getEnclosedElements())) {
- if (isAnnotationPresent(method, Provides.class)) {
- generate(factoryGenerator, bindingFactory.providesMethodBinding(method, module));
- } else if (isAnnotationPresent(method, Produces.class)) {
- generate(producerFactoryGenerator, bindingFactory.producesMethodBinding(method, module));
- } else if (isAnnotationPresent(method, Binds.class)) {
- inaccessibleMapKeyProxyGenerator.generate(bindsMethodBinding(module, method), messager);
- }
- }
- moduleConstructorProxyGenerator.generate(module, messager);
- }
-
private <B extends ContributionBinding> void generate(
SourceFileGenerator<B> generator, B binding) {
generator.generate(binding, messager);
diff --git a/java/dagger/internal/codegen/ModuleProxies.java b/java/dagger/internal/codegen/ModuleProxies.java
new file mode 100644
index 0000000..6426e69
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleProxies.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
+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 static javax.lang.model.util.ElementFilter.constructorsIn;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.langmodel.Accessibility;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.Optional;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/** Convenience methods for generating and using module constructor proxy methods. */
+final class ModuleProxies {
+ /** The name of the class that hosts the module constructor proxy method. */
+ static ClassName constructorProxyTypeName(TypeElement moduleElement) {
+ ModuleKind.checkIsModule(moduleElement);
+ ClassName moduleClassName = ClassName.get(moduleElement);
+ return moduleClassName
+ .topLevelClassName()
+ .peerClass(SourceFiles.classFileName(moduleClassName) + "_Proxy");
+ }
+
+ /**
+ * The module constructor being proxied. A proxy is generated if it is not publicly accessible and
+ * has no arguments. If an implicit reference to the enclosing class exists, or the module is
+ * abstract, no proxy method can be generated.
+ */
+ // TODO(ronshapiro): make this an @Injectable class that injects DaggerElements
+ static Optional<ExecutableElement> nonPublicNullaryConstructor(
+ TypeElement moduleElement, DaggerElements elements) {
+ ModuleKind.checkIsModule(moduleElement);
+ if (moduleElement.getModifiers().contains(ABSTRACT)
+ || (moduleElement.getNestingKind().isNested()
+ && !moduleElement.getModifiers().contains(STATIC))) {
+ return Optional.empty();
+ }
+ return constructorsIn(elements.getAllMembers(moduleElement)).stream()
+ .filter(constructor -> !Accessibility.isElementPubliclyAccessible(constructor))
+ .filter(constructor -> !constructor.getModifiers().contains(PRIVATE))
+ .filter(constructor -> constructor.getParameters().isEmpty())
+ .findAny();
+ }
+
+ /**
+ * Returns a code block that creates a new module instance, either by invoking the nullary
+ * constructor if it's accessible from {@code requestingClass} or else by invoking the
+ * constructor's generated proxy method.
+ */
+ static CodeBlock newModuleInstance(
+ TypeElement moduleElement, ClassName requestingClass, DaggerElements elements) {
+ ModuleKind.checkIsModule(moduleElement);
+ String packageName = requestingClass.packageName();
+ return nonPublicNullaryConstructor(moduleElement, elements)
+ .filter(constructor -> !isElementAccessibleFrom(constructor, packageName))
+ .map(
+ constructor ->
+ CodeBlock.of("$T.newInstance()", constructorProxyTypeName(moduleElement)))
+ .orElse(CodeBlock.of("new $T()", moduleElement));
+ }
+}
diff --git a/java/dagger/internal/codegen/ModuleValidator.java b/java/dagger/internal/codegen/ModuleValidator.java
new file mode 100644
index 0000000..094bf34
--- /dev/null
+++ b/java/dagger/internal/codegen/ModuleValidator.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2014 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.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
+import static com.google.auto.common.Visibility.PRIVATE;
+import static com.google.auto.common.Visibility.PUBLIC;
+import static com.google.auto.common.Visibility.effectiveVisibilityOfElement;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.ComponentAnnotation.componentAnnotation;
+import static dagger.internal.codegen.ComponentAnnotation.isComponentAnnotation;
+import static dagger.internal.codegen.ComponentAnnotation.subcomponentAnnotation;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.getCreatorAnnotations;
+import static dagger.internal.codegen.ConfigurationAnnotations.getSubcomponentCreator;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.ModuleAnnotation.isModuleAnnotation;
+import static dagger.internal.codegen.ModuleAnnotation.moduleAnnotation;
+import static dagger.internal.codegen.MoreAnnotationMirrors.simpleName;
+import static dagger.internal.codegen.MoreAnnotationValues.asType;
+import static dagger.internal.codegen.Util.reentrantComputeIfAbsent;
+import static dagger.internal.codegen.ValidationType.NONE;
+import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
+import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
+import static java.util.EnumSet.noneOf;
+import static java.util.stream.Collectors.joining;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.common.Visibility;
+import com.google.common.base.Joiner;
+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.google.common.collect.Sets;
+import com.google.errorprone.annotations.FormatMethod;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.BindingGraph;
+import dagger.producers.ProducerModule;
+import dagger.producers.ProductionSubcomponent;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Scope;
+import javax.inject.Singleton;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * A {@linkplain ValidationReport validator} for {@link Module}s or {@link ProducerModule}s.
+ */
+@Singleton
+final class ModuleValidator {
+ private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_TYPES =
+ ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
+ private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_CREATOR_TYPES =
+ ImmutableSet.of(
+ Subcomponent.Builder.class,
+ Subcomponent.Factory.class,
+ ProductionSubcomponent.Builder.class,
+ ProductionSubcomponent.Factory.class);
+ private static final Optional<Class<?>> ANDROID_PROCESSOR;
+ private static final String CONTRIBUTES_ANDROID_INJECTOR_NAME =
+ "dagger.android.ContributesAndroidInjector";
+ private static final String ANDROID_PROCESSOR_NAME = "dagger.android.processor.AndroidProcessor";
+
+ static {
+ Class<?> clazz;
+ try {
+ clazz = Class.forName(ANDROID_PROCESSOR_NAME, false, ModuleValidator.class.getClassLoader());
+ } catch (ClassNotFoundException ignored) {
+ clazz = null;
+ }
+ ANDROID_PROCESSOR = Optional.ofNullable(clazz);
+ }
+
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final AnyBindingMethodValidator anyBindingMethodValidator;
+ private final MethodSignatureFormatter methodSignatureFormatter;
+ private final ComponentDescriptorFactory componentDescriptorFactory;
+ private final BindingGraphFactory bindingGraphFactory;
+ private final BindingGraphConverter bindingGraphConverter;
+ private final BindingGraphValidator bindingGraphValidator;
+ private final CompilerOptions compilerOptions;
+ private final Map<TypeElement, ValidationReport<TypeElement>> cache = new HashMap<>();
+ private final Set<TypeElement> knownModules = new HashSet<>();
+
+ @Inject
+ ModuleValidator(
+ DaggerTypes types,
+ DaggerElements elements,
+ AnyBindingMethodValidator anyBindingMethodValidator,
+ MethodSignatureFormatter methodSignatureFormatter,
+ ComponentDescriptorFactory componentDescriptorFactory,
+ BindingGraphFactory bindingGraphFactory,
+ BindingGraphConverter bindingGraphConverter,
+ BindingGraphValidator bindingGraphValidator,
+ CompilerOptions compilerOptions) {
+ this.types = types;
+ this.elements = elements;
+ this.anyBindingMethodValidator = anyBindingMethodValidator;
+ this.methodSignatureFormatter = methodSignatureFormatter;
+ this.componentDescriptorFactory = componentDescriptorFactory;
+ this.bindingGraphFactory = bindingGraphFactory;
+ this.bindingGraphConverter = bindingGraphConverter;
+ this.bindingGraphValidator = bindingGraphValidator;
+ this.compilerOptions = compilerOptions;
+ }
+
+ /**
+ * Adds {@code modules} to the set of module types that will be validated during this compilation
+ * step. If a component or module includes a module that is not in this set, that included module
+ * is assumed to be valid because it was processed in a previous compilation step. If it were
+ * invalid, that previous compilation step would have failed and blocked this one.
+ *
+ * <p>This logic depends on this method being called before {@linkplain #validate(TypeElement)
+ * validating} any module or {@linkplain #validateReferencedModules(TypeElement, AnnotationMirror,
+ * ImmutableSet, Set) component}.
+ */
+ void addKnownModules(Collection<TypeElement> modules) {
+ knownModules.addAll(modules);
+ }
+
+ /** Returns a validation report for a module type. */
+ ValidationReport<TypeElement> validate(TypeElement module) {
+ return validate(module, new HashSet<>());
+ }
+
+ private ValidationReport<TypeElement> validate(
+ TypeElement module, Set<TypeElement> visitedModules) {
+ if (visitedModules.add(module)) {
+ return reentrantComputeIfAbsent(cache, module, m -> validateUncached(module, visitedModules));
+ }
+ return ValidationReport.about(module).build();
+ }
+
+ private ValidationReport<TypeElement> validateUncached(
+ TypeElement module, Set<TypeElement> visitedModules) {
+ ValidationReport.Builder<TypeElement> builder = ValidationReport.about(module);
+ ModuleKind moduleKind = ModuleKind.forAnnotatedElement(module).get();
+
+ ListMultimap<String, ExecutableElement> allMethodsByName = ArrayListMultimap.create();
+ ListMultimap<String, ExecutableElement> bindingMethodsByName = ArrayListMultimap.create();
+
+ Set<ModuleMethodKind> methodKinds = noneOf(ModuleMethodKind.class);
+ TypeElement contributesAndroidInjectorElement =
+ elements.getTypeElement(CONTRIBUTES_ANDROID_INJECTOR_NAME);
+ TypeMirror contributesAndroidInjector =
+ contributesAndroidInjectorElement != null
+ ? contributesAndroidInjectorElement.asType()
+ : null;
+ for (ExecutableElement moduleMethod : methodsIn(module.getEnclosedElements())) {
+ if (anyBindingMethodValidator.isBindingMethod(moduleMethod)) {
+ builder.addSubreport(anyBindingMethodValidator.validate(moduleMethod));
+ bindingMethodsByName.put(moduleMethod.getSimpleName().toString(), moduleMethod);
+ methodKinds.add(ModuleMethodKind.ofMethod(moduleMethod));
+ }
+ allMethodsByName.put(moduleMethod.getSimpleName().toString(), moduleMethod);
+
+ for (AnnotationMirror annotation : moduleMethod.getAnnotationMirrors()) {
+ if (!ANDROID_PROCESSOR.isPresent()
+ && MoreTypes.equivalence()
+ .equivalent(contributesAndroidInjector, annotation.getAnnotationType())) {
+ builder.addSubreport(
+ ValidationReport.about(moduleMethod)
+ .addError(
+ String.format(
+ "@%s was used, but %s was not found on the processor path",
+ CONTRIBUTES_ANDROID_INJECTOR_NAME, ANDROID_PROCESSOR_NAME))
+ .build());
+ break;
+ }
+ }
+ }
+
+ if (methodKinds.containsAll(
+ EnumSet.of(ModuleMethodKind.ABSTRACT_DECLARATION, ModuleMethodKind.INSTANCE_BINDING))) {
+ builder.addError(
+ String.format(
+ "A @%s may not contain both non-static and abstract binding methods",
+ moduleKind.annotation().getSimpleName()));
+ }
+
+ validateModuleVisibility(module, moduleKind, builder);
+ validateMethodsWithSameName(builder, bindingMethodsByName);
+ if (module.getKind() != ElementKind.INTERFACE) {
+ validateBindingMethodOverrides(module, builder, allMethodsByName, bindingMethodsByName);
+ }
+ validateModifiers(module, builder);
+ validateReferencedModules(module, moduleKind, visitedModules, builder);
+ validateReferencedSubcomponents(module, moduleKind, builder);
+ validateNoScopeAnnotationsOnModuleElement(module, moduleKind, builder);
+ validateSelfCycles(module, builder);
+
+ if (builder.build().isClean()
+ && !compilerOptions.fullBindingGraphValidationType(module).equals(NONE)) {
+ validateModuleBindings(module, builder);
+ }
+
+ return builder.build();
+ }
+
+ private void validateReferencedSubcomponents(
+ final TypeElement subject,
+ ModuleKind moduleKind,
+ final ValidationReport.Builder<TypeElement> builder) {
+ // TODO(ronshapiro): use validateTypesAreDeclared when it is checked in
+ ModuleAnnotation moduleAnnotation = moduleAnnotation(moduleKind.getModuleAnnotation(subject));
+ for (AnnotationValue subcomponentAttribute :
+ moduleAnnotation.subcomponentsAsAnnotationValues()) {
+ asType(subcomponentAttribute)
+ .accept(
+ new SimpleTypeVisitor8<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror e, Void aVoid) {
+ builder.addError(
+ e + " is not a valid subcomponent type",
+ subject,
+ moduleAnnotation.annotation(),
+ subcomponentAttribute);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType declaredType, Void aVoid) {
+ TypeElement attributeType = MoreTypes.asTypeElement(declaredType);
+ if (isAnyAnnotationPresent(attributeType, SUBCOMPONENT_TYPES)) {
+ validateSubcomponentHasBuilder(
+ attributeType, moduleAnnotation.annotation(), builder);
+ } else {
+ builder.addError(
+ isAnyAnnotationPresent(attributeType, SUBCOMPONENT_CREATOR_TYPES)
+ ? moduleSubcomponentsIncludesCreator(attributeType)
+ : moduleSubcomponentsIncludesNonSubcomponent(attributeType),
+ subject,
+ moduleAnnotation.annotation(),
+ subcomponentAttribute);
+ }
+
+ return null;
+ }
+ },
+ null);
+ }
+ }
+
+ private static String moduleSubcomponentsIncludesNonSubcomponent(TypeElement notSubcomponent) {
+ return notSubcomponent.getQualifiedName()
+ + " is not a @Subcomponent or @ProductionSubcomponent";
+ }
+
+ private static String moduleSubcomponentsIncludesCreator(
+ TypeElement moduleSubcomponentsAttribute) {
+ TypeElement subcomponentType =
+ MoreElements.asType(moduleSubcomponentsAttribute.getEnclosingElement());
+ ComponentCreatorAnnotation creatorAnnotation =
+ getOnlyElement(getCreatorAnnotations(moduleSubcomponentsAttribute));
+ return String.format(
+ "%s is a @%s.%s. Did you mean to use %s?",
+ moduleSubcomponentsAttribute.getQualifiedName(),
+ subcomponentAnnotation(subcomponentType).get().simpleName(),
+ creatorAnnotation.creatorKind().typeName(),
+ subcomponentType.getQualifiedName());
+ }
+
+ private static void validateSubcomponentHasBuilder(
+ TypeElement subcomponentAttribute,
+ AnnotationMirror moduleAnnotation,
+ ValidationReport.Builder<TypeElement> builder) {
+ if (getSubcomponentCreator(subcomponentAttribute).isPresent()) {
+ return;
+ }
+ builder.addError(
+ moduleSubcomponentsDoesntHaveCreator(subcomponentAttribute, moduleAnnotation),
+ builder.getSubject(),
+ moduleAnnotation);
+ }
+
+ private static String moduleSubcomponentsDoesntHaveCreator(
+ TypeElement subcomponent, AnnotationMirror moduleAnnotation) {
+ return String.format(
+ "%1$s doesn't have a @%2$s.Builder or @%2$s.Factory, which is required when used with "
+ + "@%3$s.subcomponents",
+ subcomponent.getQualifiedName(),
+ subcomponentAnnotation(subcomponent).get().simpleName(),
+ simpleName(moduleAnnotation));
+ }
+
+ enum ModuleMethodKind {
+ ABSTRACT_DECLARATION,
+ INSTANCE_BINDING,
+ STATIC_BINDING,
+ ;
+
+ static ModuleMethodKind ofMethod(ExecutableElement moduleMethod) {
+ if (moduleMethod.getModifiers().contains(STATIC)) {
+ return STATIC_BINDING;
+ } else if (moduleMethod.getModifiers().contains(ABSTRACT)) {
+ return ABSTRACT_DECLARATION;
+ } else {
+ return INSTANCE_BINDING;
+ }
+ }
+ }
+
+ private void validateModifiers(
+ TypeElement subject, ValidationReport.Builder<TypeElement> builder) {
+ // This coupled with the check for abstract modules in ComponentValidator guarantees that
+ // only modules without type parameters are referenced from @Component(modules={...}).
+ if (!subject.getTypeParameters().isEmpty() && !subject.getModifiers().contains(ABSTRACT)) {
+ builder.addError("Modules with type parameters must be abstract", subject);
+ }
+ }
+
+ private void validateMethodsWithSameName(
+ ValidationReport.Builder<TypeElement> builder,
+ ListMultimap<String, ExecutableElement> bindingMethodsByName) {
+ for (Entry<String, Collection<ExecutableElement>> entry :
+ bindingMethodsByName.asMap().entrySet()) {
+ if (entry.getValue().size() > 1) {
+ for (ExecutableElement offendingMethod : entry.getValue()) {
+ builder.addError(
+ String.format(
+ "Cannot have more than one binding method with the same name in a single module"),
+ offendingMethod);
+ }
+ }
+ }
+ }
+
+ private void validateReferencedModules(
+ TypeElement subject,
+ ModuleKind moduleKind,
+ Set<TypeElement> visitedModules,
+ ValidationReport.Builder<TypeElement> builder) {
+ // Validate that all the modules we include are valid for inclusion.
+ AnnotationMirror mirror = moduleKind.getModuleAnnotation(subject);
+ builder.addSubreport(
+ validateReferencedModules(
+ subject, mirror, moduleKind.legalIncludedModuleKinds(), visitedModules));
+ }
+
+ /**
+ * Validates modules included in a given module or installed in a given component.
+ *
+ * <p>Checks that the referenced modules are non-generic types annotated with {@code @Module} or
+ * {@code @ProducerModule}.
+ *
+ * <p>If the referenced module is in the {@linkplain #addKnownModules(Collection) known modules
+ * set} and has errors, reports an error at that module's inclusion.
+ *
+ * @param annotatedType the annotated module or component
+ * @param annotation the annotation specifying the referenced modules ({@code @Component},
+ * {@code @ProductionComponent}, {@code @Subcomponent}, {@code @ProductionSubcomponent},
+ * {@code @Module}, or {@code @ProducerModule})
+ * @param validModuleKinds the module kinds that the annotated type is permitted to include
+ */
+ ValidationReport<TypeElement> validateReferencedModules(
+ TypeElement annotatedType,
+ AnnotationMirror annotation,
+ ImmutableSet<ModuleKind> validModuleKinds,
+ Set<TypeElement> visitedModules) {
+ ValidationReport.Builder<TypeElement> subreport = ValidationReport.about(annotatedType);
+ ImmutableSet<? extends Class<? extends Annotation>> validModuleAnnotations =
+ validModuleKinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
+
+ for (AnnotationValue includedModule : getModules(annotation)) {
+ asType(includedModule)
+ .accept(
+ new SimpleTypeVisitor8<Void, Void>() {
+ @Override
+ protected Void defaultAction(TypeMirror mirror, Void p) {
+ reportError("%s is not a valid module type.", mirror);
+ return null;
+ }
+
+ @Override
+ public Void visitDeclared(DeclaredType t, Void p) {
+ TypeElement module = MoreElements.asType(t.asElement());
+ if (!t.getTypeArguments().isEmpty()) {
+ reportError(
+ "%s is listed as a module, but has type parameters",
+ module.getQualifiedName());
+ }
+ if (!isAnyAnnotationPresent(module, validModuleAnnotations)) {
+ reportError(
+ "%s is listed as a module, but is not annotated with %s",
+ module.getQualifiedName(),
+ (validModuleAnnotations.size() > 1 ? "one of " : "")
+ + validModuleAnnotations
+ .stream()
+ .map(otherClass -> "@" + otherClass.getSimpleName())
+ .collect(joining(", ")));
+ } else if (knownModules.contains(module)
+ && !validate(module, visitedModules).isClean()) {
+ reportError("%s has errors", module.getQualifiedName());
+ }
+ return null;
+ }
+
+ @FormatMethod
+ private void reportError(String format, Object... args) {
+ subreport.addError(
+ String.format(format, args), annotatedType, annotation, includedModule);
+ }
+ },
+ null);
+ }
+ return subreport.build();
+ }
+
+ private static ImmutableList<AnnotationValue> getModules(AnnotationMirror annotation) {
+ if (isModuleAnnotation(annotation)) {
+ return moduleAnnotation(annotation).includesAsAnnotationValues();
+ }
+ if (isComponentAnnotation(annotation)) {
+ return componentAnnotation(annotation).moduleValues();
+ }
+ throw new IllegalArgumentException(String.format("unsupported annotation: %s", annotation));
+ }
+
+ private void validateBindingMethodOverrides(
+ TypeElement subject,
+ ValidationReport.Builder<TypeElement> builder,
+ ListMultimap<String, ExecutableElement> allMethodsByName,
+ ListMultimap<String, ExecutableElement> bindingMethodsByName) {
+ // For every binding method, confirm it overrides nothing *and* nothing overrides it.
+ // Consider the following hierarchy:
+ // class Parent {
+ // @Provides Foo a() {}
+ // @Provides Foo b() {}
+ // Foo c() {}
+ // }
+ // class Child extends Parent {
+ // @Provides Foo a() {}
+ // Foo b() {}
+ // @Provides Foo c() {}
+ // }
+ // In each of those cases, we want to fail. "a" is clear, "b" because Child is overriding
+ // a binding method in Parent, and "c" because Child is defining a binding method that overrides
+ // Parent.
+ TypeElement currentClass = subject;
+ TypeMirror objectType = elements.getTypeElement(Object.class).asType();
+ // We keep track of methods that failed so we don't spam with multiple failures.
+ Set<ExecutableElement> failedMethods = Sets.newHashSet();
+ while (!types.isSameType(currentClass.getSuperclass(), objectType)) {
+ currentClass = MoreElements.asType(types.asElement(currentClass.getSuperclass()));
+ List<ExecutableElement> superclassMethods = methodsIn(currentClass.getEnclosedElements());
+ for (ExecutableElement superclassMethod : superclassMethods) {
+ String name = superclassMethod.getSimpleName().toString();
+ // For each method in the superclass, confirm our binding methods don't override it
+ for (ExecutableElement bindingMethod : bindingMethodsByName.get(name)) {
+ if (failedMethods.add(bindingMethod)
+ && elements.overrides(bindingMethod, superclassMethod, subject)) {
+ builder.addError(
+ String.format(
+ "Binding methods may not override another method. Overrides: %s",
+ methodSignatureFormatter.format(superclassMethod)),
+ bindingMethod);
+ }
+ }
+ // For each binding method in superclass, confirm our methods don't override it.
+ if (anyBindingMethodValidator.isBindingMethod(superclassMethod)) {
+ for (ExecutableElement method : allMethodsByName.get(name)) {
+ if (failedMethods.add(method)
+ && elements.overrides(method, superclassMethod, subject)) {
+ builder.addError(
+ String.format(
+ "Binding methods may not be overridden in modules. Overrides: %s",
+ methodSignatureFormatter.format(superclassMethod)),
+ method);
+ }
+ }
+ }
+ allMethodsByName.put(superclassMethod.getSimpleName().toString(), superclassMethod);
+ }
+ }
+ }
+
+ private void validateModuleVisibility(
+ final TypeElement moduleElement,
+ ModuleKind moduleKind,
+ final ValidationReport.Builder<?> reportBuilder) {
+ ModuleAnnotation moduleAnnotation =
+ moduleAnnotation(getAnnotationMirror(moduleElement, moduleKind.annotation()).get());
+ Visibility moduleVisibility = Visibility.ofElement(moduleElement);
+ Visibility moduleEffectiveVisibility = effectiveVisibilityOfElement(moduleElement);
+ if (moduleVisibility.equals(PRIVATE)) {
+ reportBuilder.addError("Modules cannot be private.", moduleElement);
+ } else if (moduleEffectiveVisibility.equals(PRIVATE)) {
+ reportBuilder.addError("Modules cannot be enclosed in private types.", moduleElement);
+ }
+
+ switch (moduleElement.getNestingKind()) {
+ case ANONYMOUS:
+ throw new IllegalStateException("Can't apply @Module to an anonymous class");
+ case LOCAL:
+ throw new IllegalStateException("Local classes shouldn't show up in the processor");
+ case MEMBER:
+ case TOP_LEVEL:
+ if (moduleEffectiveVisibility.equals(PUBLIC)) {
+ ImmutableSet<TypeElement> invalidVisibilityIncludes =
+ getModuleIncludesWithInvalidVisibility(moduleAnnotation);
+ if (!invalidVisibilityIncludes.isEmpty()) {
+ reportBuilder.addError(
+ String.format(
+ "This module is public, but it includes non-public (or effectively non-public) "
+ + "modules (%s) that have non-static, non-abstract binding methods. Either "
+ + "reduce the visibility of this module, make the included modules "
+ + "public, or make all of the binding methods on the included modules "
+ + "abstract or static.",
+ formatListForErrorMessage(invalidVisibilityIncludes.asList())),
+ moduleElement);
+ }
+ }
+ }
+ }
+
+ private ImmutableSet<TypeElement> getModuleIncludesWithInvalidVisibility(
+ ModuleAnnotation moduleAnnotation) {
+ return moduleAnnotation.includes().stream()
+ .filter(include -> !effectiveVisibilityOfElement(include).equals(PUBLIC))
+ .filter(this::requiresModuleInstance)
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns {@code true} if a module instance is needed for any of the binding methods on the
+ * given {@code module}. This is the case when the module has any binding methods that are neither
+ * {@code abstract} nor {@code static}.
+ */
+ private boolean requiresModuleInstance(TypeElement module) {
+ // Note elements.getAllMembers(module) rather than module.getEnclosedElements() here: we need to
+ // include binding methods declared in supertypes because unlike most other validations being
+ // done in this class, which assume that supertype binding methods will be validated in a
+ // separate call to the validator since the supertype itself must be a @Module, we need to look
+ // at all the binding methods in the module's type hierarchy here.
+ return methodsIn(elements.getAllMembers(module)).stream()
+ .filter(method -> anyBindingMethodValidator.isBindingMethod(method))
+ .map(ExecutableElement::getModifiers)
+ .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC));
+ }
+
+ private void validateNoScopeAnnotationsOnModuleElement(
+ TypeElement module, ModuleKind moduleKind, ValidationReport.Builder<TypeElement> report) {
+ for (AnnotationMirror scope : getAnnotatedAnnotations(module, Scope.class)) {
+ report.addError(
+ String.format(
+ "@%ss cannot be scoped. Did you mean to scope a method instead?",
+ moduleKind.annotation().getSimpleName()),
+ module,
+ scope);
+ }
+ }
+
+ private void validateSelfCycles(
+ TypeElement module, ValidationReport.Builder<TypeElement> builder) {
+ ModuleAnnotation moduleAnnotation = moduleAnnotation(module).get();
+ moduleAnnotation
+ .includesAsAnnotationValues()
+ .forEach(
+ value ->
+ value.accept(
+ new SimpleAnnotationValueVisitor8<Void, Void>() {
+ @Override
+ public Void visitType(TypeMirror includedModule, Void aVoid) {
+ if (MoreTypes.equivalence().equivalent(module.asType(), includedModule)) {
+ String moduleKind = moduleAnnotation.annotationClass().getSimpleName();
+ builder.addError(
+ String.format("@%s cannot include themselves.", moduleKind),
+ module,
+ moduleAnnotation.annotation(),
+ value);
+ }
+ return null;
+ }
+ },
+ null));
+ }
+
+ private void validateModuleBindings(
+ TypeElement module, ValidationReport.Builder<TypeElement> report) {
+ BindingGraph bindingGraph =
+ bindingGraphConverter.convert(
+ bindingGraphFactory.create(
+ componentDescriptorFactory.moduleComponentDescriptor(module), true));
+ if (!bindingGraphValidator.isValid(bindingGraph)) {
+ // Since the validator uses a DiagnosticReporter to report errors, the ValdiationReport won't
+ // have any Items for them. We have to tell the ValidationReport that some errors were
+ // reported for the subject.
+ report.markDirty();
+ }
+ }
+
+ private static String formatListForErrorMessage(List<?> things) {
+ switch (things.size()) {
+ case 0:
+ return "";
+ case 1:
+ return things.get(0).toString();
+ default:
+ StringBuilder output = new StringBuilder();
+ Joiner.on(", ").appendTo(output, things.subList(0, things.size() - 1));
+ output.append(" and ").append(things.get(things.size() - 1));
+ return output.toString();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/MonitoringModuleGenerator.java b/java/dagger/internal/codegen/MonitoringModuleGenerator.java
new file mode 100644
index 0000000..1738fe9
--- /dev/null
+++ b/java/dagger/internal/codegen/MonitoringModuleGenerator.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCTION_COMPONENT_MONITOR_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static dagger.internal.codegen.javapoet.TypeNames.setOf;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.multibindings.Multibinds;
+import dagger.producers.ProductionScope;
+import dagger.producers.monitoring.ProductionComponentMonitor;
+import dagger.producers.monitoring.internal.Monitors;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/** Generates a monitoring module for use with production components. */
+final class MonitoringModuleGenerator extends SourceFileGenerator<TypeElement> {
+
+ @Inject
+ MonitoringModuleGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ }
+
+ @Override
+ ClassName nameGeneratedType(TypeElement componentElement) {
+ return SourceFiles.generatedMonitoringModuleName(componentElement);
+ }
+
+ @Override
+ Element originatingElement(TypeElement componentElement) {
+ return componentElement;
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, TypeElement componentElement) {
+ return Optional.of(
+ classBuilder(generatedTypeName)
+ .addAnnotation(Module.class)
+ .addModifiers(ABSTRACT)
+ .addMethod(privateConstructor())
+ .addMethod(setOfFactories())
+ .addMethod(monitor(componentElement)));
+ }
+
+ private MethodSpec privateConstructor() {
+ return constructorBuilder().addModifiers(PRIVATE).build();
+ }
+
+ private MethodSpec setOfFactories() {
+ return methodBuilder("setOfFactories")
+ .addAnnotation(Multibinds.class)
+ .addModifiers(ABSTRACT)
+ .returns(setOf(PRODUCTION_COMPONENT_MONITOR_FACTORY))
+ .build();
+ }
+
+ private MethodSpec monitor(TypeElement componentElement) {
+ return methodBuilder("monitor")
+ .returns(ProductionComponentMonitor.class)
+ .addModifiers(STATIC)
+ .addAnnotation(Provides.class)
+ .addAnnotation(ProductionScope.class)
+ .addParameter(providerOf(ClassName.get(componentElement.asType())), "component")
+ .addParameter(
+ providerOf(setOf(PRODUCTION_COMPONENT_MONITOR_FACTORY)), "factories")
+ .addStatement(
+ "return $T.createMonitorForComponent(component, factories)", Monitors.class)
+ .build();
+ }
+}
diff --git a/java/dagger/internal/codegen/MonitoringModuleProcessingStep.java b/java/dagger/internal/codegen/MonitoringModuleProcessingStep.java
new file mode 100644
index 0000000..55ae579
--- /dev/null
+++ b/java/dagger/internal/codegen/MonitoringModuleProcessingStep.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import dagger.producers.ProductionComponent;
+import dagger.producers.ProductionSubcomponent;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A processing step that is responsible for generating a special module for a {@link
+ * ProductionComponent} or {@link ProductionSubcomponent}.
+ */
+final class MonitoringModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
+ private final Messager messager;
+ private final MonitoringModuleGenerator monitoringModuleGenerator;
+
+ @Inject
+ MonitoringModuleProcessingStep(
+ Messager messager, MonitoringModuleGenerator monitoringModuleGenerator) {
+ super(MoreElements::asType);
+ this.messager = messager;
+ this.monitoringModuleGenerator = monitoringModuleGenerator;
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(ProductionComponent.class, ProductionSubcomponent.class);
+ }
+
+ @Override
+ protected void process(
+ TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
+ monitoringModuleGenerator.generate(MoreElements.asType(element), messager);
+ }
+}
diff --git a/java/dagger/internal/codegen/MoreAnnotationMirrors.java b/java/dagger/internal/codegen/MoreAnnotationMirrors.java
new file mode 100644
index 0000000..92825a0
--- /dev/null
+++ b/java/dagger/internal/codegen/MoreAnnotationMirrors.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 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.auto.common.AnnotationMirrors.getAnnotationValue;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.MoreAnnotationValues.asAnnotationValues;
+
+import com.google.auto.common.AnnotationMirrors;
+import com.google.common.base.Equivalence;
+import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Name;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A utility class for working with {@link AnnotationMirror} instances, similar to {@link
+ * AnnotationMirrors}.
+ */
+final class MoreAnnotationMirrors {
+
+ private MoreAnnotationMirrors() {}
+
+ /**
+ * Wraps an {@link Optional} of a type in an {@code Optional} of a {@link Equivalence.Wrapper} for
+ * that type.
+ */
+ static Optional<Equivalence.Wrapper<AnnotationMirror>> wrapOptionalInEquivalence(
+ Optional<AnnotationMirror> optional) {
+ return optional.map(AnnotationMirrors.equivalence()::wrap);
+ }
+
+ /**
+ * Unwraps an {@link Optional} of a {@link Equivalence.Wrapper} into an {@code Optional} of the
+ * underlying type.
+ */
+ static Optional<AnnotationMirror> unwrapOptionalEquivalence(
+ Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedOptional) {
+ return wrappedOptional.map(Equivalence.Wrapper::get);
+ }
+
+ static Name simpleName(AnnotationMirror annotationMirror) {
+ return annotationMirror.getAnnotationType().asElement().getSimpleName();
+ }
+
+ /**
+ * Returns the list of types that is the value named {@code name} from {@code annotationMirror}.
+ *
+ * @throws IllegalArgumentException unless that member represents an array of types
+ */
+ static ImmutableList<TypeMirror> getTypeListValue(
+ AnnotationMirror annotationMirror, String name) {
+ return asAnnotationValues(getAnnotationValue(annotationMirror, name))
+ .stream()
+ .map(MoreAnnotationValues::asType)
+ .collect(toImmutableList());
+ }
+}
diff --git a/java/dagger/internal/codegen/MoreAnnotationValues.java b/java/dagger/internal/codegen/MoreAnnotationValues.java
new file mode 100644
index 0000000..84a4d94
--- /dev/null
+++ b/java/dagger/internal/codegen/MoreAnnotationValues.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 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 com.google.common.collect.ImmutableList;
+import java.util.List;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+
+/** Utility methods for working with {@link AnnotationValue} instances. */
+final class MoreAnnotationValues {
+ /**
+ * Returns the list of values represented by an array annotation value.
+ *
+ * @throws IllegalArgumentException unless {@code annotationValue} represents an array
+ */
+ static ImmutableList<AnnotationValue> asAnnotationValues(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);
+ }
+ };
+
+ /**
+ * Returns the type represented by an annotation value.
+ *
+ * @throws IllegalArgumentException unless {@code annotationValue} represents a single type
+ */
+ static TypeMirror asType(AnnotationValue annotationValue) {
+ return AS_TYPE.visit(annotationValue);
+ }
+
+ private static final AnnotationValueVisitor<TypeMirror, Void> AS_TYPE =
+ new SimpleAnnotationValueVisitor8<TypeMirror, Void>() {
+ @Override
+ public TypeMirror visitType(TypeMirror t, Void p) {
+ return t;
+ }
+
+ @Override
+ protected TypeMirror defaultAction(Object o, Void p) {
+ throw new TypeNotPresentException(o.toString(), null);
+ }
+ };
+
+ private MoreAnnotationValues() {}
+}
diff --git a/java/dagger/internal/codegen/MultibindingAnnotations.java b/java/dagger/internal/codegen/MultibindingAnnotations.java
new file mode 100644
index 0000000..b478704
--- /dev/null
+++ b/java/dagger/internal/codegen/MultibindingAnnotations.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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 dagger.internal.codegen.langmodel.DaggerElements.getAllAnnotations;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.IntoSet;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+
+/**
+ * Utility methods related to processing {@link IntoSet}, {@link ElementsIntoSet}, and {@link
+ * IntoMap}.
+ */
+final class MultibindingAnnotations {
+ static ImmutableSet<AnnotationMirror> forElement(Element method) {
+ return getAllAnnotations(method, IntoSet.class, ElementsIntoSet.class, IntoMap.class);
+ }
+}
diff --git a/java/dagger/internal/codegen/MultibindingAnnotationsProcessingStep.java b/java/dagger/internal/codegen/MultibindingAnnotationsProcessingStep.java
new file mode 100644
index 0000000..2bb0a7e
--- /dev/null
+++ b/java/dagger/internal/codegen/MultibindingAnnotationsProcessingStep.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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 dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.IntoSet;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+import javax.annotation.processing.Messager;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+
+/**
+ * Processing step that verifies that {@link IntoSet}, {@link ElementsIntoSet} and {@link IntoMap}
+ * are not present on non-binding methods.
+ */
+final class MultibindingAnnotationsProcessingStep
+ extends TypeCheckingProcessingStep<ExecutableElement> {
+ private final AnyBindingMethodValidator anyBindingMethodValidator;
+ private final Messager messager;
+
+ @Inject
+ MultibindingAnnotationsProcessingStep(
+ AnyBindingMethodValidator anyBindingMethodValidator, Messager messager) {
+ super(MoreElements::asExecutable);
+ this.anyBindingMethodValidator = anyBindingMethodValidator;
+ this.messager = messager;
+ }
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotations() {
+ return ImmutableSet.of(IntoSet.class, ElementsIntoSet.class, IntoMap.class);
+ }
+
+ @Override
+ protected void process(
+ ExecutableElement method, ImmutableSet<Class<? extends Annotation>> annotations) {
+ if (!anyBindingMethodValidator.isBindingMethod(method)) {
+ annotations.forEach(
+ annotation ->
+ messager.printMessage(
+ ERROR,
+ "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods",
+ method,
+ getAnnotationMirror(method, annotation).get()));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/MultibindingDeclaration.java b/java/dagger/internal/codegen/MultibindingDeclaration.java
new file mode 100644
index 0000000..c3724dc
--- /dev/null
+++ b/java/dagger/internal/codegen/MultibindingDeclaration.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import dagger.internal.codegen.ContributionType.HasContributionType;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import dagger.multibindings.Multibinds;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A declaration that a multibinding with a certain key is available to be injected in a component
+ * even if the component has no multibindings for that key. Identified by a map- or set-returning
+ * method annotated with {@link Multibinds @Multibinds}.
+ */
+@AutoValue
+abstract class MultibindingDeclaration extends BindingDeclaration implements HasContributionType {
+
+ /**
+ * The map or set key whose availability is declared. For maps, this will be {@code Map<K,
+ * Provider<V>>}. For sets, this will be {@code Set<T>}.
+ */
+ @Override
+ public abstract Key key();
+
+ /**
+ * {@link ContributionType#SET} if the declared type is a {@link Set}, or
+ * {@link ContributionType#MAP} if it is a {@link Map}.
+ */
+ @Override
+ public abstract ContributionType contributionType();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ /**
+ * A factory for {@link MultibindingDeclaration}s.
+ */
+ static final class Factory {
+ private final DaggerTypes types;
+ private final KeyFactory keyFactory;
+
+ @Inject
+ Factory(DaggerTypes types, KeyFactory keyFactory) {
+ this.types = types;
+ this.keyFactory = keyFactory;
+ }
+
+ /** A multibinding declaration for a {@link Multibinds @Multibinds} method. */
+ MultibindingDeclaration forMultibindsMethod(
+ ExecutableElement moduleMethod, TypeElement moduleElement) {
+ checkArgument(isAnnotationPresent(moduleMethod, Multibinds.class));
+ return forDeclaredMethod(
+ moduleMethod,
+ MoreTypes.asExecutable(
+ types.asMemberOf(MoreTypes.asDeclared(moduleElement.asType()), moduleMethod)),
+ moduleElement);
+ }
+
+ private MultibindingDeclaration forDeclaredMethod(
+ ExecutableElement method,
+ ExecutableType methodType,
+ TypeElement contributingType) {
+ TypeMirror returnType = methodType.getReturnType();
+ checkArgument(
+ SetType.isSet(returnType) || MapType.isMap(returnType),
+ "%s must return a set or map",
+ method);
+ return new AutoValue_MultibindingDeclaration(
+ Optional.<Element>of(method),
+ Optional.of(contributingType),
+ keyFactory.forMultibindsMethod(methodType, method),
+ contributionType(returnType));
+ }
+
+ private ContributionType contributionType(TypeMirror returnType) {
+ if (MapType.isMap(returnType)) {
+ return ContributionType.MAP;
+ } else if (SetType.isSet(returnType)) {
+ return ContributionType.SET;
+ } else {
+ throw new IllegalArgumentException("Must be Map or Set: " + returnType);
+ }
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/MultibindingExpression.java b/java/dagger/internal/codegen/MultibindingExpression.java
new file mode 100644
index 0000000..f0523eb
--- /dev/null
+++ b/java/dagger/internal/codegen/MultibindingExpression.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 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 com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import java.util.Optional;
+import java.util.Set;
+
+/** An abstract base class for multibinding {@link BindingExpression}s. */
+abstract class MultibindingExpression extends SimpleInvocationBindingExpression {
+ private final ProvisionBinding binding;
+ private final ComponentImplementation componentImplementation;
+
+ MultibindingExpression(
+ ResolvedBindings resolvedBindings, ComponentImplementation componentImplementation) {
+ super(resolvedBindings);
+ this.componentImplementation = componentImplementation;
+ this.binding = (ProvisionBinding) resolvedBindings.contributionBinding();
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ Expression expression = buildDependencyExpression(requestingClass);
+ componentImplementation.registerImplementedMultibinding(binding, bindingRequest());
+ return expression;
+ }
+
+ /**
+ * Returns an expression that evaluates to the value of a multibinding request for the given
+ * requesting class.
+ */
+ protected abstract Expression buildDependencyExpression(ClassName requestingClass);
+
+ /**
+ * Returns the subset of {@code dependencies} that represent multibinding contributions that were
+ * not included in a superclass implementation of this multibinding method. This is relevant only
+ * for ahead-of-time subcomponents. When not generating ahead-of-time subcomponents there is only
+ * one implementation of a multibinding expression and all {@link DependencyRequest}s from the
+ * argment are returned.
+ */
+ protected Set<DependencyRequest> getNewContributions(
+ ImmutableSet<DependencyRequest> dependencies) {
+ ImmutableSet<Key> superclassContributions = superclassContributions();
+ return Sets.filter(
+ dependencies, dependency -> !superclassContributions.contains(dependency.key()));
+ }
+
+ /**
+ * Returns the {@link CodeBlock} representing a call to a superclass implementation of the
+ * modifiable binding method that encapsulates this binding, if it exists. This is only possible
+ * when generating ahead-of-time subcomponents.
+ */
+ protected Optional<CodeBlock> superMethodCall() {
+ if (componentImplementation.superclassImplementation().isPresent()) {
+ Optional<ModifiableBindingMethod> method =
+ componentImplementation.getModifiableBindingMethod(bindingRequest());
+ if (method.isPresent()) {
+ if (!superclassContributions().isEmpty()) {
+ return Optional.of(CodeBlock.of("super.$L()", method.get().methodSpec().name));
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ private BindingRequest bindingRequest() {
+ return BindingRequest.bindingRequest(binding.key(), RequestKind.INSTANCE);
+ }
+
+ private ImmutableSet<Key> superclassContributions() {
+ return componentImplementation.superclassContributionsMade(bindingRequest());
+ }
+}
diff --git a/java/dagger/internal/codegen/MultibindingFactoryCreationExpression.java b/java/dagger/internal/codegen/MultibindingFactoryCreationExpression.java
new file mode 100644
index 0000000..abe161a
--- /dev/null
+++ b/java/dagger/internal/codegen/MultibindingFactoryCreationExpression.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import java.util.Optional;
+
+/** An abstract factory creation expression for multibindings. */
+abstract class MultibindingFactoryCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final ComponentImplementation componentImplementation;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ContributionBinding binding;
+
+ MultibindingFactoryCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ /** Returns the expression for a dependency of this multibinding. */
+ protected final CodeBlock multibindingDependencyExpression(DependencyRequest dependency) {
+ CodeBlock expression =
+ componentBindingExpressions
+ .getDependencyExpression(
+ BindingRequest.bindingRequest(dependency.key(), binding.frameworkType()),
+ componentImplementation.name())
+ .codeBlock();
+
+ return useRawType()
+ ? CodeBlocks.cast(expression, binding.frameworkType().frameworkClass())
+ : expression;
+ }
+
+ protected final ImmutableSet<DependencyRequest> dependenciesToImplement() {
+ ImmutableSet<Key> alreadyImplementedKeys =
+ componentImplementation.superclassContributionsMade(bindingRequest());
+ return binding.dependencies().stream()
+ .filter(dependency -> !alreadyImplementedKeys.contains(dependency.key()))
+ .collect(toImmutableSet());
+ }
+
+ protected Optional<CodeBlock> superContributions() {
+ if (dependenciesToImplement().size() == binding.dependencies().size()) {
+ return Optional.empty();
+ }
+ ModifiableBindingMethod superMethod =
+ componentImplementation.getModifiableBindingMethod(bindingRequest()).get();
+ return Optional.of(CodeBlock.of("super.$N()", superMethod.methodSpec().name));
+ }
+
+ /** The binding request for this framework instance. */
+ protected final BindingRequest bindingRequest() {
+ return BindingRequest.bindingRequest(binding.key(), binding.frameworkType());
+ }
+
+ /**
+ * Returns true if the {@linkplain ContributionBinding#key() key type} is inaccessible from the
+ * component, and therefore a raw type must be used.
+ */
+ protected final boolean useRawType() {
+ return !componentImplementation.isTypeAccessible(binding.key().type());
+ }
+
+ @Override
+ public final boolean useInnerSwitchingProvider() {
+ return !binding.dependencies().isEmpty();
+ }
+}
diff --git a/java/dagger/internal/codegen/MultibindsMethodValidator.java b/java/dagger/internal/codegen/MultibindsMethodValidator.java
new file mode 100644
index 0000000..bc97d30
--- /dev/null
+++ b/java/dagger/internal/codegen/MultibindsMethodValidator.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 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 dagger.internal.codegen.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS;
+import static dagger.internal.codegen.BindingElementValidator.AllowsScoping.NO_SCOPING;
+import static dagger.internal.codegen.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
+import static dagger.internal.codegen.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
+import static dagger.internal.codegen.FrameworkTypes.isFrameworkType;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.multibindings.Multibinds;
+import dagger.producers.ProducerModule;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeMirror;
+
+/** A validator for {@link Multibinds} methods. */
+class MultibindsMethodValidator extends BindingMethodValidator {
+
+ /** Creates a validator for {@link Multibinds @Multibinds} methods. */
+ @Inject
+ MultibindsMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestValidator dependencyRequestValidator) {
+ super(
+ elements,
+ types,
+ Multibinds.class,
+ ImmutableSet.of(Module.class, ProducerModule.class),
+ dependencyRequestValidator,
+ MUST_BE_ABSTRACT,
+ NO_EXCEPTIONS,
+ NO_MULTIBINDINGS,
+ NO_SCOPING);
+ }
+
+ @Override
+ protected ElementValidator elementValidator(ExecutableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends MethodValidator {
+ Validator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkParameters() {
+ if (!element.getParameters().isEmpty()) {
+ report.addError(bindingMethods("cannot have parameters"));
+ }
+ }
+
+ /** Adds an error unless the method returns a {@code Map<K, V>} or {@code Set<T>}. */
+ @Override
+ protected void checkType() {
+ if (!isPlainMap(element.getReturnType())
+ && !isPlainSet(element.getReturnType())) {
+ report.addError(bindingMethods("must return Map<K, V> or Set<T>"));
+ }
+ }
+
+ private boolean isPlainMap(TypeMirror returnType) {
+ if (!MapType.isMap(returnType)) {
+ return false;
+ }
+ MapType mapType = MapType.from(returnType);
+ return !mapType.isRawType()
+ && MoreTypes.isType(mapType.valueType()) // No wildcards.
+ && !isFrameworkType(mapType.valueType());
+ }
+
+ private boolean isPlainSet(TypeMirror returnType) {
+ if (!SetType.isSet(returnType)) {
+ return false;
+ }
+ SetType setType = SetType.from(returnType);
+ return !setType.isRawType()
+ && MoreTypes.isType(setType.elementType()) // No wildcards.
+ && !isFrameworkType(setType.elementType());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/NullableBindingValidator.java b/java/dagger/internal/codegen/NullableBindingValidator.java
new file mode 100644
index 0000000..1452c3f
--- /dev/null
+++ b/java/dagger/internal/codegen/NullableBindingValidator.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import javax.inject.Inject;
+
+/**
+ * Reports errors or warnings (depending on the {@code -Adagger.nullableValidation} value) for each
+ * non-nullable dependency request that is satisfied by a nullable binding.
+ */
+final class NullableBindingValidator implements BindingGraphPlugin {
+
+ private final CompilerOptions compilerOptions;
+
+ @Inject
+ NullableBindingValidator(CompilerOptions compilerOptions) {
+ this.compilerOptions = compilerOptions;
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ for (dagger.model.Binding binding : nullableBindings(bindingGraph)) {
+ for (DependencyEdge dependencyEdge : nonNullableDependencies(bindingGraph, binding)) {
+ diagnosticReporter.reportDependency(
+ compilerOptions.nullableValidationKind(),
+ dependencyEdge,
+ nullableToNonNullable(
+ binding.key().toString(),
+ binding.toString())); // binding.toString() will include the @Nullable
+ }
+ }
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/Nullable";
+ }
+
+ private ImmutableList<dagger.model.Binding> nullableBindings(BindingGraph bindingGraph) {
+ return bindingGraph.bindings().stream()
+ .filter(binding -> binding.isNullable())
+ .collect(toImmutableList());
+ }
+
+ private ImmutableSet<DependencyEdge> nonNullableDependencies(
+ BindingGraph bindingGraph, dagger.model.Binding binding) {
+ return bindingGraph.network().inEdges(binding).stream()
+ .flatMap(instancesOf(DependencyEdge.class))
+ .filter(edge -> !edge.dependencyRequest().isNullable())
+ .collect(toImmutableSet());
+ }
+
+ @VisibleForTesting
+ static String nullableToNonNullable(String key, String binding) {
+ return String.format("%s is not nullable, but is being provided by %s", key, binding);
+ }
+}
diff --git a/java/dagger/internal/codegen/OptionalBindingDeclaration.java b/java/dagger/internal/codegen/OptionalBindingDeclaration.java
new file mode 100644
index 0000000..b26ab91
--- /dev/null
+++ b/java/dagger/internal/codegen/OptionalBindingDeclaration.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.auto.common.MoreElements.isAnnotationPresent;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import dagger.BindsOptionalOf;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/** A {@link BindsOptionalOf} declaration. */
+@AutoValue
+abstract class OptionalBindingDeclaration extends BindingDeclaration {
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The key's type is the method's return type, even though the synthetic bindings will be for
+ * {@code Optional} of derived types.
+ */
+ @Override
+ public abstract Key key();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ static class Factory {
+ private final KeyFactory keyFactory;
+
+ @Inject
+ Factory(KeyFactory keyFactory) {
+ this.keyFactory = keyFactory;
+ }
+
+ OptionalBindingDeclaration forMethod(ExecutableElement method, TypeElement contributingModule) {
+ checkArgument(isAnnotationPresent(method, BindsOptionalOf.class));
+ return new AutoValue_OptionalBindingDeclaration(
+ Optional.<Element>of(method),
+ Optional.of(contributingModule),
+ keyFactory.forBindsOptionalOfMethod(method, contributingModule));
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/OptionalBindingExpression.java b/java/dagger/internal/codegen/OptionalBindingExpression.java
new file mode 100644
index 0000000..dbb0e37
--- /dev/null
+++ b/java/dagger/internal/codegen/OptionalBindingExpression.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.OptionalType.OptionalKind;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+
+/** A binding expression for optional bindings. */
+final class OptionalBindingExpression extends SimpleInvocationBindingExpression {
+ private final ProvisionBinding binding;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+ private final SourceVersion sourceVersion;
+
+ @Inject
+ OptionalBindingExpression(
+ ResolvedBindings resolvedBindings,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types,
+ SourceVersion sourceVersion) {
+ super(resolvedBindings);
+ this.binding = (ProvisionBinding) resolvedBindings.contributionBinding();
+ this.componentBindingExpressions = componentBindingExpressions;
+ this.types = types;
+ this.sourceVersion = sourceVersion;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ OptionalType optionalType = OptionalType.from(binding.key());
+ OptionalKind optionalKind = optionalType.kind();
+ if (binding.dependencies().isEmpty()) {
+ if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
+ // When compiling with -source 7, javac's type inference isn't strong enough to detect
+ // Futures.immediateFuture(Optional.absent()) for keys that aren't Object. It also has
+ // issues
+ // when used as an argument to some members injection proxy methods (see
+ // https://github.com/google/dagger/issues/916)
+ if (isTypeAccessibleFrom(binding.key().type(), requestingClass.packageName())) {
+ return Expression.create(
+ binding.key().type(), optionalKind.parameterizedAbsentValueExpression(optionalType));
+ }
+ }
+ return Expression.create(binding.key().type(), optionalKind.absentValueExpression());
+ }
+ DependencyRequest dependency = getOnlyElement(binding.dependencies());
+
+ CodeBlock dependencyExpression =
+ componentBindingExpressions
+ .getDependencyExpression(bindingRequest(dependency), requestingClass)
+ .codeBlock();
+
+ // If the dependency type is inaccessible, then we have to use Optional.<Object>of(...), or else
+ // we will get "incompatible types: inference variable has incompatible bounds.
+ return isTypeAccessibleFrom(dependency.key().type(), requestingClass.packageName())
+ ? Expression.create(
+ binding.key().type(), optionalKind.presentExpression(dependencyExpression))
+ : Expression.create(
+ types.erasure(binding.key().type()),
+ optionalKind.presentObjectExpression(dependencyExpression));
+ }
+
+ @Override
+ boolean requiresMethodEncapsulation() {
+ // TODO(dpb): Maybe require it for present bindings.
+ return false;
+ }
+}
diff --git a/java/dagger/internal/codegen/OptionalFactories.java b/java/dagger/internal/codegen/OptionalFactories.java
new file mode 100644
index 0000000..51c9939
--- /dev/null
+++ b/java/dagger/internal/codegen/OptionalFactories.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.ComponentImplementation.FieldSpecKind.ABSENT_OPTIONAL_FIELD;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.ABSENT_OPTIONAL_METHOD;
+import static dagger.internal.codegen.ComponentImplementation.TypeSpecKind.PRESENT_FACTORY;
+import static dagger.internal.codegen.RequestKinds.requestTypeName;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
+import static dagger.internal.codegen.javapoet.TypeNames.abstractProducerOf;
+import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
+import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+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 com.squareup.javapoet.TypeVariableName;
+import dagger.internal.InstanceFactory;
+import dagger.internal.Preconditions;
+import dagger.internal.codegen.OptionalType.OptionalKind;
+import dagger.internal.codegen.javapoet.AnnotationSpecs;
+import dagger.model.RequestKind;
+import dagger.producers.Producer;
+import dagger.producers.internal.Producers;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+import java.util.concurrent.Executor;
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+/** The nested class and static methods required by the component to implement optional bindings. */
+// TODO(dpb): Name members simply if a component uses only one of Guava or JDK Optional.
+@PerGeneratedFile
+final class OptionalFactories {
+ private final ComponentImplementation componentImplementation;
+
+ @Inject OptionalFactories(@TopLevel ComponentImplementation componentImplementation) {
+ this.componentImplementation = componentImplementation;
+ }
+
+ /**
+ * The factory classes that implement {@code Provider<Optional<T>>} or {@code
+ * Producer<Optional<T>>} for present optional bindings for a given kind of dependency request
+ * within the component.
+ *
+ * <p>The key is the {@code Provider<Optional<T>>} type.
+ */
+ private final Map<PresentFactorySpec, TypeSpec> presentFactoryClasses =
+ new TreeMap<>(
+ Comparator.comparing(PresentFactorySpec::valueKind)
+ .thenComparing(PresentFactorySpec::frameworkType)
+ .thenComparing(PresentFactorySpec::optionalKind));
+
+ /**
+ * The static methods that return a {@code Provider<Optional<T>>} that always returns an absent
+ * value.
+ */
+ private final Map<OptionalKind, MethodSpec> absentOptionalProviderMethods = new TreeMap<>();
+
+ /**
+ * The static fields for {@code Provider<Optional<T>>} objects that always return an absent value.
+ */
+ private final Map<OptionalKind, FieldSpec> absentOptionalProviderFields = new TreeMap<>();
+
+ /**
+ * Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>}
+ * for absent optional bindings.
+ */
+ CodeBlock absentOptionalProvider(ContributionBinding binding) {
+ verify(
+ binding.bindingType().equals(BindingType.PROVISION),
+ "Absent optional bindings should be provisions: %s",
+ binding);
+ OptionalKind optionalKind = OptionalType.from(binding.key()).kind();
+ return CodeBlock.of(
+ "$N()",
+ absentOptionalProviderMethods.computeIfAbsent(
+ optionalKind,
+ kind -> {
+ MethodSpec method = absentOptionalProviderMethod(kind);
+ componentImplementation.addMethod(ABSENT_OPTIONAL_METHOD, method);
+ return method;
+ }));
+ }
+
+ /**
+ * Creates a method specification for a {@code Provider<Optional<T>>} that always returns an
+ * absent value.
+ */
+ private MethodSpec absentOptionalProviderMethod(OptionalKind optionalKind) {
+ TypeVariableName typeVariable = TypeVariableName.get("T");
+ return methodBuilder(
+ String.format(
+ "absent%sProvider", UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind.name())))
+ .addModifiers(PRIVATE, STATIC)
+ .addTypeVariable(typeVariable)
+ .returns(providerOf(optionalKind.of(typeVariable)))
+ .addJavadoc(
+ "Returns a {@link $T} that returns {@code $L}.",
+ Provider.class,
+ optionalKind.absentValueExpression())
+ .addCode("$L // safe covariant cast\n", AnnotationSpecs.suppressWarnings(UNCHECKED))
+ .addCode(
+ "$1T provider = ($1T) $2N;",
+ providerOf(optionalKind.of(typeVariable)),
+ absentOptionalProviderFields.computeIfAbsent(
+ optionalKind,
+ kind -> {
+ FieldSpec field = absentOptionalProviderField(kind);
+ componentImplementation.addField(ABSENT_OPTIONAL_FIELD, field);
+ return field;
+ }))
+ .addCode("return provider;")
+ .build();
+ }
+
+ /**
+ * Creates a field specification for a {@code Provider<Optional<T>>} that always returns an absent
+ * value.
+ */
+ private FieldSpec absentOptionalProviderField(OptionalKind optionalKind) {
+ return FieldSpec.builder(
+ PROVIDER,
+ String.format("ABSENT_%s_PROVIDER", optionalKind.name()),
+ PRIVATE,
+ STATIC,
+ FINAL)
+ .addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES))
+ .initializer("$T.create($L)", InstanceFactory.class, optionalKind.absentValueExpression())
+ .addJavadoc(
+ "A {@link $T} that returns {@code $L}.",
+ Provider.class,
+ optionalKind.absentValueExpression())
+ .build();
+ }
+
+ /** Information about the type of a factory for present bindings. */
+ @AutoValue
+ abstract static class PresentFactorySpec {
+ /** Whether the factory is a {@link Provider} or a {@link Producer}. */
+ abstract FrameworkType frameworkType();
+
+ /** What kind of {@code Optional} is returned. */
+ abstract OptionalKind optionalKind();
+
+ /** The kind of request satisfied by the value of the {@code Optional}. */
+ abstract RequestKind valueKind();
+
+ /** The type variable for the factory class. */
+ TypeVariableName typeVariable() {
+ return TypeVariableName.get("T");
+ }
+
+ /** The type contained by the {@code Optional}. */
+ TypeName valueType() {
+ return requestTypeName(valueKind(), typeVariable());
+ }
+
+ /** The type provided or produced by the factory. */
+ ParameterizedTypeName optionalType() {
+ return optionalKind().of(valueType());
+ }
+
+ /** The type of the factory. */
+ ParameterizedTypeName factoryType() {
+ return frameworkType().frameworkClassOf(optionalType());
+ }
+
+ /** The type of the delegate provider or producer. */
+ ParameterizedTypeName delegateType() {
+ return frameworkType().frameworkClassOf(typeVariable());
+ }
+
+ /** Returns the superclass the generated factory should have, if any. */
+ Optional<ParameterizedTypeName> superclass() {
+ switch (frameworkType()) {
+ case PRODUCER_NODE:
+ // TODO(cgdecker): This probably isn't a big issue for now, but it's possible this
+ // shouldn't be an AbstractProducer:
+ // - As AbstractProducer, it'll only call the delegate's get() method once and then cache
+ // that result (essentially) rather than calling the delegate's get() method each time
+ // its get() method is called (which was what it did before the cancellation change).
+ // - It's not 100% clear to me whether the view-creation methods should return a view of
+ // the same view created by the delegate or if they should just return their own views.
+ return Optional.of(abstractProducerOf(optionalType()));
+ default:
+ return Optional.empty();
+ }
+ }
+
+ /** Returns the superinterface the generated factory should have, if any. */
+ Optional<ParameterizedTypeName> superinterface() {
+ switch (frameworkType()) {
+ case PROVIDER:
+ return Optional.of(factoryType());
+ default:
+ return Optional.empty();
+ }
+ }
+
+ /** Returns the name of the factory method to generate. */
+ String factoryMethodName() {
+ switch (frameworkType()) {
+ case PROVIDER:
+ return "get";
+ case PRODUCER_NODE:
+ return "compute";
+ }
+ throw new AssertionError(frameworkType());
+ }
+
+ /** The name of the factory class. */
+ String factoryClassName() {
+ return new StringBuilder("Present")
+ .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind().name()))
+ .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind().toString()))
+ .append(frameworkType().frameworkClass().getSimpleName())
+ .toString();
+ }
+
+ private static PresentFactorySpec of(ContributionBinding binding) {
+ return new AutoValue_OptionalFactories_PresentFactorySpec(
+ FrameworkType.forBindingType(binding.bindingType()),
+ OptionalType.from(binding.key()).kind(),
+ getOnlyElement(binding.dependencies()).kind());
+ }
+ }
+
+ /**
+ * Returns an expression for an instance of a nested class that implements {@code
+ * Provider<Optional<T>>} or {@code Producer<Optional<T>>} for a present optional binding, where
+ * {@code T} represents dependency requests of that kind.
+ *
+ * <ul>
+ * <li>If {@code optionalRequestKind} is {@link RequestKind#INSTANCE}, the class implements
+ * {@code ProviderOrProducer<Optional<T>>}.
+ * <li>If {@code optionalRequestKind} is {@link RequestKind#PROVIDER}, the class implements
+ * {@code Provider<Optional<Provider<T>>>}.
+ * <li>If {@code optionalRequestKind} is {@link RequestKind#LAZY}, the class implements {@code
+ * Provider<Optional<Lazy<T>>>}.
+ * <li>If {@code optionalRequestKind} is {@link RequestKind#PROVIDER_OF_LAZY}, the class
+ * implements {@code Provider<Optional<Provider<Lazy<T>>>>}.
+ * <li>If {@code optionalRequestKind} is {@link RequestKind#PRODUCER}, the class implements
+ * {@code Producer<Optional<Producer<T>>>}.
+ * <li>If {@code optionalRequestKind} is {@link RequestKind#PRODUCED}, the class implements
+ * {@code Producer<Optional<Produced<T>>>}.
+ * </ul>
+ *
+ * @param delegateFactory an expression for a {@link Provider} or {@link Producer} of the
+ * underlying type
+ */
+ CodeBlock presentOptionalFactory(ContributionBinding binding, CodeBlock delegateFactory) {
+ return CodeBlock.of(
+ "$N.of($L)",
+ presentFactoryClasses.computeIfAbsent(
+ PresentFactorySpec.of(binding),
+ spec -> {
+ TypeSpec type = presentOptionalFactoryClass(spec);
+ componentImplementation.addType(PRESENT_FACTORY, type);
+ return type;
+ }),
+ delegateFactory);
+ }
+
+ private TypeSpec presentOptionalFactoryClass(PresentFactorySpec spec) {
+ FieldSpec delegateField =
+ FieldSpec.builder(spec.delegateType(), "delegate", PRIVATE, FINAL).build();
+ ParameterSpec delegateParameter = ParameterSpec.builder(delegateField.type, "delegate").build();
+ TypeSpec.Builder factoryClassBuilder =
+ classBuilder(spec.factoryClassName())
+ .addTypeVariable(spec.typeVariable())
+ .addModifiers(PRIVATE, STATIC, FINAL)
+ .addJavadoc(
+ "A {@code $T} that uses a delegate {@code $T}.",
+ spec.factoryType(),
+ delegateField.type);
+
+ spec.superclass().ifPresent(factoryClassBuilder::superclass);
+ spec.superinterface().ifPresent(factoryClassBuilder::addSuperinterface);
+
+ return factoryClassBuilder
+ .addField(delegateField)
+ .addMethod(
+ constructorBuilder()
+ .addModifiers(PRIVATE)
+ .addParameter(delegateParameter)
+ .addCode(
+ "this.$N = $T.checkNotNull($N);",
+ delegateField,
+ Preconditions.class,
+ delegateParameter)
+ .build())
+ .addMethod(presentOptionalFactoryGetMethod(spec, delegateField))
+ .addMethod(
+ methodBuilder("of")
+ .addModifiers(PRIVATE, STATIC)
+ .addTypeVariable(spec.typeVariable())
+ .returns(spec.factoryType())
+ .addParameter(delegateParameter)
+ .addCode(
+ "return new $L<$T>($N);",
+ spec.factoryClassName(),
+ spec.typeVariable(),
+ delegateParameter)
+ .build())
+ .build();
+ }
+
+ private MethodSpec presentOptionalFactoryGetMethod(
+ PresentFactorySpec spec, FieldSpec delegateField) {
+ MethodSpec.Builder getMethodBuilder =
+ methodBuilder(spec.factoryMethodName()).addAnnotation(Override.class).addModifiers(PUBLIC);
+
+ switch (spec.frameworkType()) {
+ case PROVIDER:
+ return getMethodBuilder
+ .returns(spec.optionalType())
+ .addCode(
+ "return $L;",
+ spec.optionalKind()
+ .presentExpression(
+ FrameworkType.PROVIDER.to(
+ spec.valueKind(), CodeBlock.of("$N", delegateField))))
+ .build();
+
+ case PRODUCER_NODE:
+ getMethodBuilder.returns(listenableFutureOf(spec.optionalType()));
+
+ switch (spec.valueKind()) {
+ case FUTURE: // return a ListenableFuture<Optional<ListenableFuture<T>>>
+ case PRODUCER: // return a ListenableFuture<Optional<Producer<T>>>
+ return getMethodBuilder
+ .addCode(
+ "return $T.immediateFuture($L);",
+ Futures.class,
+ spec.optionalKind()
+ .presentExpression(
+ FrameworkType.PRODUCER_NODE.to(
+ spec.valueKind(), CodeBlock.of("$N", delegateField))))
+ .build();
+
+ case INSTANCE: // return a ListenableFuture<Optional<T>>
+ return getMethodBuilder
+ .addCode(
+ "return $L;",
+ transformFutureToOptional(
+ spec.optionalKind(),
+ spec.typeVariable(),
+ CodeBlock.of("$N.get()", delegateField)))
+ .build();
+
+ case PRODUCED: // return a ListenableFuture<Optional<Produced<T>>>
+ return getMethodBuilder
+ .addCode(
+ "return $L;",
+ transformFutureToOptional(
+ spec.optionalKind(),
+ spec.valueType(),
+ CodeBlock.of(
+ "$T.createFutureProduced($N.get())", Producers.class, delegateField)))
+ .build();
+
+ default:
+ throw new UnsupportedOperationException(
+ spec.factoryType() + " objects are not supported");
+ }
+ }
+ throw new AssertionError(spec.frameworkType());
+ }
+
+ /**
+ * An expression that uses {@link Futures#transform(ListenableFuture, Function, Executor)} to
+ * transform a {@code ListenableFuture<inputType>} into a {@code
+ * ListenableFuture<Optional<inputType>>}.
+ *
+ * @param inputFuture an expression of type {@code ListenableFuture<inputType>}
+ */
+ private static CodeBlock transformFutureToOptional(
+ OptionalKind optionalKind, TypeName inputType, CodeBlock inputFuture) {
+ return CodeBlock.of(
+ "$T.transform($L, $L, $T.directExecutor())",
+ Futures.class,
+ inputFuture,
+ anonymousClassBuilder("")
+ .addSuperinterface(
+ ParameterizedTypeName.get(
+ ClassName.get(Function.class), inputType, optionalKind.of(inputType)))
+ .addMethod(
+ methodBuilder("apply")
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .returns(optionalKind.of(inputType))
+ .addParameter(inputType, "input")
+ .addCode("return $L;", optionalKind.presentExpression(CodeBlock.of("input")))
+ .build())
+ .build(),
+ MoreExecutors.class);
+ }
+}
diff --git a/java/dagger/internal/codegen/OptionalFactoryInstanceCreationExpression.java b/java/dagger/internal/codegen/OptionalFactoryInstanceCreationExpression.java
new file mode 100644
index 0000000..ba9e25f
--- /dev/null
+++ b/java/dagger/internal/codegen/OptionalFactoryInstanceCreationExpression.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/**
+ * A {@link FrameworkInstanceCreationExpression} for {@link dagger.model.BindingKind#OPTIONAL
+ * optional bindings}.
+ */
+final class OptionalFactoryInstanceCreationExpression
+ implements FrameworkInstanceCreationExpression {
+ private final OptionalFactories optionalFactories;
+ private final ContributionBinding binding;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentBindingExpressions componentBindingExpressions;
+
+ OptionalFactoryInstanceCreationExpression(
+ OptionalFactories optionalFactories,
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions) {
+ this.optionalFactories = optionalFactories;
+ this.binding = binding;
+ this.componentImplementation = componentImplementation;
+ this.componentBindingExpressions = componentBindingExpressions;
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ return binding.dependencies().isEmpty()
+ ? optionalFactories.absentOptionalProvider(binding)
+ : optionalFactories.presentOptionalFactory(
+ binding,
+ componentBindingExpressions
+ .getDependencyExpression(
+ bindingRequest(
+ getOnlyElement(binding.dependencies()).key(), binding.frameworkType()),
+ componentImplementation.name())
+ .codeBlock());
+ }
+
+ @Override
+ public boolean useInnerSwitchingProvider() {
+ // Share providers for empty optionals from OptionalFactories so we don't have numerous
+ // switch cases that all return Optional.empty().
+ return !binding.dependencies().isEmpty();
+ }
+}
diff --git a/java/dagger/internal/codegen/OptionalType.java b/java/dagger/internal/codegen/OptionalType.java
new file mode 100644
index 0000000..0fdbf68
--- /dev/null
+++ b/java/dagger/internal/codegen/OptionalType.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.common.MoreElements;
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.lang.model.element.Name;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVisitor;
+import javax.lang.model.util.SimpleTypeVisitor8;
+
+/**
+ * Information about an {@code Optional} {@link TypeMirror}.
+ *
+ * <p>{@link com.google.common.base.Optional} and {@link java.util.Optional} are supported.
+ */
+@AutoValue
+abstract class OptionalType {
+
+ /** A variant of {@code Optional}. */
+ enum OptionalKind {
+ /** {@link com.google.common.base.Optional}. */
+ GUAVA_OPTIONAL(com.google.common.base.Optional.class, "absent"),
+
+ /** {@link java.util.Optional}. */
+ JDK_OPTIONAL(java.util.Optional.class, "empty"),
+ ;
+
+ private final Class<?> clazz;
+ private final String absentFactoryMethodName;
+
+ OptionalKind(Class<?> clazz, String absentFactoryMethodName) {
+ this.clazz = clazz;
+ this.absentFactoryMethodName = absentFactoryMethodName;
+ }
+
+ /** Returns {@code valueType} wrapped in the correct class. */
+ ParameterizedTypeName of(TypeName valueType) {
+ return ParameterizedTypeName.get(ClassName.get(clazz), valueType);
+ }
+
+ /** Returns an expression for the absent/empty value. */
+ CodeBlock absentValueExpression() {
+ return CodeBlock.of("$T.$L()", clazz, absentFactoryMethodName);
+ }
+
+ /**
+ * Returns an expression for the absent/empty value, parameterized with {@link #valueType()}.
+ */
+ CodeBlock parameterizedAbsentValueExpression(OptionalType optionalType) {
+ return CodeBlock.of("$T.<$T>$L()", clazz, optionalType.valueType(), absentFactoryMethodName);
+ }
+
+ /** Returns an expression for the present {@code value}. */
+ CodeBlock presentExpression(CodeBlock value) {
+ return CodeBlock.of("$T.of($L)", clazz, value);
+ }
+
+ /**
+ * Returns an expression for the present {@code value}, returning {@code Optional<Object>} no
+ * matter what type the value is.
+ */
+ CodeBlock presentObjectExpression(CodeBlock value) {
+ return CodeBlock.of("$T.<$T>of($L)", clazz, Object.class, value);
+ }
+ }
+
+ private static final TypeVisitor<Optional<OptionalKind>, Void> OPTIONAL_KIND =
+ new SimpleTypeVisitor8<Optional<OptionalKind>, Void>(Optional.empty()) {
+ @Override
+ public Optional<OptionalKind> visitDeclared(DeclaredType t, Void p) {
+ for (OptionalKind optionalKind : OptionalKind.values()) {
+ Name qualifiedName = MoreElements.asType(t.asElement()).getQualifiedName();
+ if (qualifiedName.contentEquals(optionalKind.clazz.getCanonicalName())) {
+ return Optional.of(optionalKind);
+ }
+ }
+ return Optional.empty();
+ }
+ };
+
+ /**
+ * The optional type itself, wrapped using {@link MoreTypes#equivalence()}.
+ *
+ * @deprecated Use {@link #declaredOptionalType()} instead.
+ */
+ @Deprecated
+ protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredOptionalType();
+
+ /** The optional type itself. */
+ @SuppressWarnings("deprecation")
+ DeclaredType declaredOptionalType() {
+ return wrappedDeclaredOptionalType().get();
+ }
+
+ /** Which {@code Optional} type is used. */
+ OptionalKind kind() {
+ return declaredOptionalType().accept(OPTIONAL_KIND, null).get();
+ }
+
+ /** The value type. */
+ TypeMirror valueType() {
+ return declaredOptionalType().getTypeArguments().get(0);
+ }
+
+ /** Returns {@code true} if {@code type} is an {@code Optional} type. */
+ static boolean isOptional(TypeMirror type) {
+ return type.accept(OPTIONAL_KIND, null).isPresent();
+ }
+
+ /** Returns {@code true} if {@code key.type()} is an {@code Optional} type. */
+ static boolean isOptional(Key key) {
+ return isOptional(key.type());
+ }
+
+ /**
+ * Returns a {@link OptionalType} for {@code type}.
+ *
+ * @throws IllegalArgumentException if {@code type} is not an {@code Optional} type
+ */
+ static OptionalType from(TypeMirror type) {
+ checkArgument(isOptional(type), "%s must be an Optional", type);
+ return new AutoValue_OptionalType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
+ }
+
+ /**
+ * Returns a {@link OptionalType} for {@code key}'s {@link Key#type() type}.
+ *
+ * @throws IllegalArgumentException if {@code key.type()} is not an {@code Optional} type
+ */
+ static OptionalType from(Key key) {
+ return from(key.type());
+ }
+}
diff --git a/java/dagger/internal/codegen/Optionals.java b/java/dagger/internal/codegen/Optionals.java
new file mode 100644
index 0000000..1021c35
--- /dev/null
+++ b/java/dagger/internal/codegen/Optionals.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.asList;
+
+import java.util.Comparator;
+import java.util.Optional;
+import java.util.function.Function;
+
+/** Utilities for {@link Optional}s. */
+final class Optionals {
+ /**
+ * A {@link Comparator} that puts empty {@link Optional}s before present ones, and compares
+ * present {@link Optional}s by their values.
+ */
+ static <C extends Comparable<C>> Comparator<Optional<C>> optionalComparator() {
+ return Comparator.comparing((Optional<C> optional) -> optional.isPresent())
+ .thenComparing(Optional::get);
+ }
+
+ static <T> Comparator<Optional<T>> emptiesLast(Comparator<? super T> valueComparator) {
+ checkNotNull(valueComparator);
+ return Comparator.comparing(o -> o.orElse(null), Comparator.nullsLast(valueComparator));
+ }
+
+ /** Returns the first argument that is present, or empty if none are. */
+ @SafeVarargs
+ static <T> Optional<T> firstPresent(Optional<T> first, Optional<T> second, Optional<T>... rest) {
+ return asList(first, second, rest)
+ .stream()
+ .filter(Optional::isPresent)
+ .findFirst()
+ .orElse(Optional.empty());
+ }
+
+ /**
+ * Walks a chain of present optionals as defined by successive calls to {@code nextFunction},
+ * returning the value of the final optional that is present. The first optional in the chain is
+ * the result of {@code nextFunction(start)}.
+ */
+ static <T> T rootmostValue(T start, Function<T, Optional<T>> nextFunction) {
+ T current = start;
+ for (Optional<T> next = nextFunction.apply(start);
+ next.isPresent();
+ next = nextFunction.apply(current)) {
+ current = next.get();
+ }
+ return current;
+ }
+
+ private Optionals() {}
+}
diff --git a/java/dagger/internal/codegen/ParentComponent.java b/java/dagger/internal/codegen/ParentComponent.java
new file mode 100644
index 0000000..2d2b583
--- /dev/null
+++ b/java/dagger/internal/codegen/ParentComponent.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+/**
+ * A {@link Qualifier} for bindings that are associated with a component implementation's
+ * parent component.
+ */
+@Retention(RUNTIME)
+@Qualifier
+@interface ParentComponent {}
diff --git a/java/dagger/internal/codegen/PerComponentImplementation.java b/java/dagger/internal/codegen/PerComponentImplementation.java
new file mode 100644
index 0000000..5d4ba18
--- /dev/null
+++ b/java/dagger/internal/codegen/PerComponentImplementation.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Scope;
+
+/** A {@link Scope} that encompasses a single component implementation. */
+@Retention(RUNTIME)
+@Scope
+@interface PerComponentImplementation {}
diff --git a/java/dagger/internal/codegen/PerGeneratedFile.java b/java/dagger/internal/codegen/PerGeneratedFile.java
new file mode 100644
index 0000000..c30e67a
--- /dev/null
+++ b/java/dagger/internal/codegen/PerGeneratedFile.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Scope;
+
+/**
+ * A {@link Scope} that encompasses a top-level component implementation and any of its inner
+ * descendant component implementations in the same generated file.
+ */
+@Retention(RUNTIME)
+@Scope
+@interface PerGeneratedFile {}
diff --git a/java/dagger/internal/codegen/PrivateMethodBindingExpression.java b/java/dagger/internal/codegen/PrivateMethodBindingExpression.java
new file mode 100644
index 0000000..482c123
--- /dev/null
+++ b/java/dagger/internal/codegen/PrivateMethodBindingExpression.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static dagger.internal.codegen.ComponentImplementation.MethodSpecKind.PRIVATE_METHOD;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+
+/**
+ * A binding expression that wraps the dependency expressions in a private, no-arg method.
+ *
+ * <p>Dependents of this binding expression will just call the no-arg private method.
+ */
+final class PrivateMethodBindingExpression extends MethodBindingExpression {
+ private final BindingRequest request;
+ private final ComponentImplementation componentImplementation;
+ private String methodName;
+
+ PrivateMethodBindingExpression(
+ BindingRequest request,
+ ResolvedBindings resolvedBindings,
+ MethodImplementationStrategy methodImplementationStrategy,
+ BindingExpression wrappedBindingExpression,
+ ComponentImplementation componentImplementation,
+ DaggerTypes types) {
+ super(
+ request,
+ resolvedBindings,
+ methodImplementationStrategy,
+ wrappedBindingExpression,
+ componentImplementation,
+ types);
+ this.request = checkNotNull(request);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ }
+
+ @Override
+ protected void addMethod() {
+ if (methodName == null) {
+ // Have to set methodName field before implementing the method in order to handle recursion.
+ methodName = componentImplementation.getUniqueMethodName(request);
+ // TODO(user): Fix the order that these generated methods are written to the component.
+ componentImplementation.addMethod(
+ PRIVATE_METHOD,
+ methodBuilder(methodName)
+ .addModifiers(PRIVATE)
+ .returns(TypeName.get(returnType()))
+ .addCode(methodBody())
+ .build());
+ }
+ }
+
+ @Override
+ protected String methodName() {
+ checkState(methodName != null, "addMethod() must be called before methodName()");
+ return methodName;
+ }
+}
diff --git a/java/dagger/internal/codegen/ProcessingEnvironmentCompilerOptions.java b/java/dagger/internal/codegen/ProcessingEnvironmentCompilerOptions.java
new file mode 100644
index 0000000..cf2475d
--- /dev/null
+++ b/java/dagger/internal/codegen/ProcessingEnvironmentCompilerOptions.java
@@ -0,0 +1,484 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Sets.immutableEnumSet;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.FeatureStatus.DISABLED;
+import static dagger.internal.codegen.FeatureStatus.ENABLED;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.EMIT_MODIFIABLE_METADATA_ANNOTATIONS;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_ANDROID_MODE;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.FAST_INIT;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.FLOATING_BINDS_METHODS;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.FORCE_USE_SERIALIZED_COMPONENT_IMPLEMENTATIONS;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Feature.WRITE_PRODUCER_NAME_IN_TOKEN;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.KeyOnlyOption.HEADER_COMPILATION;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.KeyOnlyOption.USE_GRADLE_INCREMENTAL_PROCESSING;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.DISABLE_INTER_COMPONENT_SCOPE_VALIDATION;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.EXPLICIT_BINDING_CONFLICTS_WITH_INJECT;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.FULL_BINDING_GRAPH_VALIDATION;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.MODULE_HAS_DIFFERENT_SCOPES_VALIDATION;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.NULLABLE_VALIDATION;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.PRIVATE_MEMBER_VALIDATION;
+import static dagger.internal.codegen.ProcessingEnvironmentCompilerOptions.Validation.STATIC_MEMBER_VALIDATION;
+import static dagger.internal.codegen.ValidationType.ERROR;
+import static dagger.internal.codegen.ValidationType.NONE;
+import static dagger.internal.codegen.ValidationType.WARNING;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Stream.concat;
+
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import dagger.producers.Produces;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+final class ProcessingEnvironmentCompilerOptions extends CompilerOptions {
+ /** Returns a valid {@link CompilerOptions} parsed from the processing environment. */
+ static CompilerOptions create(ProcessingEnvironment processingEnvironment) {
+ return new ProcessingEnvironmentCompilerOptions(processingEnvironment).checkValid();
+ }
+
+ private final ProcessingEnvironment processingEnvironment;
+ private final Map<EnumOption<?>, Object> enumOptions = new HashMap<>();
+ private final Map<EnumOption<?>, ImmutableMap<String, ? extends Enum<?>>> allCommandLineOptions =
+ new HashMap<>();
+
+ private ProcessingEnvironmentCompilerOptions(ProcessingEnvironment processingEnvironment) {
+ this.processingEnvironment = processingEnvironment;
+ }
+
+ @Override
+ boolean usesProducers() {
+ return processingEnvironment.getElementUtils().getTypeElement(Produces.class.getCanonicalName())
+ != null;
+ }
+
+ @Override
+ boolean headerCompilation() {
+ return isEnabled(HEADER_COMPILATION);
+ }
+
+ @Override
+ boolean fastInit() {
+ return isEnabled(FAST_INIT);
+ }
+
+ @Override
+ boolean formatGeneratedSource() {
+ return isEnabled(FORMAT_GENERATED_SOURCE);
+ }
+
+ @Override
+ boolean writeProducerNameInToken() {
+ return isEnabled(WRITE_PRODUCER_NAME_IN_TOKEN);
+ }
+
+ @Override
+ Diagnostic.Kind nullableValidationKind() {
+ return diagnosticKind(NULLABLE_VALIDATION);
+ }
+
+ @Override
+ Diagnostic.Kind privateMemberValidationKind() {
+ return diagnosticKind(PRIVATE_MEMBER_VALIDATION);
+ }
+
+ @Override
+ Diagnostic.Kind staticMemberValidationKind() {
+ return diagnosticKind(STATIC_MEMBER_VALIDATION);
+ }
+
+ @Override
+ boolean ignorePrivateAndStaticInjectionForComponent() {
+ return isEnabled(IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT);
+ }
+
+ @Override
+ ValidationType scopeCycleValidationType() {
+ return parseOption(DISABLE_INTER_COMPONENT_SCOPE_VALIDATION);
+ }
+
+ @Override
+ boolean warnIfInjectionFactoryNotGeneratedUpstream() {
+ return isEnabled(WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM);
+ }
+
+ @Override
+ boolean aheadOfTimeSubcomponents() {
+ return isEnabled(EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS);
+ }
+
+ @Override
+ boolean forceUseSerializedComponentImplementations() {
+ return isEnabled(FORCE_USE_SERIALIZED_COMPONENT_IMPLEMENTATIONS);
+ }
+
+ @Override
+ boolean emitModifiableMetadataAnnotations() {
+ return isEnabled(EMIT_MODIFIABLE_METADATA_ANNOTATIONS);
+ }
+
+ @Override
+ boolean useGradleIncrementalProcessing() {
+ return isEnabled(USE_GRADLE_INCREMENTAL_PROCESSING);
+ }
+
+ @Override
+ ValidationType fullBindingGraphValidationType(TypeElement element) {
+ return fullBindingGraphValidationType();
+ }
+
+ private ValidationType fullBindingGraphValidationType() {
+ return parseOption(FULL_BINDING_GRAPH_VALIDATION);
+ }
+
+ @Override
+ Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind() {
+ return diagnosticKind(MODULE_HAS_DIFFERENT_SCOPES_VALIDATION);
+ }
+
+ @Override
+ ValidationType explicitBindingConflictsWithInjectValidationType() {
+ return parseOption(EXPLICIT_BINDING_CONFLICTS_WITH_INJECT);
+ }
+
+ private boolean isEnabled(KeyOnlyOption keyOnlyOption) {
+ return processingEnvironment.getOptions().containsKey(keyOnlyOption.toString());
+ }
+
+ private boolean isEnabled(Feature feature) {
+ return parseOption(feature).equals(ENABLED);
+ }
+
+ private Diagnostic.Kind diagnosticKind(Validation validation) {
+ return parseOption(validation).diagnosticKind().get();
+ }
+
+ @SuppressWarnings("CheckReturnValue")
+ private ProcessingEnvironmentCompilerOptions checkValid() {
+ for (KeyOnlyOption keyOnlyOption : KeyOnlyOption.values()) {
+ isEnabled(keyOnlyOption);
+ }
+ for (Feature feature : Feature.values()) {
+ parseOption(feature);
+ }
+ for (Validation validation : Validation.values()) {
+ parseOption(validation);
+ }
+ noLongerRecognized(EXPERIMENTAL_ANDROID_MODE);
+ noLongerRecognized(FLOATING_BINDS_METHODS);
+ return this;
+ }
+
+ private void noLongerRecognized(CommandLineOption commandLineOption) {
+ if (processingEnvironment.getOptions().containsKey(commandLineOption.toString())) {
+ processingEnvironment
+ .getMessager()
+ .printMessage(
+ Diagnostic.Kind.WARNING, commandLineOption + " is no longer recognized by Dagger");
+ }
+ }
+
+ private interface CommandLineOption {
+ /** The key of the option (appears after "-A"). */
+ @Override
+ String toString();
+
+ /**
+ * Returns all aliases besides {@link #toString()}, such as old names for an option, in order of
+ * precedence.
+ */
+ default ImmutableList<String> aliases() {
+ return ImmutableList.of();
+ }
+
+ /** All the command-line names for this option, in order of precedence. */
+ default Stream<String> allNames() {
+ return concat(Stream.of(toString()), aliases().stream());
+ }
+ }
+
+ /** An option that can be set on the command line. */
+ private interface EnumOption<E extends Enum<E>> extends CommandLineOption {
+ /** The default value for this option. */
+ E defaultValue();
+
+ /** The valid values for this option. */
+ Set<E> validValues();
+ }
+
+ enum KeyOnlyOption implements CommandLineOption {
+ HEADER_COMPILATION {
+ @Override
+ public String toString() {
+ return "experimental_turbine_hjar";
+ }
+ },
+
+ USE_GRADLE_INCREMENTAL_PROCESSING {
+ @Override
+ public String toString() {
+ return "dagger.gradle.incremental";
+ }
+ },
+ }
+
+ /**
+ * A feature that can be enabled or disabled on the command line by setting {@code -Akey=ENABLED}
+ * or {@code -Akey=DISABLED}.
+ */
+ enum Feature implements EnumOption<FeatureStatus> {
+ FAST_INIT,
+
+ EXPERIMENTAL_ANDROID_MODE,
+
+ FORMAT_GENERATED_SOURCE,
+
+ WRITE_PRODUCER_NAME_IN_TOKEN,
+
+ WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM,
+
+ IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT,
+
+ EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS,
+
+ FORCE_USE_SERIALIZED_COMPONENT_IMPLEMENTATIONS,
+
+ EMIT_MODIFIABLE_METADATA_ANNOTATIONS(ENABLED),
+
+ FLOATING_BINDS_METHODS,
+ ;
+
+ final FeatureStatus defaultValue;
+
+ Feature() {
+ this(DISABLED);
+ }
+
+ Feature(FeatureStatus defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public FeatureStatus defaultValue() {
+ return defaultValue;
+ }
+
+ @Override
+ public Set<FeatureStatus> validValues() {
+ return EnumSet.allOf(FeatureStatus.class);
+ }
+
+ @Override
+ public String toString() {
+ return optionName(this);
+ }
+ }
+
+ /** The diagnostic kind or validation type for a kind of validation. */
+ enum Validation implements EnumOption<ValidationType> {
+ DISABLE_INTER_COMPONENT_SCOPE_VALIDATION(),
+
+ NULLABLE_VALIDATION(ERROR, WARNING),
+
+ PRIVATE_MEMBER_VALIDATION(ERROR, WARNING),
+
+ STATIC_MEMBER_VALIDATION(ERROR, WARNING),
+
+ /** Whether to validate full binding graphs for components, subcomponents, and modules. */
+ FULL_BINDING_GRAPH_VALIDATION(NONE, ERROR, WARNING) {
+ @Override
+ public ImmutableList<String> aliases() {
+ return ImmutableList.of("dagger.moduleBindingValidation");
+ }
+ },
+
+ /**
+ * How to report conflicting scoped bindings when validating partial binding graphs associated
+ * with modules.
+ */
+ MODULE_HAS_DIFFERENT_SCOPES_VALIDATION(ERROR, WARNING),
+
+ /**
+ * How to report that an explicit binding in a subcomponent conflicts with an {@code @Inject}
+ * constructor used in an ancestor component.
+ */
+ EXPLICIT_BINDING_CONFLICTS_WITH_INJECT(WARNING, ERROR, NONE),
+ ;
+
+ final ValidationType defaultType;
+ final ImmutableSet<ValidationType> validTypes;
+
+ Validation() {
+ this(ERROR, WARNING, NONE);
+ }
+
+ Validation(ValidationType defaultType, ValidationType... moreValidTypes) {
+ this.defaultType = defaultType;
+ this.validTypes = immutableEnumSet(defaultType, moreValidTypes);
+ }
+
+ @Override
+ public ValidationType defaultValue() {
+ return defaultType;
+ }
+
+ @Override
+ public Set<ValidationType> validValues() {
+ return validTypes;
+ }
+
+ @Override
+ public String toString() {
+ return optionName(this);
+ }
+ }
+
+ private static String optionName(Enum<? extends EnumOption<?>> option) {
+ return "dagger." + UPPER_UNDERSCORE.to(LOWER_CAMEL, option.name());
+ }
+
+ /** The supported command-line options. */
+ static ImmutableSet<String> supportedOptions() {
+ // need explicit type parameter to avoid a runtime stream error
+ return Stream.<CommandLineOption[]>of(
+ KeyOnlyOption.values(), Feature.values(), Validation.values())
+ .flatMap(Arrays::stream)
+ .flatMap(CommandLineOption::allNames)
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * Returns the value for the option as set on the command line by any name, or the default value
+ * if not set.
+ *
+ * <p>If more than one name is used to set the value, but all names specify the same value,
+ * reports a warning and returns that value.
+ *
+ * <p>If more than one name is used to set the value, and not all names specify the same value,
+ * reports an error and returns the default value.
+ */
+ private <T extends Enum<T>> T parseOption(EnumOption<T> option) {
+ @SuppressWarnings("unchecked") // we only put covariant values into the map
+ T value = (T) enumOptions.computeIfAbsent(option, this::parseOptionUncached);
+ return value;
+ }
+
+ private <T extends Enum<T>> T parseOptionUncached(EnumOption<T> option) {
+ ImmutableMap<String, T> values = parseOptionWithAllNames(option);
+
+ // If no value is specified, return the default value.
+ if (values.isEmpty()) {
+ return option.defaultValue();
+ }
+
+ // If all names have the same value, return that.
+ if (values.asMultimap().inverse().keySet().size() == 1) {
+ // Warn if an option was set with more than one name. That would be an error if the values
+ // differed.
+ if (values.size() > 1) {
+ reportUseOfDifferentNamesForOption(Diagnostic.Kind.WARNING, option, values.keySet());
+ }
+ return values.values().asList().get(0);
+ }
+
+ // If different names have different values, report an error and return the default
+ // value.
+ reportUseOfDifferentNamesForOption(Diagnostic.Kind.ERROR, option, values.keySet());
+ return option.defaultValue();
+ }
+
+ private void reportUseOfDifferentNamesForOption(
+ Diagnostic.Kind diagnosticKind, EnumOption<?> option, ImmutableSet<String> usedNames) {
+ processingEnvironment
+ .getMessager()
+ .printMessage(
+ diagnosticKind,
+ String.format(
+ "Only one of the equivalent options (%s) should be used; prefer -A%s",
+ usedNames.stream().map(name -> "-A" + name).collect(joining(", ")), option));
+ }
+
+ private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNames(
+ EnumOption<T> option) {
+ @SuppressWarnings("unchecked") // map is covariant
+ ImmutableMap<String, T> aliasValues =
+ (ImmutableMap<String, T>)
+ allCommandLineOptions.computeIfAbsent(option, this::parseOptionWithAllNamesUncached);
+ return aliasValues;
+ }
+
+ private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNamesUncached(
+ EnumOption<T> option) {
+ ImmutableMap.Builder<String, T> values = ImmutableMap.builder();
+ getUsedNames(option)
+ .forEach(
+ name -> parseOptionWithName(option, name).ifPresent(value -> values.put(name, value)));
+ return values.build();
+ }
+
+ private <T extends Enum<T>> Optional<T> parseOptionWithName(EnumOption<T> option, String key) {
+ checkArgument(processingEnvironment.getOptions().containsKey(key), "key %s not found", key);
+ String stringValue = processingEnvironment.getOptions().get(key);
+ if (stringValue == null) {
+ processingEnvironment
+ .getMessager()
+ .printMessage(Diagnostic.Kind.ERROR, "Processor option -A" + key + " needs a value");
+ } else {
+ try {
+ T value =
+ Enum.valueOf(option.defaultValue().getDeclaringClass(), Ascii.toUpperCase(stringValue));
+ if (option.validValues().contains(value)) {
+ return Optional.of(value);
+ }
+ } catch (IllegalArgumentException e) {
+ // handled below
+ }
+ processingEnvironment
+ .getMessager()
+ .printMessage(
+ Diagnostic.Kind.ERROR,
+ String.format(
+ "Processor option -A%s may only have the values %s "
+ + "(case insensitive), found: %s",
+ key, option.validValues(), stringValue));
+ }
+ return Optional.empty();
+ }
+
+ private Stream<String> getUsedNames(CommandLineOption option) {
+ return option.allNames().filter(name -> processingEnvironment.getOptions().containsKey(name));
+ }
+}
diff --git a/java/dagger/internal/codegen/ProcessingEnvironmentModule.java b/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
index 8a535fe..1730574 100644
--- a/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
+++ b/java/dagger/internal/codegen/ProcessingEnvironmentModule.java
@@ -16,18 +16,15 @@
package dagger.internal.codegen;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.googlejavaformat.java.filer.FormattingFiler;
-import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.Reusable;
-import dagger.internal.codegen.SpiModule.ProcessorClassLoader;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions;
-import dagger.internal.codegen.compileroption.ProcessingOptions;
import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.spi.BindingGraphPlugin;
import java.util.Map;
+import java.util.Optional;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
@@ -36,25 +33,27 @@
/** Bindings that depend on the {@link ProcessingEnvironment}. */
@Module
-interface ProcessingEnvironmentModule {
- @Binds
- @Reusable // to avoid parsing options more than once
- CompilerOptions bindCompilerOptions(
- ProcessingEnvironmentCompilerOptions processingEnvironmentCompilerOptions);
+final class ProcessingEnvironmentModule {
+
+ private final ProcessingEnvironment processingEnvironment;
+
+ ProcessingEnvironmentModule(ProcessingEnvironment processingEnvironment) {
+ this.processingEnvironment = checkNotNull(processingEnvironment);
+ }
@Provides
@ProcessingOptions
- static Map<String, String> processingOptions(ProcessingEnvironment processingEnvironment) {
+ Map<String, String> processingOptions() {
return processingEnvironment.getOptions();
}
@Provides
- static Messager messager(ProcessingEnvironment processingEnvironment) {
+ Messager messager() {
return processingEnvironment.getMessager();
}
@Provides
- static Filer filer(CompilerOptions compilerOptions, ProcessingEnvironment processingEnvironment) {
+ Filer filer(CompilerOptions compilerOptions) {
if (compilerOptions.headerCompilation() || !compilerOptions.formatGeneratedSource()) {
return processingEnvironment.getFiler();
} else {
@@ -63,23 +62,28 @@
}
@Provides
- static Types types(ProcessingEnvironment processingEnvironment) {
+ Types types() {
return processingEnvironment.getTypeUtils();
}
@Provides
- static SourceVersion sourceVersion(ProcessingEnvironment processingEnvironment) {
+ SourceVersion sourceVersion() {
return processingEnvironment.getSourceVersion();
}
@Provides
- static DaggerElements daggerElements(ProcessingEnvironment processingEnvironment) {
+ DaggerElements daggerElements() {
return new DaggerElements(processingEnvironment);
}
@Provides
- @ProcessorClassLoader
- static ClassLoader processorClassloader(ProcessingEnvironment processingEnvironment) {
- return BindingGraphPlugin.class.getClassLoader();
+ @Reusable // to avoid parsing options more than once
+ CompilerOptions compilerOptions() {
+ return ProcessingEnvironmentCompilerOptions.create(processingEnvironment);
+ }
+
+ @Provides
+ Optional<DaggerStatisticsRecorder> daggerStatisticsRecorder() {
+ return Optional.empty();
}
}
diff --git a/java/dagger/internal/codegen/ProcessingOptions.java b/java/dagger/internal/codegen/ProcessingOptions.java
new file mode 100644
index 0000000..105452a
--- /dev/null
+++ b/java/dagger/internal/codegen/ProcessingOptions.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+/**
+ * A qualifier for the {@link javax.annotation.processing.ProcessingEnvironment#getOptions()
+ * processing options} passed to the current invocation of {@code javac}.
+ */
+@Retention(RUNTIME)
+@Qualifier
+@interface ProcessingOptions {}
diff --git a/java/dagger/internal/codegen/ProcessingRoundCacheModule.java b/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
index 2373cd2..b56cc30 100644
--- a/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
+++ b/java/dagger/internal/codegen/ProcessingRoundCacheModule.java
@@ -18,14 +18,6 @@
import dagger.Binds;
import dagger.Module;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.binding.BindingGraphFactory;
-import dagger.internal.codegen.binding.ModuleDescriptor;
-import dagger.internal.codegen.kotlin.KotlinMetadataFactory;
-import dagger.internal.codegen.validation.AnyBindingMethodValidator;
-import dagger.internal.codegen.validation.ComponentCreatorValidator;
-import dagger.internal.codegen.validation.ComponentValidator;
-import dagger.internal.codegen.validation.InjectValidator;
import dagger.multibindings.IntoSet;
/**
@@ -36,14 +28,6 @@
interface ProcessingRoundCacheModule {
@Binds
@IntoSet
- ClearableCache anyBindingMethodValidator(AnyBindingMethodValidator cache);
-
- @Binds
- @IntoSet
- ClearableCache injectValidator(InjectValidator cache);
-
- @Binds
- @IntoSet
ClearableCache moduleDescriptorFactory(ModuleDescriptor.Factory cache);
@Binds
@@ -52,13 +36,5 @@
@Binds
@IntoSet
- ClearableCache componentValidator(ComponentValidator cache);
-
- @Binds
- @IntoSet
- ClearableCache componentCreatorValidator(ComponentCreatorValidator cache);
-
- @Binds
- @IntoSet
- ClearableCache kotlinMetadata(KotlinMetadataFactory cache);
+ ClearableCache componentImplementationFactory(ComponentImplementationFactory cache);
}
diff --git a/java/dagger/internal/codegen/ProducerCreationExpression.java b/java/dagger/internal/codegen/ProducerCreationExpression.java
new file mode 100644
index 0000000..1dd7a1c
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerCreationExpression.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+
+/**
+ * A {@link dagger.producers.Producer} creation expression for a {@link
+ * dagger.producers.Produces @Produces}-annotated module method.
+ */
+// TODO(dpb): Resolve with InjectionOrProvisionProviderCreationExpression.
+final class ProducerCreationExpression implements FrameworkInstanceCreationExpression {
+
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final ContributionBinding binding;
+
+ ProducerCreationExpression(
+ ContributionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ return CodeBlock.of(
+ "$T.create($L)",
+ generatedClassNameForBinding(binding),
+ componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
+ }
+}
diff --git a/java/dagger/internal/codegen/ProducerEntryPointView.java b/java/dagger/internal/codegen/ProducerEntryPointView.java
new file mode 100644
index 0000000..87b5a4a
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerEntryPointView.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.ComponentImplementation.FieldSpecKind.FRAMEWORK_FIELD;
+import static javax.lang.model.element.Modifier.PRIVATE;
+
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.RequestKind;
+import dagger.producers.Producer;
+import dagger.producers.internal.CancellationListener;
+import dagger.producers.internal.Producers;
+import java.util.Optional;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A factory of {@linkplain Producers#entryPointViewOf(Producer, CancellationListener) entry point
+ * views} of {@link Producer}s.
+ */
+final class ProducerEntryPointView {
+ private final DaggerTypes types;
+
+ ProducerEntryPointView(DaggerTypes types) {
+ this.types = types;
+ }
+
+ /**
+ * Returns an expression for an {@linkplain Producers#entryPointViewOf(Producer,
+ * CancellationListener) entry point view} of a producer if the component method returns a {@link
+ * Producer} or {@link com.google.common.util.concurrent.ListenableFuture}.
+ *
+ * <p>This is intended to be a replacement implementation for {@link
+ * BindingExpression#getDependencyExpressionForComponentMethod(ComponentMethodDescriptor,
+ * ComponentImplementation)}, and in cases where {@link Optional#empty()} is returned, callers
+ * should call {@code super.getDependencyExpressionForComponentMethod()}.
+ */
+ Optional<Expression> getProducerEntryPointField(
+ BindingExpression producerExpression,
+ ComponentMethodDescriptor componentMethod,
+ ComponentImplementation component) {
+ if (component.componentDescriptor().isProduction()
+ && (componentMethod.dependencyRequest().get().kind().equals(RequestKind.FUTURE)
+ || componentMethod.dependencyRequest().get().kind().equals(RequestKind.PRODUCER))) {
+ return Optional.of(
+ Expression.create(
+ fieldType(componentMethod),
+ "$N",
+ createField(producerExpression, componentMethod, component)));
+ } else {
+ // If the component isn't a production component, it won't implement CancellationListener and
+ // as such we can't create an entry point. But this binding must also just be a Producer from
+ // Provider anyway in that case, so there shouldn't be an issue.
+ // TODO(b/116855531): Is it really intended that a non-production component can have Producer
+ // entry points?
+ return Optional.empty();
+ }
+ }
+
+ private FieldSpec createField(
+ BindingExpression producerExpression,
+ ComponentMethodDescriptor componentMethod,
+ ComponentImplementation component) {
+ // TODO(cgdecker): Use a FrameworkFieldInitializer for this?
+ // Though I don't think we need the once-only behavior of that, since I think
+ // getComponentMethodImplementation will only be called once anyway
+ String methodName = componentMethod.methodElement().getSimpleName().toString();
+ FieldSpec field =
+ FieldSpec.builder(
+ TypeName.get(fieldType(componentMethod)),
+ component.getUniqueFieldName(methodName + "EntryPoint"),
+ PRIVATE)
+ .build();
+ component.addField(FRAMEWORK_FIELD, field);
+
+ CodeBlock fieldInitialization =
+ CodeBlock.of(
+ "this.$N = $T.entryPointViewOf($L, this);",
+ field,
+ Producers.class,
+ producerExpression.getDependencyExpression(component.name()).codeBlock());
+ component.addInitialization(fieldInitialization);
+
+ return field;
+ }
+
+ // TODO(cgdecker): Can we use producerExpression.getDependencyExpression().type() instead of
+ // needing to (re)compute this?
+ private TypeMirror fieldType(ComponentMethodDescriptor componentMethod) {
+ return types.wrapType(componentMethod.dependencyRequest().get().key().type(), Producer.class);
+ }
+}
diff --git a/java/dagger/internal/codegen/ProducerFactoryGenerator.java b/java/dagger/internal/codegen/ProducerFactoryGenerator.java
new file mode 100644
index 0000000..3f2bef4
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerFactoryGenerator.java
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verifyNotNull;
+import static com.squareup.javapoet.ClassName.OBJECT;
+import static com.squareup.javapoet.MethodSpec.constructorBuilder;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.GwtCompatibility.gwtIncompatibleAnnotation;
+import static dagger.internal.codegen.SourceFiles.bindingTypeElementTypeVariableNames;
+import static dagger.internal.codegen.SourceFiles.generateBindingFieldsForDependencies;
+import static dagger.internal.codegen.SourceFiles.generatedClassNameForBinding;
+import static dagger.internal.codegen.SourceFiles.parameterizedGeneratedTypeNameForBinding;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.FUTURES;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
+import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_TOKEN;
+import static dagger.internal.codegen.javapoet.TypeNames.VOID_CLASS;
+import static dagger.internal.codegen.javapoet.TypeNames.listOf;
+import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
+import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
+import static java.util.stream.Collectors.joining;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.javapoet.AnnotationSpecs;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import dagger.producers.Producer;
+import dagger.producers.internal.AbstractProducesMethodProducer;
+import dagger.producers.internal.Producers;
+import java.util.Map;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Generates {@link Producer} implementations from {@link ProductionBinding} instances.
+ */
+final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> {
+ private final CompilerOptions compilerOptions;
+ private final KeyFactory keyFactory;
+
+ @Inject
+ ProducerFactoryGenerator(
+ Filer filer,
+ DaggerElements elements,
+ SourceVersion sourceVersion,
+ CompilerOptions compilerOptions,
+ KeyFactory keyFactory) {
+ super(filer, elements, sourceVersion);
+ this.compilerOptions = compilerOptions;
+ this.keyFactory = keyFactory;
+ }
+
+ @Override
+ ClassName nameGeneratedType(ProductionBinding binding) {
+ return generatedClassNameForBinding(binding);
+ }
+
+ @Override
+ Element originatingElement(ProductionBinding binding) {
+ // we only create factories for bindings that have a binding element
+ return binding.bindingElement().get();
+ }
+
+ @Override
+ Optional<TypeSpec.Builder> write(ClassName generatedTypeName, ProductionBinding binding) {
+ // We don't want to write out resolved bindings -- we want to write out the generic version.
+ checkArgument(!binding.unresolved().isPresent());
+ checkArgument(binding.bindingElement().isPresent());
+
+ TypeName providedTypeName = TypeName.get(binding.contributedType());
+ TypeName futureTypeName = listenableFutureOf(providedTypeName);
+
+ TypeSpec.Builder factoryBuilder =
+ classBuilder(generatedTypeName)
+ .addAnnotation(
+ // TODO(beder): examine if we can remove this or prevent subtypes of Future from
+ // being produced
+ AnnotationSpec.builder(SuppressWarnings.class)
+ .addMember("value", "$S", "FutureReturnValueIgnored")
+ .build())
+ .addModifiers(PUBLIC, FINAL)
+ .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
+
+ UniqueNameSet uniqueFieldNames = new UniqueNameSet();
+ ImmutableMap.Builder<Key, FieldSpec> fieldsBuilder = ImmutableMap.builder();
+
+ MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PRIVATE);
+
+ Optional<FieldSpec> moduleField =
+ binding.requiresModuleInstance()
+ ? Optional.of(
+ addFieldAndConstructorParameter(
+ factoryBuilder,
+ constructorBuilder,
+ uniqueFieldNames.getUniqueName("module"),
+ TypeName.get(binding.bindingTypeElement().get().asType())))
+ : Optional.empty();
+
+ String[] executorParameterName = new String[1];
+ String[] monitorParameterName = new String[1];
+ Map<Key, FrameworkField> bindingFieldsForDependencies =
+ generateBindingFieldsForDependencies(binding);
+ bindingFieldsForDependencies.forEach(
+ (key, bindingField) -> {
+ String fieldName = uniqueFieldNames.getUniqueName(bindingField.name());
+ if (key.equals(keyFactory.forProductionImplementationExecutor())) {
+ executorParameterName[0] = fieldName;
+ constructorBuilder.addParameter(bindingField.type(), executorParameterName[0]);
+ } else if (key.equals(keyFactory.forProductionComponentMonitor())) {
+ monitorParameterName[0] = fieldName;
+ constructorBuilder.addParameter(bindingField.type(), monitorParameterName[0]);
+ } else {
+ FieldSpec field =
+ addFieldAndConstructorParameter(
+ factoryBuilder, constructorBuilder, fieldName, bindingField.type());
+ fieldsBuilder.put(key, field);
+ }
+ });
+ ImmutableMap<Key, FieldSpec> fields = fieldsBuilder.build();
+
+ constructorBuilder.addStatement(
+ "super($N, $L, $N)",
+ verifyNotNull(monitorParameterName[0]),
+ producerTokenConstruction(generatedTypeName, binding),
+ verifyNotNull(executorParameterName[0]));
+
+ if (binding.requiresModuleInstance()) {
+ assignField(constructorBuilder, moduleField.get(), null);
+ }
+
+ fields.forEach(
+ (key, field) -> {
+ ParameterizedTypeName type = bindingFieldsForDependencies.get(key).type();
+ assignField(constructorBuilder, field, type);
+ });
+
+ MethodSpec.Builder collectDependenciesBuilder =
+ methodBuilder("collectDependencies")
+ .addAnnotation(Override.class)
+ .addModifiers(PROTECTED);
+
+ ImmutableList<DependencyRequest> asyncDependencies = asyncDependencies(binding);
+ for (DependencyRequest dependency : asyncDependencies) {
+ TypeName futureType = listenableFutureOf(asyncDependencyType(dependency));
+ CodeBlock futureAccess = CodeBlock.of("$N.get()", fields.get(dependency.key()));
+ collectDependenciesBuilder.addStatement(
+ "$T $L = $L",
+ futureType,
+ dependencyFutureName(dependency),
+ dependency.kind().equals(RequestKind.PRODUCED)
+ ? CodeBlock.of("$T.createFutureProduced($L)", PRODUCERS, futureAccess)
+ : futureAccess);
+ }
+ FutureTransform futureTransform = FutureTransform.create(fields, binding, asyncDependencies);
+
+ collectDependenciesBuilder
+ .returns(listenableFutureOf(futureTransform.applyArgType()))
+ .addStatement("return $L", futureTransform.futureCodeBlock());
+
+ MethodSpec.Builder callProducesMethod =
+ methodBuilder("callProducesMethod")
+ .returns(futureTypeName)
+ .addAnnotation(Override.class)
+ .addModifiers(PUBLIC)
+ .addParameter(futureTransform.applyArgType(), futureTransform.applyArgName())
+ .addExceptions(getThrownTypeNames(binding.thrownTypes()))
+ .addCode(
+ getInvocationCodeBlock(
+ binding, providedTypeName, futureTransform.parameterCodeBlocks()));
+ if (futureTransform.hasUncheckedCast()) {
+ callProducesMethod.addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED));
+ }
+
+ MethodSpec constructor = constructorBuilder.build();
+ factoryBuilder
+ .superclass(
+ ParameterizedTypeName.get(
+ ClassName.get(AbstractProducesMethodProducer.class),
+ futureTransform.applyArgType(),
+ providedTypeName))
+ .addMethod(constructor)
+ .addMethod(staticFactoryMethod(binding, constructor))
+ .addMethod(collectDependenciesBuilder.build())
+ .addMethod(callProducesMethod.build());
+
+ gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
+
+ // TODO(gak): write a sensible toString
+ return Optional.of(factoryBuilder);
+ }
+
+ private MethodSpec staticFactoryMethod(ProductionBinding binding, MethodSpec constructor) {
+ return MethodSpec.methodBuilder("create")
+ .addModifiers(PUBLIC, STATIC)
+ .returns(parameterizedGeneratedTypeNameForBinding(binding))
+ .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
+ .addParameters(constructor.parameters)
+ .addStatement(
+ "return new $T($L)",
+ parameterizedGeneratedTypeNameForBinding(binding),
+ constructor.parameters.stream()
+ .map(p -> CodeBlock.of("$N", p.name))
+ .collect(toParametersCodeBlock()))
+ .build();
+ }
+
+ // TODO(ronshapiro): consolidate versions of these
+ private static FieldSpec addFieldAndConstructorParameter(
+ TypeSpec.Builder typeBuilder,
+ MethodSpec.Builder constructorBuilder,
+ String variableName,
+ TypeName variableType) {
+ FieldSpec field = FieldSpec.builder(variableType, variableName, PRIVATE, FINAL).build();
+ typeBuilder.addField(field);
+ constructorBuilder.addParameter(field.type, field.name);
+ return field;
+ }
+
+ private static void assignField(
+ MethodSpec.Builder constructorBuilder, FieldSpec field, ParameterizedTypeName type) {
+ if (type != null && type.rawType.equals(TypeNames.PRODUCER)) {
+ constructorBuilder.addStatement(
+ "this.$1N = $2T.nonCancellationPropagatingViewOf($1N)", field, Producers.class);
+ } else {
+ constructorBuilder.addStatement("this.$1N = $1N", field);
+ }
+ }
+
+ /** Returns a list of dependencies that are generated asynchronously. */
+ private static ImmutableList<DependencyRequest> asyncDependencies(Binding binding) {
+ final ImmutableMap<DependencyRequest, FrameworkDependency> frameworkDependencies =
+ binding.dependenciesToFrameworkDependenciesMap();
+ return FluentIterable.from(binding.dependencies())
+ .filter(
+ dependency ->
+ isAsyncDependency(dependency)
+ && frameworkDependencies
+ .get(dependency)
+ .frameworkClass()
+ .equals(Producer.class))
+ .toList();
+ }
+
+ private CodeBlock producerTokenConstruction(
+ ClassName generatedTypeName, ProductionBinding binding) {
+ CodeBlock producerTokenArgs =
+ compilerOptions.writeProducerNameInToken()
+ ? CodeBlock.of(
+ "$S",
+ String.format(
+ "%s#%s",
+ ClassName.get(binding.bindingTypeElement().get()),
+ binding.bindingElement().get().getSimpleName()))
+ : CodeBlock.of("$T.class", generatedTypeName);
+ return CodeBlock.of("$T.create($L)", PRODUCER_TOKEN, producerTokenArgs);
+ }
+
+ /** Returns a name of the variable representing this dependency's future. */
+ private static String dependencyFutureName(DependencyRequest dependency) {
+ return dependency.requestElement().get().getSimpleName() + "Future";
+ }
+
+ /** Represents the transformation of an input future by a producer method. */
+ abstract static class FutureTransform {
+ protected final ImmutableMap<Key, FieldSpec> fields;
+ protected final ProductionBinding binding;
+
+ FutureTransform(ImmutableMap<Key, FieldSpec> fields, ProductionBinding binding) {
+ this.fields = fields;
+ this.binding = binding;
+ }
+
+ /** The code block representing the future that should be transformed. */
+ abstract CodeBlock futureCodeBlock();
+
+ /** The type of the argument to the apply method. */
+ abstract TypeName applyArgType();
+
+ /** The name of the argument to the apply method */
+ abstract String applyArgName();
+
+ /** The code blocks to be passed to the produces method itself. */
+ abstract ImmutableList<CodeBlock> parameterCodeBlocks();
+
+ /** Whether the transform method has an unchecked cast. */
+ boolean hasUncheckedCast() {
+ return false;
+ }
+
+ CodeBlock frameworkTypeUsageStatement(DependencyRequest dependency) {
+ return SourceFiles.frameworkTypeUsageStatement(
+ CodeBlock.of("$N", fields.get(dependency.key())), dependency.kind());
+ }
+
+ static FutureTransform create(
+ ImmutableMap<Key, FieldSpec> fields,
+ ProductionBinding binding,
+ ImmutableList<DependencyRequest> asyncDependencies) {
+ if (asyncDependencies.isEmpty()) {
+ return new NoArgFutureTransform(fields, binding);
+ } else if (asyncDependencies.size() == 1) {
+ return new SingleArgFutureTransform(
+ fields, binding, Iterables.getOnlyElement(asyncDependencies));
+ } else {
+ return new MultiArgFutureTransform(fields, binding, asyncDependencies);
+ }
+ }
+ }
+
+ static final class NoArgFutureTransform extends FutureTransform {
+ NoArgFutureTransform(ImmutableMap<Key, FieldSpec> fields, ProductionBinding binding) {
+ super(fields, binding);
+ }
+
+ @Override
+ CodeBlock futureCodeBlock() {
+ return CodeBlock.of("$T.<$T>immediateFuture(null)", FUTURES, VOID_CLASS);
+ }
+
+ @Override
+ TypeName applyArgType() {
+ return VOID_CLASS;
+ }
+
+ @Override
+ String applyArgName() {
+ return "ignoredVoidArg";
+ }
+
+ @Override
+ ImmutableList<CodeBlock> parameterCodeBlocks() {
+ return binding.explicitDependencies().stream()
+ .map(this::frameworkTypeUsageStatement)
+ .collect(toImmutableList());
+ }
+ }
+
+ static final class SingleArgFutureTransform extends FutureTransform {
+ private final DependencyRequest asyncDependency;
+
+ SingleArgFutureTransform(
+ ImmutableMap<Key, FieldSpec> fields,
+ ProductionBinding binding,
+ DependencyRequest asyncDependency) {
+ super(fields, binding);
+ this.asyncDependency = asyncDependency;
+ }
+
+ @Override
+ CodeBlock futureCodeBlock() {
+ return CodeBlock.of("$L", dependencyFutureName(asyncDependency));
+ }
+
+ @Override
+ TypeName applyArgType() {
+ return asyncDependencyType(asyncDependency);
+ }
+
+ @Override
+ String applyArgName() {
+ String argName = asyncDependency.requestElement().get().getSimpleName().toString();
+ if (argName.equals("module")) {
+ return "moduleArg";
+ }
+ return argName;
+ }
+
+ @Override
+ ImmutableList<CodeBlock> parameterCodeBlocks() {
+ ImmutableList.Builder<CodeBlock> parameterCodeBlocks = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.explicitDependencies()) {
+ // We really want to compare instances here, because asyncDependency is an element in the
+ // set binding.dependencies().
+ if (dependency == asyncDependency) {
+ parameterCodeBlocks.add(CodeBlock.of("$L", applyArgName()));
+ } else {
+ parameterCodeBlocks.add(frameworkTypeUsageStatement(dependency));
+ }
+ }
+ return parameterCodeBlocks.build();
+ }
+ }
+
+ static final class MultiArgFutureTransform extends FutureTransform {
+ private final ImmutableList<DependencyRequest> asyncDependencies;
+
+ MultiArgFutureTransform(
+ ImmutableMap<Key, FieldSpec> fields,
+ ProductionBinding binding,
+ ImmutableList<DependencyRequest> asyncDependencies) {
+ super(fields, binding);
+ this.asyncDependencies = asyncDependencies;
+ }
+
+ @Override
+ CodeBlock futureCodeBlock() {
+ return CodeBlock.of(
+ "$T.<$T>allAsList($L)",
+ FUTURES,
+ OBJECT,
+ asyncDependencies
+ .stream()
+ .map(ProducerFactoryGenerator::dependencyFutureName)
+ .collect(joining(", ")));
+ }
+
+ @Override
+ TypeName applyArgType() {
+ return listOf(OBJECT);
+ }
+
+ @Override
+ String applyArgName() {
+ return "args";
+ }
+
+ @Override
+ ImmutableList<CodeBlock> parameterCodeBlocks() {
+ int argIndex = 0;
+ ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
+ for (DependencyRequest dependency : binding.explicitDependencies()) {
+ if (isAsyncDependency(dependency)) {
+ codeBlocks.add(
+ CodeBlock.of(
+ "($T) $L.get($L)", asyncDependencyType(dependency), applyArgName(), argIndex));
+ argIndex++;
+ } else {
+ codeBlocks.add(frameworkTypeUsageStatement(dependency));
+ }
+ }
+ return codeBlocks.build();
+ }
+
+ @Override
+ boolean hasUncheckedCast() {
+ return true;
+ }
+ }
+
+ private static boolean isAsyncDependency(DependencyRequest dependency) {
+ switch (dependency.kind()) {
+ case INSTANCE:
+ case PRODUCED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static TypeName asyncDependencyType(DependencyRequest dependency) {
+ TypeName keyName = TypeName.get(dependency.key().type());
+ switch (dependency.kind()) {
+ case INSTANCE:
+ return keyName;
+ case PRODUCED:
+ return producedOf(keyName);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Creates a code block for the invocation of the producer method from the module, which should be
+ * used entirely within a method body.
+ *
+ * @param binding The binding to generate the invocation code block for.
+ * @param providedTypeName The type name that should be provided by this producer.
+ * @param parameterCodeBlocks The code blocks for all the parameters to the producer method.
+ */
+ private CodeBlock getInvocationCodeBlock(
+ ProductionBinding binding,
+ TypeName providedTypeName,
+ ImmutableList<CodeBlock> parameterCodeBlocks) {
+ CodeBlock moduleCodeBlock =
+ CodeBlock.of(
+ "$L.$L($L)",
+ binding.requiresModuleInstance()
+ ? "module"
+ : CodeBlock.of("$T", ClassName.get(binding.bindingTypeElement().get())),
+ binding.bindingElement().get().getSimpleName(),
+ makeParametersCodeBlock(parameterCodeBlocks));
+
+ final CodeBlock returnCodeBlock;
+ switch (binding.productionKind().get()) {
+ case IMMEDIATE:
+ returnCodeBlock =
+ CodeBlock.of("$T.<$T>immediateFuture($L)", FUTURES, providedTypeName, moduleCodeBlock);
+ break;
+ case FUTURE:
+ returnCodeBlock = moduleCodeBlock;
+ break;
+ case SET_OF_FUTURE:
+ returnCodeBlock = CodeBlock.of("$T.allAsSet($L)", PRODUCERS, moduleCodeBlock);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return CodeBlock.of("return $L;", returnCodeBlock);
+ }
+
+ /**
+ * Converts the list of thrown types into type names.
+ *
+ * @param thrownTypes the list of thrown types.
+ */
+ private FluentIterable<? extends TypeName> getThrownTypeNames(
+ Iterable<? extends TypeMirror> thrownTypes) {
+ return FluentIterable.from(thrownTypes).transform(TypeName::get);
+ }
+}
diff --git a/java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java b/java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java
new file mode 100644
index 0000000..aca9756
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerFromProviderCreationExpression.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
+import dagger.internal.codegen.javapoet.TypeNames;
+import dagger.model.RequestKind;
+import dagger.producers.Producer;
+import java.util.Optional;
+
+/** An {@link Producer} creation expression for provision bindings. */
+final class ProducerFromProviderCreationExpression implements FrameworkInstanceCreationExpression {
+ private final ContributionBinding binding;
+ private final ComponentImplementation componentImplementation;
+ private final ComponentBindingExpressions componentBindingExpressions;
+
+ ProducerFromProviderCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions) {
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ return FrameworkType.PROVIDER.to(
+ RequestKind.PRODUCER,
+ componentBindingExpressions
+ .getDependencyExpression(
+ bindingRequest(binding.key(), FrameworkType.PROVIDER),
+ componentImplementation.name())
+ .codeBlock());
+ }
+
+ @Override
+ public Optional<ClassName> alternativeFrameworkClass() {
+ return Optional.of(TypeNames.PRODUCER);
+ }
+
+ // TODO(ronshapiro): should this have a simple factory if the delegate expression is simple?
+}
diff --git a/java/dagger/internal/codegen/ProducerNodeInstanceBindingExpression.java b/java/dagger/internal/codegen/ProducerNodeInstanceBindingExpression.java
new file mode 100644
index 0000000..18818d5
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducerNodeInstanceBindingExpression.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+
+/** Binding expression for producer node instances. */
+final class ProducerNodeInstanceBindingExpression extends FrameworkInstanceBindingExpression {
+ /** The component defining this binding. */
+ private final ComponentImplementation componentImplementation;
+ private final Key key;
+ private final ProducerEntryPointView producerEntryPointView;
+
+ ProducerNodeInstanceBindingExpression(
+ ResolvedBindings resolvedBindings,
+ FrameworkInstanceSupplier frameworkInstanceSupplier,
+ DaggerTypes types,
+ DaggerElements elements,
+ ComponentImplementation componentImplementation) {
+ super(resolvedBindings, frameworkInstanceSupplier, types, elements);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.key = resolvedBindings.key();
+ this.producerEntryPointView = new ProducerEntryPointView(types);
+ }
+
+ @Override
+ protected FrameworkType frameworkType() {
+ return FrameworkType.PRODUCER_NODE;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ Expression result = super.getDependencyExpression(requestingClass);
+ componentImplementation.addCancellableProducerKey(key);
+ return result;
+ }
+
+ @Override
+ Expression getDependencyExpressionForComponentMethod(
+ ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
+ return producerEntryPointView
+ .getProducerEntryPointField(this, componentMethod, component)
+ .orElseGet(
+ () -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
+ }
+}
diff --git a/java/dagger/internal/codegen/ProducesMethodValidator.java b/java/dagger/internal/codegen/ProducesMethodValidator.java
new file mode 100644
index 0000000..bf45948
--- /dev/null
+++ b/java/dagger/internal/codegen/ProducesMethodValidator.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2014 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
+import static dagger.internal.codegen.BindingElementValidator.AllowsScoping.NO_SCOPING;
+import static dagger.internal.codegen.BindingMethodValidator.Abstractness.MUST_BE_CONCRETE;
+import static dagger.internal.codegen.BindingMethodValidator.ExceptionSuperclass.EXCEPTION;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.multibindings.ElementsIntoSet;
+import dagger.producers.ProducerModule;
+import dagger.producers.Produces;
+import java.util.Optional;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/** A validator for {@link Produces} methods. */
+final class ProducesMethodValidator extends BindingMethodValidator {
+
+ @Inject
+ ProducesMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestValidator dependencyRequestValidator) {
+ super(
+ elements,
+ types,
+ dependencyRequestValidator,
+ Produces.class,
+ ProducerModule.class,
+ MUST_BE_CONCRETE,
+ EXCEPTION,
+ ALLOWS_MULTIBINDINGS,
+ NO_SCOPING);
+ }
+
+ @Override
+ protected String elementsIntoSetNotASetMessage() {
+ return "@Produces methods of type set values must return a Set or ListenableFuture of Set";
+ }
+
+ @Override
+ protected String badTypeMessage() {
+ return "@Produces methods can return only a primitive, an array, a type variable, "
+ + "a declared type, or a ListenableFuture of one of those types";
+ }
+
+ @Override
+ protected ElementValidator elementValidator(ExecutableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends MethodValidator {
+ Validator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkAdditionalMethodProperties() {
+ checkNullable();
+ }
+
+ /** Adds a warning if a {@link Produces @Produces} method is declared nullable. */
+ // TODO(beder): Properly handle nullable with producer methods.
+ private void checkNullable() {
+ if (ConfigurationAnnotations.getNullableType(element).isPresent()) {
+ report.addWarning("@Nullable on @Produces methods does not do anything");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Allows {@code keyType} to be a {@link ListenableFuture} of an otherwise-valid key type.
+ */
+ @Override
+ protected void checkKeyType(TypeMirror keyType) {
+ Optional<TypeMirror> typeToCheck = unwrapListenableFuture(keyType);
+ if (typeToCheck.isPresent()) {
+ super.checkKeyType(typeToCheck.get());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Allows an {@link ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} method to return
+ * a {@link ListenableFuture} of a {@link Set} as well.
+ */
+ @Override
+ protected void checkSetValuesType() {
+ Optional<TypeMirror> typeToCheck = unwrapListenableFuture(element.getReturnType());
+ if (typeToCheck.isPresent()) {
+ checkSetValuesType(typeToCheck.get());
+ }
+ }
+
+ private Optional<TypeMirror> unwrapListenableFuture(TypeMirror type) {
+ if (MoreTypes.isType(type) && MoreTypes.isTypeOf(ListenableFuture.class, type)) {
+ DeclaredType declaredType = MoreTypes.asDeclared(type);
+ if (declaredType.getTypeArguments().isEmpty()) {
+ report.addError("@Produces methods cannot return a raw ListenableFuture");
+ return Optional.empty();
+ } else {
+ return Optional.of((TypeMirror) getOnlyElement(declaredType.getTypeArguments()));
+ }
+ }
+ return Optional.of(type);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ProductionBinding.java b/java/dagger/internal/codegen/ProductionBinding.java
new file mode 100644
index 0000000..a22f21c
--- /dev/null
+++ b/java/dagger/internal/codegen/ProductionBinding.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
+
+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.ImmutableSet;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import java.util.Optional;
+import java.util.stream.Stream;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A value object representing the mechanism by which a {@link Key} can be produced.
+ */
+@AutoValue
+abstract class ProductionBinding extends ContributionBinding {
+
+ @Override
+ public BindingType bindingType() {
+ return BindingType.PRODUCTION;
+ }
+
+ @Override
+ abstract Optional<ProductionBinding> unresolved();
+
+ @Override
+ ImmutableSet<DependencyRequest> implicitDependencies() {
+ return Stream.of(executorRequest(), monitorRequest())
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(toImmutableSet());
+ }
+
+ /** What kind of object a {@code @Produces}-annotated method returns. */
+ enum ProductionKind {
+ /** A value. */
+ IMMEDIATE,
+ /** A {@code ListenableFuture<T>}. */
+ FUTURE,
+ /** A {@code Set<ListenableFuture<T>>}. */
+ SET_OF_FUTURE;
+
+ /** Returns the kind of object a {@code @Produces}-annotated method returns. */
+ static ProductionKind fromProducesMethod(ExecutableElement producesMethod) {
+ if (isFutureType(producesMethod.getReturnType())) {
+ return FUTURE;
+ } else if (ContributionType.fromBindingElement(producesMethod)
+ .equals(ContributionType.SET_VALUES)
+ && isFutureType(SetType.from(producesMethod.getReturnType()).elementType())) {
+ return SET_OF_FUTURE;
+ } else {
+ return IMMEDIATE;
+ }
+ }
+ }
+
+ /**
+ * Returns the kind of object the produces method returns. All production bindings from
+ * {@code @Produces} methods will have a production kind, but synthetic production bindings may
+ * not.
+ */
+ abstract Optional<ProductionKind> productionKind();
+
+ /** Returns the list of types in the throws clause of the method. */
+ abstract ImmutableList<? extends TypeMirror> thrownTypes();
+
+ /**
+ * If this production requires an executor, this will be the corresponding request. All
+ * production bindings from {@code @Produces} methods will have an executor request, but
+ * synthetic production bindings may not.
+ */
+ abstract Optional<DependencyRequest> executorRequest();
+
+ /** If this production requires a monitor, this will be the corresponding request. All
+ * production bindings from {@code @Produces} methods will have a monitor request, but synthetic
+ * production bindings may not.
+ */
+ abstract Optional<DependencyRequest> monitorRequest();
+
+ // Profiling determined that this method is called enough times that memoizing it had a measurable
+ // performance improvement for large components.
+ @Memoized
+ @Override
+ boolean requiresModuleInstance() {
+ return super.requiresModuleInstance();
+ }
+
+ static Builder builder() {
+ return new AutoValue_ProductionBinding.Builder()
+ .explicitDependencies(ImmutableList.<DependencyRequest>of())
+ .thrownTypes(ImmutableList.<TypeMirror>of());
+ }
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ // TODO(ronshapiro,dpb): simplify the equality semantics
+ @Override
+ public abstract boolean equals(Object obj);
+
+ @AutoValue.Builder
+ @CanIgnoreReturnValue
+ abstract static class Builder extends ContributionBinding.Builder<ProductionBinding, Builder> {
+
+ @Override
+ Builder dependencies(Iterable<DependencyRequest> dependencies) {
+ return explicitDependencies(dependencies);
+ }
+
+ abstract Builder explicitDependencies(Iterable<DependencyRequest> dependencies);
+
+ abstract Builder productionKind(ProductionKind productionKind);
+
+ @Override
+ abstract Builder unresolved(ProductionBinding unresolved);
+
+ abstract Builder thrownTypes(Iterable<? extends TypeMirror> thrownTypes);
+
+ abstract Builder executorRequest(DependencyRequest executorRequest);
+
+ abstract Builder monitorRequest(DependencyRequest monitorRequest);
+ }
+}
diff --git a/java/dagger/internal/codegen/ProviderInstanceBindingExpression.java b/java/dagger/internal/codegen/ProviderInstanceBindingExpression.java
new file mode 100644
index 0000000..60166de
--- /dev/null
+++ b/java/dagger/internal/codegen/ProviderInstanceBindingExpression.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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 dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+
+/** Binding expression for provider instances. */
+final class ProviderInstanceBindingExpression extends FrameworkInstanceBindingExpression {
+
+ ProviderInstanceBindingExpression(
+ ResolvedBindings resolvedBindings,
+ FrameworkInstanceSupplier frameworkInstanceSupplier,
+ DaggerTypes types,
+ DaggerElements elements) {
+ super(
+ resolvedBindings,
+ frameworkInstanceSupplier,
+ types,
+ elements);
+ }
+
+ @Override
+ protected FrameworkType frameworkType() {
+ return FrameworkType.PROVIDER;
+ }
+}
diff --git a/java/dagger/internal/codegen/ProvidesMethodValidator.java b/java/dagger/internal/codegen/ProvidesMethodValidator.java
new file mode 100644
index 0000000..01e71ae
--- /dev/null
+++ b/java/dagger/internal/codegen/ProvidesMethodValidator.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
+import static dagger.internal.codegen.BindingElementValidator.AllowsScoping.ALLOWS_SCOPING;
+import static dagger.internal.codegen.BindingMethodValidator.Abstractness.MUST_BE_CONCRETE;
+import static dagger.internal.codegen.BindingMethodValidator.ExceptionSuperclass.RUNTIME_EXCEPTION;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.Module;
+import dagger.Provides;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.producers.ProducerModule;
+import javax.inject.Inject;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+
+/** A validator for {@link Provides} methods. */
+final class ProvidesMethodValidator extends BindingMethodValidator {
+
+ private final DependencyRequestValidator dependencyRequestValidator;
+
+ @Inject
+ ProvidesMethodValidator(
+ DaggerElements elements,
+ DaggerTypes types,
+ DependencyRequestValidator dependencyRequestValidator) {
+ super(
+ elements,
+ types,
+ Provides.class,
+ ImmutableSet.of(Module.class, ProducerModule.class),
+ dependencyRequestValidator,
+ MUST_BE_CONCRETE,
+ RUNTIME_EXCEPTION,
+ ALLOWS_MULTIBINDINGS,
+ ALLOWS_SCOPING);
+ this.dependencyRequestValidator = dependencyRequestValidator;
+ }
+
+ @Override
+ protected ElementValidator elementValidator(ExecutableElement element) {
+ return new Validator(element);
+ }
+
+ private class Validator extends MethodValidator {
+ Validator(ExecutableElement element) {
+ super(element);
+ }
+
+ @Override
+ protected void checkAdditionalMethodProperties() {
+ }
+
+ /** Adds an error if a {@link Provides @Provides} method depends on a producer type. */
+ @Override
+ protected void checkParameter(VariableElement parameter) {
+ super.checkParameter(parameter);
+ dependencyRequestValidator.checkNotProducer(report, parameter);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ProvisionBinding.java b/java/dagger/internal/codegen/ProvisionBinding.java
new file mode 100644
index 0000000..306cb13
--- /dev/null
+++ b/java/dagger/internal/codegen/ProvisionBinding.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.model.BindingKind.COMPONENT_PROVISION;
+import static dagger.model.BindingKind.PROVISION;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import dagger.internal.codegen.MembersInjectionBinding.InjectionSite;
+import dagger.model.BindingKind;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.Scope;
+import java.util.Optional;
+
+/**
+ * A value object representing the mechanism by which a {@link Key} can be provided.
+ */
+@AutoValue
+abstract class ProvisionBinding extends ContributionBinding {
+
+ @Override
+ @Memoized
+ ImmutableSet<DependencyRequest> explicitDependencies() {
+ return ImmutableSet.<DependencyRequest>builder()
+ .addAll(provisionDependencies())
+ .addAll(membersInjectionDependencies())
+ .build();
+ }
+
+ /**
+ * Dependencies necessary to invoke an {@code @Inject} constructor or {@code @Provides} method.
+ */
+ abstract ImmutableSet<DependencyRequest> provisionDependencies();
+
+ @Memoized
+ ImmutableSet<DependencyRequest> membersInjectionDependencies() {
+ return injectionSites()
+ .stream()
+ .flatMap(i -> i.dependencies().stream())
+ .collect(toImmutableSet());
+ }
+
+ /**
+ * {@link InjectionSite}s for all {@code @Inject} members if {@link #kind()} is {@link
+ * BindingKind#INJECTION}, otherwise empty.
+ */
+ abstract ImmutableSortedSet<InjectionSite> injectionSites();
+
+ @Override
+ public BindingType bindingType() {
+ return BindingType.PROVISION;
+ }
+
+ @Override
+ abstract Optional<ProvisionBinding> unresolved();
+
+ // TODO(ronshapiro): we should be able to remove this, but AutoValue barks on the Builder's scope
+ // method, saying that the method doesn't correspond to a property of ProvisionBinding
+ @Override
+ public abstract Optional<Scope> scope();
+
+ static Builder builder() {
+ return new AutoValue_ProvisionBinding.Builder()
+ .provisionDependencies(ImmutableSet.of())
+ .injectionSites(ImmutableSortedSet.of());
+ }
+
+ abstract Builder toBuilder();
+
+ private static final ImmutableSet<BindingKind> KINDS_TO_CHECK_FOR_NULL =
+ ImmutableSet.of(PROVISION, COMPONENT_PROVISION);
+
+ boolean shouldCheckForNull(CompilerOptions compilerOptions) {
+ return KINDS_TO_CHECK_FOR_NULL.contains(kind())
+ && !contributedPrimitiveType().isPresent()
+ && !nullableType().isPresent()
+ && compilerOptions.doCheckForNulls();
+ }
+
+ // Profiling determined that this method is called enough times that memoizing it had a measurable
+ // performance improvement for large components.
+ @Memoized
+ @Override
+ boolean requiresModuleInstance() {
+ return super.requiresModuleInstance();
+ }
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ // TODO(ronshapiro,dpb): simplify the equality semantics
+ @Override
+ public abstract boolean equals(Object obj);
+
+ @AutoValue.Builder
+ @CanIgnoreReturnValue
+ abstract static class Builder extends ContributionBinding.Builder<ProvisionBinding, Builder> {
+
+ @Override
+ Builder dependencies(Iterable<DependencyRequest> dependencies) {
+ return provisionDependencies(dependencies);
+ }
+
+ abstract Builder provisionDependencies(Iterable<DependencyRequest> provisionDependencies);
+
+ abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
+
+ @Override
+ abstract Builder unresolved(ProvisionBinding unresolved);
+
+ abstract Builder scope(Optional<Scope> scope);
+ }
+
+}
diff --git a/java/dagger/internal/codegen/ProvisionDependencyOnProducerBindingValidator.java b/java/dagger/internal/codegen/ProvisionDependencyOnProducerBindingValidator.java
new file mode 100644
index 0000000..2fb1a0e
--- /dev/null
+++ b/java/dagger/internal/codegen/ProvisionDependencyOnProducerBindingValidator.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.RequestKinds.canBeSatisfiedByProductionBinding;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.DependencyEdge;
+import dagger.model.BindingGraph.Node;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import java.util.stream.Stream;
+import javax.inject.Inject;
+
+/**
+ * Reports an error for each provision-only dependency request that is satisfied by a production
+ * binding.
+ */
+// TODO(b/29509141): Clarify the error.
+final class ProvisionDependencyOnProducerBindingValidator implements BindingGraphPlugin {
+
+ @Inject
+ ProvisionDependencyOnProducerBindingValidator() {}
+
+ @Override
+ public String pluginName() {
+ return "Dagger/ProviderDependsOnProducer";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ provisionDependenciesOnProductionBindings(bindingGraph)
+ .forEach(
+ provisionDependent ->
+ diagnosticReporter.reportDependency(
+ ERROR,
+ provisionDependent,
+ provisionDependent.isEntryPoint()
+ ? entryPointErrorMessage(provisionDependent)
+ : dependencyErrorMessage(provisionDependent, bindingGraph)));
+ }
+
+ private Stream<DependencyEdge> provisionDependenciesOnProductionBindings(
+ BindingGraph bindingGraph) {
+ return bindingGraph.bindings().stream()
+ .filter(binding -> binding.isProduction())
+ .flatMap(binding -> incomingDependencies(binding, bindingGraph))
+ .filter(edge -> !dependencyCanUseProduction(edge, bindingGraph));
+ }
+
+ /** Returns the dependencies on {@code binding}. */
+ // TODO(dpb): Move to BindingGraph.
+ private Stream<DependencyEdge> incomingDependencies(
+ dagger.model.Binding binding, BindingGraph bindingGraph) {
+ return bindingGraph.network().inEdges(binding).stream()
+ .flatMap(instancesOf(DependencyEdge.class));
+ }
+
+ // TODO(ronshapiro): merge with MissingBindingValidator.dependencyCanUseProduction
+ private boolean dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph) {
+ return edge.isEntryPoint()
+ ? canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind())
+ : bindingRequestingDependency(edge, bindingGraph).isProduction();
+ }
+
+ /**
+ * Returns the binding that requests a dependency.
+ *
+ * @throws IllegalArgumentException if {@code dependency} is an {@linkplain
+ * DependencyEdge#isEntryPoint() entry point}.
+ */
+ // TODO(dpb): Move to BindingGraph.
+ private dagger.model.Binding bindingRequestingDependency(
+ DependencyEdge dependency, BindingGraph bindingGraph) {
+ checkArgument(!dependency.isEntryPoint());
+ Node source = bindingGraph.network().incidentNodes(dependency).source();
+ verify(
+ source instanceof dagger.model.Binding,
+ "expected source of %s to be a binding, but was: %s",
+ dependency,
+ source);
+ return (dagger.model.Binding) source;
+ }
+
+ private String entryPointErrorMessage(DependencyEdge entryPoint) {
+ return String.format(
+ "%s is a provision entry-point, which cannot depend on a production.",
+ entryPoint.dependencyRequest().key());
+ }
+
+ private String dependencyErrorMessage(
+ DependencyEdge dependencyOnProduction, BindingGraph bindingGraph) {
+ return String.format(
+ "%s is a provision, which cannot depend on a production.",
+ bindingRequestingDependency(dependencyOnProduction, bindingGraph).key());
+ }
+}
diff --git a/java/dagger/internal/codegen/PrunedConcreteMethodBindingExpression.java b/java/dagger/internal/codegen/PrunedConcreteMethodBindingExpression.java
new file mode 100644
index 0000000..6eb92ac
--- /dev/null
+++ b/java/dagger/internal/codegen/PrunedConcreteMethodBindingExpression.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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 com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.MissingBindingFactory;
+import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.producers.internal.MissingBindingProducer;
+import java.util.Optional;
+
+/**
+ * A {@link BindingExpression} that implements a method that encapsulates a binding that is not part
+ * of the binding graph when generating a final concrete implementation of a subcomponent. The
+ * implementation throws an exception. It is assumed that a binding may remain missing in a valid
+ * binding graph, because it's possible for there to be dependencies that are passively pruned when
+ * a non-leaf binding is re-defined (such as when {@code @Provides} bindings override
+ * {@code @Inject} bindings).
+ *
+ * <p>This method should never be invoked. If it is the exception indicates an issue within Dagger
+ * itself.
+ */
+final class PrunedConcreteMethodBindingExpression extends BindingExpression {
+ private static final CodeBlock METHOD_IMPLEMENTATION =
+ CodeBlock.of(
+ "throw new $T($S);",
+ UnsupportedOperationException.class,
+ "This binding is not part of the final binding graph. The key was requested by a binding "
+ + "that was believed to possibly be part of the graph, but is no longer requested. "
+ + "If this exception is thrown, it is the result of a Dagger bug.");
+
+ PrunedConcreteMethodBindingExpression() {}
+
+ @Override
+ CodeBlock getModifiableBindingMethodImplementation(
+ ModifiableBindingMethod modifiableBindingMethod,
+ ComponentImplementation component,
+ DaggerTypes types) {
+ Optional<FrameworkType> frameworkType = modifiableBindingMethod.request().frameworkType();
+ if (frameworkType.isPresent()) {
+ // If we make initializations replaceable, we can do away with these classes and this logic
+ // since the pruned framework instances will no longer be initialized
+ switch (frameworkType.get()) {
+ case PROVIDER:
+ return missingFrameworkInstance(MissingBindingFactory.class);
+ case PRODUCER_NODE:
+ return missingFrameworkInstance(MissingBindingProducer.class);
+ }
+ throw new AssertionError(frameworkType);
+ }
+ return METHOD_IMPLEMENTATION;
+ }
+
+ private static CodeBlock missingFrameworkInstance(Class<?> factoryClass) {
+ return CodeBlock.builder().addStatement("return $T.create()", factoryClass).build();
+ }
+
+ @Override
+ final Expression getDependencyExpression(ClassName requestingClass) {
+ throw new UnsupportedOperationException(
+ "Requesting a dependency expression for a pruned binding.");
+ }
+}
diff --git a/java/dagger/internal/codegen/RequestKinds.java b/java/dagger/internal/codegen/RequestKinds.java
new file mode 100644
index 0000000..aa17f5e
--- /dev/null
+++ b/java/dagger/internal/codegen/RequestKinds.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 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.auto.common.MoreTypes.asDeclared;
+import static com.google.auto.common.MoreTypes.isType;
+import static com.google.auto.common.MoreTypes.isTypeOf;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.javapoet.TypeNames.lazyOf;
+import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
+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.langmodel.DaggerTypes.checkTypePresent;
+import static dagger.model.RequestKind.INSTANCE;
+import static dagger.model.RequestKind.LAZY;
+import static dagger.model.RequestKind.PRODUCED;
+import static dagger.model.RequestKind.PRODUCER;
+import static dagger.model.RequestKind.PROVIDER;
+import static dagger.model.RequestKind.PROVIDER_OF_LAZY;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.squareup.javapoet.TypeName;
+import dagger.Lazy;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.RequestKind;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import javax.inject.Provider;
+import javax.lang.model.type.TypeMirror;
+
+/** Utility methods for {@link RequestKind}s. */
+final class RequestKinds {
+ /** Returns the type of a request of this kind for a key with a given type. */
+ static TypeMirror requestType(RequestKind requestKind, TypeMirror type, DaggerTypes types) {
+ switch (requestKind) {
+ case INSTANCE:
+ return type;
+
+ case PROVIDER_OF_LAZY:
+ return types.wrapType(requestType(LAZY, type, types), Provider.class);
+
+ case FUTURE:
+ return types.wrapType(type, ListenableFuture.class);
+
+ default:
+ return types.wrapType(type, frameworkClass(requestKind));
+ }
+ }
+
+ /** Returns the type of a request of this kind for a key with a given type. */
+ static TypeName requestTypeName(RequestKind requestKind, TypeName keyType) {
+ switch (requestKind) {
+ case INSTANCE:
+ return keyType;
+
+ case PROVIDER:
+ return providerOf(keyType);
+
+ case LAZY:
+ return lazyOf(keyType);
+
+ case PROVIDER_OF_LAZY:
+ return providerOf(lazyOf(keyType));
+
+ case PRODUCER:
+ return producerOf(keyType);
+
+ case PRODUCED:
+ return producedOf(keyType);
+
+ case FUTURE:
+ return listenableFutureOf(keyType);
+
+ default:
+ throw new AssertionError(requestKind);
+ }
+ }
+
+ private static final ImmutableMap<RequestKind, Class<?>> FRAMEWORK_CLASSES =
+ ImmutableMap.of(
+ PROVIDER, Provider.class,
+ LAZY, Lazy.class,
+ PRODUCER, Producer.class,
+ PRODUCED, Produced.class);
+
+ /** Returns the {@link RequestKind} that matches the wrapping types (if any) of {@code type}. */
+ static RequestKind getRequestKind(TypeMirror type) {
+ checkTypePresent(type);
+ for (RequestKind kind : FRAMEWORK_CLASSES.keySet()) {
+ if (matchesKind(kind, type)) {
+ if (kind.equals(PROVIDER) && matchesKind(LAZY, extractKeyType(kind, type))) {
+ return PROVIDER_OF_LAZY;
+ }
+ return kind;
+ }
+ }
+ return INSTANCE;
+ }
+
+ /**
+ * Returns {@code true} if {@code type} is a parameterized type of {@code kind}'s {@link
+ * #frameworkClass(RequestKind) framework class}.
+ */
+ private static boolean matchesKind(RequestKind kind, TypeMirror type) {
+ return isType(type)
+ && isTypeOf(frameworkClass(kind), type)
+ && !asDeclared(type).getTypeArguments().isEmpty();
+ }
+
+ /**
+ * Unwraps the framework class(es) of {@code requestKind} from {@code type}. If {@code
+ * requestKind} is {@link RequestKind#INSTANCE}, this acts as an identity function.
+ *
+ * @throws TypeNotPresentException if {@code type} is an {@link javax.lang.model.type.ErrorType},
+ * which may mean that the type will be generated in a later round of processing
+ * @throws IllegalArgumentException if {@code type} is not wrapped with {@code requestKind}'s
+ * framework class(es).
+ */
+ static TypeMirror extractKeyType(RequestKind requestKind, TypeMirror type) {
+ checkTypePresent(type);
+ switch (requestKind) {
+ case INSTANCE:
+ return type;
+ case PROVIDER_OF_LAZY:
+ return extractKeyType(LAZY, extractKeyType(PROVIDER, type));
+ default:
+ checkArgument(isType(type) && isTypeOf(frameworkClass(requestKind), type));
+ return getOnlyElement(MoreTypes.asDeclared(type).getTypeArguments());
+ }
+ }
+
+ /**
+ * A dagger- or {@code javax.inject}-defined class for {@code requestKind} that that can wrap
+ * another type but share the same {@link dagger.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.
+ *
+ * <p>This concept is not well defined and should probably be removed and inlined into the cases
+ * that need it. For example, {@link RequestKind#PROVIDER_OF_LAZY} has <em>2</em> wrapping
+ * classes, and {@link RequestKind#FUTURE} is wrapped with a {@link ListenableFuture}, but for
+ * historical/implementation reasons has not had an associated framework class.
+ */
+ static Class<?> frameworkClass(RequestKind requestKind) {
+ Class<?> result = FRAMEWORK_CLASSES.get(requestKind);
+ checkArgument(result != null, "no framework class for %s", requestKind);
+ return result;
+ }
+
+ /**
+ * Returns {@code true} if requests for {@code requestKind} can be satisfied by a production
+ * binding.
+ */
+ static boolean canBeSatisfiedByProductionBinding(RequestKind requestKind) {
+ switch (requestKind) {
+ case INSTANCE:
+ case PROVIDER:
+ case LAZY:
+ case PROVIDER_OF_LAZY:
+ case MEMBERS_INJECTION:
+ return false;
+ case PRODUCER:
+ case PRODUCED:
+ case FUTURE:
+ return true;
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns true if {@code requestKind} is always derived from a {@link RequestKind#PROVIDER}
+ * instance.
+ */
+ static boolean isDerivedFromProvider(RequestKind requestKind) {
+ switch (requestKind) {
+ case LAZY:
+ case PROVIDER_OF_LAZY:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private RequestKinds() {}
+}
diff --git a/java/dagger/internal/codegen/ResolvedBindings.java b/java/dagger/internal/codegen/ResolvedBindings.java
new file mode 100644
index 0000000..814995a
--- /dev/null
+++ b/java/dagger/internal/codegen/ResolvedBindings.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import dagger.internal.codegen.ContributionType.HasContributionType;
+import dagger.model.Key;
+import dagger.model.Scope;
+import java.util.Optional;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * The collection of bindings that have been resolved for a key. For valid graphs, contains exactly
+ * one binding.
+ *
+ * <p>Separate {@link ResolvedBindings} instances should be used if a {@link
+ * MembersInjectionBinding} and a {@link ProvisionBinding} for the same key exist in the same
+ * component. (This will only happen if a type has an {@code @Inject} constructor and members, the
+ * component has a members injection method, and the type is also requested normally.)
+ */
+@AutoValue
+abstract class ResolvedBindings implements HasContributionType {
+ /**
+ * The binding key for which the {@link #bindings()} have been resolved.
+ */
+ abstract Key key();
+
+ /**
+ * The {@link ContributionBinding}s for {@link #key()} indexed by the component that owns the
+ * binding. Each key in the multimap is a part of the same component ancestry.
+ */
+ abstract ImmutableSetMultimap<TypeElement, ContributionBinding> allContributionBindings();
+
+ /**
+ * The {@link MembersInjectionBinding}s for {@link #key()} indexed by the component that owns the
+ * binding. Each key in the map is a part of the same component ancestry.
+ */
+ abstract ImmutableMap<TypeElement, MembersInjectionBinding> allMembersInjectionBindings();
+
+ /** The multibinding declarations for {@link #key()}. */
+ abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
+
+ /** The subcomponent declarations for {@link #key()}. */
+ abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
+
+ /**
+ * The optional binding declarations for {@link #key()}.
+ */
+ abstract ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations();
+
+ // Computing the hash code is an expensive operation.
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ // Suppresses ErrorProne warning that hashCode was overridden w/o equals
+ @Override
+ public abstract boolean equals(Object other);
+
+ /** All bindings for {@link #key()}, indexed by the component that owns the binding. */
+ final ImmutableSetMultimap<TypeElement, ? extends Binding> allBindings() {
+ return !allMembersInjectionBindings().isEmpty()
+ ? allMembersInjectionBindings().asMultimap()
+ : allContributionBindings();
+ }
+
+ /** All bindings for {@link #key()}, regardless of which component owns them. */
+ final ImmutableCollection<? extends Binding> bindings() {
+ return allBindings().values();
+ }
+
+ /**
+ * Returns the single binding.
+ *
+ * @throws IllegalStateException if there is not exactly one element in {@link #bindings()}, which
+ * will never happen for contributions in valid graphs
+ */
+ final Binding binding() {
+ return getOnlyElement(bindings());
+ }
+
+ /**
+ * {@code true} if there are no {@link #bindings()}, {@link #multibindingDeclarations()}, {@link
+ * #optionalBindingDeclarations()}, or {@link #subcomponentDeclarations()}.
+ */
+ final boolean isEmpty() {
+ return allMembersInjectionBindings().isEmpty()
+ && allContributionBindings().isEmpty()
+ && multibindingDeclarations().isEmpty()
+ && optionalBindingDeclarations().isEmpty()
+ && subcomponentDeclarations().isEmpty();
+ }
+
+ /** All bindings for {@link #key()} that are owned by a component. */
+ ImmutableSet<? extends Binding> bindingsOwnedBy(ComponentDescriptor component) {
+ return allBindings().get(component.typeElement());
+ }
+
+ /**
+ * All contribution bindings, regardless of owning component. Empty if this is a members-injection
+ * binding.
+ */
+ @Memoized
+ ImmutableSet<ContributionBinding> contributionBindings() {
+ // TODO(ronshapiro): consider optimizing ImmutableSet.copyOf(Collection) for small immutable
+ // collections so that it doesn't need to call toArray(). Even though this method is memoized,
+ // toArray() can take ~150ms for large components, and there are surely other places in the
+ // processor that can benefit from this.
+ return ImmutableSet.copyOf(allContributionBindings().values());
+ }
+
+ /** The component that owns {@code binding}. */
+ final TypeElement owningComponent(ContributionBinding binding) {
+ checkArgument(
+ contributionBindings().contains(binding),
+ "binding is not resolved for %s: %s",
+ key(),
+ binding);
+ return getOnlyElement(allContributionBindings().inverse().get(binding));
+ }
+
+ /**
+ * The members-injection binding, regardless of owning component. Absent if these are contribution
+ * bindings, or if there is no members-injection binding because the type fails validation.
+ */
+ final Optional<MembersInjectionBinding> membersInjectionBinding() {
+ return allMembersInjectionBindings().isEmpty()
+ ? Optional.empty()
+ : Optional.of(Iterables.getOnlyElement(allMembersInjectionBindings().values()));
+ }
+
+ /** Creates a {@link ResolvedBindings} for contribution bindings. */
+ static ResolvedBindings forContributionBindings(
+ Key key,
+ Multimap<TypeElement, ContributionBinding> contributionBindings,
+ Iterable<MultibindingDeclaration> multibindings,
+ Iterable<SubcomponentDeclaration> subcomponentDeclarations,
+ Iterable<OptionalBindingDeclaration> optionalBindingDeclarations) {
+ return new AutoValue_ResolvedBindings(
+ key,
+ ImmutableSetMultimap.copyOf(contributionBindings),
+ ImmutableMap.of(),
+ ImmutableSet.copyOf(multibindings),
+ ImmutableSet.copyOf(subcomponentDeclarations),
+ ImmutableSet.copyOf(optionalBindingDeclarations));
+ }
+
+ /**
+ * Creates a {@link ResolvedBindings} for members injection bindings.
+ */
+ static ResolvedBindings forMembersInjectionBinding(
+ Key key,
+ ComponentDescriptor owningComponent,
+ MembersInjectionBinding ownedMembersInjectionBinding) {
+ return new AutoValue_ResolvedBindings(
+ key,
+ ImmutableSetMultimap.of(),
+ ImmutableMap.of(owningComponent.typeElement(), ownedMembersInjectionBinding),
+ ImmutableSet.of(),
+ ImmutableSet.of(),
+ ImmutableSet.of());
+ }
+
+ /**
+ * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key.
+ */
+ static ResolvedBindings noBindings(Key key) {
+ return new AutoValue_ResolvedBindings(
+ key,
+ ImmutableSetMultimap.of(),
+ ImmutableMap.of(),
+ ImmutableSet.of(),
+ ImmutableSet.of(),
+ ImmutableSet.of());
+ }
+
+ /**
+ * {@code true} if this is a multibinding contribution.
+ */
+ boolean isMultibindingContribution() {
+ return contributionBindings().size() == 1
+ && contributionBinding().contributionType().isMultibinding();
+ }
+
+ /**
+ * Returns the single contribution binding.
+ *
+ * @throws IllegalStateException if there is not exactly one element in
+ * {@link #contributionBindings()}, which will never happen for contributions in valid graphs
+ */
+ ContributionBinding contributionBinding() {
+ return getOnlyElement(contributionBindings());
+ }
+
+ /**
+ * The binding type for these bindings. If there are {@link #multibindingDeclarations()} or {@link
+ * #subcomponentDeclarations()} but no {@link #bindings()}, returns {@link BindingType#PROVISION}.
+ *
+ * @throws IllegalStateException if {@link #isEmpty()} or the binding types conflict
+ */
+ final BindingType bindingType() {
+ checkState(!isEmpty(), "empty bindings for %s", key());
+ if (allBindings().isEmpty()
+ && (!multibindingDeclarations().isEmpty() || !subcomponentDeclarations().isEmpty())) {
+ // Only multibinding declarations, so assume provision.
+ return BindingType.PROVISION;
+ }
+ ImmutableSet<BindingType> bindingTypes = bindingTypes();
+ checkState(bindingTypes.size() == 1, "conflicting binding types: %s", bindings());
+ return getOnlyElement(bindingTypes);
+ }
+
+ /** The binding types for {@link #bindings()}. */
+ @Memoized
+ ImmutableSet<BindingType> bindingTypes() {
+ return bindings().stream().map(Binding::bindingType).collect(toImmutableSet());
+ }
+
+ /**
+ * The contribution type for these bindings.
+ *
+ * @throws IllegalStateException if there is not exactly one element in {@link
+ * #contributionBindings()}, which will never happen for contributions in valid graphs
+ */
+ @Override
+ public ContributionType contributionType() {
+ return contributionBinding().contributionType();
+ }
+
+ /**
+ * The scope associated with the single binding.
+ *
+ * @throws IllegalStateException if {@link #bindings()} does not have exactly one element
+ */
+ Optional<Scope> scope() {
+ return binding().scope();
+ }
+}
diff --git a/java/dagger/internal/codegen/Scopes.java b/java/dagger/internal/codegen/Scopes.java
new file mode 100644
index 0000000..252f712
--- /dev/null
+++ b/java/dagger/internal/codegen/Scopes.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DiagnosticFormatting.stripCommonTypePrefixes;
+
+import com.google.auto.common.AnnotationMirrors;
+import com.google.common.collect.ImmutableSet;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.model.Scope;
+import dagger.producers.ProductionScope;
+import java.lang.annotation.Annotation;
+import java.util.Optional;
+import javax.inject.Singleton;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/** Common names and convenience methods for {@link Scope}s. */
+final class Scopes {
+ /**
+ * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
+ */
+ static Scope scope(TypeElement scopeType) {
+ return Scope.scope(SimpleAnnotationMirror.of(scopeType));
+ }
+
+ /** Returns a representation for {@link ProductionScope @ProductionScope} scope. */
+ static Scope productionScope(DaggerElements elements) {
+ return scope(elements, ProductionScope.class);
+ }
+
+ /** Returns a representation for {@link Singleton @Singleton} scope. */
+ static Scope singletonScope(DaggerElements elements) {
+ return scope(elements, Singleton.class);
+ }
+
+ private static Scope scope(
+ DaggerElements elements, Class<? extends Annotation> scopeAnnotationClass) {
+ return scope(elements.getTypeElement(scopeAnnotationClass));
+ }
+
+ /**
+ * Returns at most one associated scoped annotation from the source code element, throwing an
+ * exception if there are more than one.
+ */
+ static Optional<Scope> uniqueScopeOf(Element element) {
+ // TODO(ronshapiro): Use MoreCollectors.toOptional() once we can use guava-jre
+ return Optional.ofNullable(getOnlyElement(scopesOf(element), null));
+ }
+
+ /**
+ * Returns the readable source representation (name with @ prefix) of the scope's annotation type.
+ *
+ * <p>It's readable source because it has had common package prefixes removed, e.g.
+ * {@code @javax.inject.Singleton} is returned as {@code @Singleton}.
+ */
+ static String getReadableSource(Scope scope) {
+ return stripCommonTypePrefixes(scope.toString());
+ }
+
+ /** Returns all of the associated scopes for a source code element. */
+ static ImmutableSet<Scope> scopesOf(Element element) {
+ return AnnotationMirrors.getAnnotatedAnnotations(element, javax.inject.Scope.class)
+ .stream()
+ .map(Scope::scope)
+ .collect(toImmutableSet());
+ }
+}
diff --git a/java/dagger/internal/codegen/SetBindingExpression.java b/java/dagger/internal/codegen/SetBindingExpression.java
new file mode 100644
index 0000000..5efb85f
--- /dev/null
+++ b/java/dagger/internal/codegen/SetBindingExpression.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.BindingRequest.bindingRequest;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.common.collect.ImmutableSet;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import dagger.internal.SetBuilder;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import java.util.Collections;
+import java.util.Optional;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/** A binding expression for multibound sets. */
+final class SetBindingExpression extends MultibindingExpression {
+ private final ProvisionBinding binding;
+ private final BindingGraph graph;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ SetBindingExpression(
+ ResolvedBindings resolvedBindings,
+ ComponentImplementation componentImplementation,
+ BindingGraph graph,
+ ComponentBindingExpressions componentBindingExpressions,
+ DaggerTypes types,
+ DaggerElements elements) {
+ super(resolvedBindings, componentImplementation);
+ this.binding = (ProvisionBinding) resolvedBindings.contributionBinding();
+ this.graph = graph;
+ this.componentBindingExpressions = componentBindingExpressions;
+ this.types = types;
+ this.elements = elements;
+ }
+
+ @Override
+ protected Expression buildDependencyExpression(ClassName requestingClass) {
+ Optional<CodeBlock> superMethodCall = superMethodCall();
+ // TODO(ronshapiro): We should also make an ImmutableSet version of SetFactory
+ boolean isImmutableSetAvailable = isImmutableSetAvailable();
+ // TODO(ronshapiro, gak): Use Sets.immutableEnumSet() if it's available?
+ if (isImmutableSetAvailable
+ && binding.dependencies().stream().allMatch(this::isSingleValue)
+ && !superMethodCall.isPresent()) {
+ return Expression.create(
+ immutableSetType(),
+ CodeBlock.builder()
+ .add("$T.", ImmutableSet.class)
+ .add(maybeTypeParameter(requestingClass))
+ .add(
+ "of($L)",
+ binding
+ .dependencies()
+ .stream()
+ .map(dependency -> getContributionExpression(dependency, requestingClass))
+ .collect(toParametersCodeBlock()))
+ .build());
+ }
+ switch (binding.dependencies().size()) {
+ case 0:
+ return collectionsStaticFactoryInvocation(requestingClass, CodeBlock.of("emptySet()"));
+ case 1:
+ {
+ DependencyRequest dependency = getOnlyElement(binding.dependencies());
+ CodeBlock contributionExpression = getContributionExpression(dependency, requestingClass);
+ if (isSingleValue(dependency)) {
+ return collectionsStaticFactoryInvocation(
+ requestingClass, CodeBlock.of("singleton($L)", contributionExpression));
+ } else if (isImmutableSetAvailable) {
+ return Expression.create(
+ immutableSetType(),
+ CodeBlock.builder()
+ .add("$T.", ImmutableSet.class)
+ .add(maybeTypeParameter(requestingClass))
+ .add("copyOf($L)", contributionExpression)
+ .build());
+ }
+ }
+ // fall through
+ default:
+ CodeBlock.Builder instantiation = CodeBlock.builder();
+ instantiation
+ .add("$T.", isImmutableSetAvailable ? ImmutableSet.class : SetBuilder.class)
+ .add(maybeTypeParameter(requestingClass));
+ if (isImmutableSetBuilderWithExpectedSizeAvailable()) {
+ instantiation.add("builderWithExpectedSize($L)", binding.dependencies().size());
+ } else if (isImmutableSetAvailable) {
+ instantiation.add("builder()");
+ } else {
+ instantiation.add("newSetBuilder($L)", binding.dependencies().size());
+ }
+ for (DependencyRequest dependency : getNewContributions(binding.dependencies())) {
+ String builderMethod = isSingleValue(dependency) ? "add" : "addAll";
+ instantiation.add(
+ ".$L($L)", builderMethod, getContributionExpression(dependency, requestingClass));
+ }
+ if (superMethodCall.isPresent()) {
+ instantiation.add(CodeBlock.of(".addAll($L)", superMethodCall.get()));
+ }
+ instantiation.add(".build()");
+ return Expression.create(
+ isImmutableSetAvailable ? immutableSetType() : binding.key().type(),
+ instantiation.build());
+ }
+ }
+
+ private DeclaredType immutableSetType() {
+ return types.getDeclaredType(
+ elements.getTypeElement(ImmutableSet.class), SetType.from(binding.key()).elementType());
+ }
+
+ private CodeBlock getContributionExpression(
+ DependencyRequest dependency, ClassName requestingClass) {
+ return componentBindingExpressions
+ .getDependencyExpression(bindingRequest(dependency), requestingClass)
+ .codeBlock();
+ }
+
+ private Expression collectionsStaticFactoryInvocation(
+ ClassName requestingClass, CodeBlock methodInvocation) {
+ return Expression.create(
+ binding.key().type(),
+ CodeBlock.builder()
+ .add("$T.", Collections.class)
+ .add(maybeTypeParameter(requestingClass))
+ .add(methodInvocation)
+ .build());
+ }
+
+ private CodeBlock maybeTypeParameter(ClassName requestingClass) {
+ TypeMirror elementType = SetType.from(binding.key()).elementType();
+ return isTypeAccessibleFrom(elementType, requestingClass.packageName())
+ ? CodeBlock.of("<$T>", elementType)
+ : CodeBlock.of("");
+ }
+
+ private boolean isSingleValue(DependencyRequest dependency) {
+ return graph
+ .contributionBindings()
+ .get(dependency.key())
+ .contributionBinding()
+ .contributionType()
+ .equals(ContributionType.SET);
+ }
+
+ private boolean isImmutableSetBuilderWithExpectedSizeAvailable() {
+ if (isImmutableSetAvailable()) {
+ return methodsIn(elements.getTypeElement(ImmutableSet.class).getEnclosedElements())
+ .stream()
+ .anyMatch(method -> method.getSimpleName().contentEquals("builderWithExpectedSize"));
+ }
+ return false;
+ }
+
+ private boolean isImmutableSetAvailable() {
+ return elements.getTypeElement(ImmutableSet.class) != null;
+ }
+}
diff --git a/java/dagger/internal/codegen/SetFactoryCreationExpression.java b/java/dagger/internal/codegen/SetFactoryCreationExpression.java
new file mode 100644
index 0000000..9712091
--- /dev/null
+++ b/java/dagger/internal/codegen/SetFactoryCreationExpression.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static dagger.internal.codegen.SourceFiles.setFactoryClassName;
+
+import com.squareup.javapoet.CodeBlock;
+import dagger.model.DependencyRequest;
+import dagger.producers.Produced;
+import java.util.Optional;
+
+/** A factory creation expression for a multibound set. */
+final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpression {
+
+ private final ComponentImplementation componentImplementation;
+ private final BindingGraph graph;
+ private final ContributionBinding binding;
+
+ SetFactoryCreationExpression(
+ ContributionBinding binding,
+ ComponentImplementation componentImplementation,
+ ComponentBindingExpressions componentBindingExpressions,
+ BindingGraph graph) {
+ super(binding, componentImplementation, componentBindingExpressions);
+ this.binding = checkNotNull(binding);
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.graph = checkNotNull(graph);
+ }
+
+ @Override
+ public CodeBlock creationExpression() {
+ CodeBlock.Builder builder = CodeBlock.builder().add("$T.", setFactoryClassName(binding));
+ if (!useRawType()) {
+ SetType setType = SetType.from(binding.key());
+ builder.add(
+ "<$T>",
+ setType.elementsAreTypeOf(Produced.class)
+ ? setType.unwrappedElementType(Produced.class)
+ : setType.elementType());
+ }
+
+ int individualProviders = 0;
+ int setProviders = 0;
+ CodeBlock.Builder builderMethodCalls = CodeBlock.builder();
+ String methodNameSuffix =
+ binding.bindingType().equals(BindingType.PROVISION) ? "Provider" : "Producer";
+
+ Optional<CodeBlock> superContributions = superContributions();
+ if (superContributions.isPresent()) {
+ // TODO(b/117833324): consider decomposing the Provider<Set<Provider>> and adding the
+ // individual contributions separately from the collection contributions. Though this may
+ // actually not be doable/desirable if the super provider instance is a DelegateFactory or
+ // another internal type that is not SetFactory
+ builderMethodCalls.add(".addCollection$N($L)", methodNameSuffix, superContributions.get());
+ setProviders++;
+ }
+
+ for (DependencyRequest dependency : dependenciesToImplement()) {
+ ContributionType contributionType =
+ graph.contributionBindings().get(dependency.key()).contributionType();
+ String methodNamePrefix;
+ switch (contributionType) {
+ case SET:
+ individualProviders++;
+ methodNamePrefix = "add";
+ break;
+ case SET_VALUES:
+ setProviders++;
+ methodNamePrefix = "addCollection";
+ break;
+ default:
+ throw new AssertionError(dependency + " is not a set multibinding");
+ }
+
+ builderMethodCalls.add(
+ ".$N$N($L)",
+ methodNamePrefix,
+ methodNameSuffix,
+ multibindingDependencyExpression(dependency));
+ }
+ builder.add("builder($L, $L)", individualProviders, setProviders);
+ builder.add(builderMethodCalls.build());
+
+ componentImplementation.registerImplementedMultibinding(binding, bindingRequest());
+
+ return builder.add(".build()").build();
+ }
+}
diff --git a/java/dagger/internal/codegen/SetType.java b/java/dagger/internal/codegen/SetType.java
new file mode 100644
index 0000000..e4fa584
--- /dev/null
+++ b/java/dagger/internal/codegen/SetType.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.auto.common.MoreTypes;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Equivalence;
+import dagger.model.Key;
+import java.util.Set;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Information about a {@link Set} {@link TypeMirror}.
+ */
+@AutoValue
+abstract class SetType {
+ /**
+ * The set type itself, wrapped using {@link MoreTypes#equivalence()}. Use
+ * {@link #declaredSetType()} instead.
+ */
+ protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredSetType();
+
+ /**
+ * The set type itself.
+ */
+ DeclaredType declaredSetType() {
+ return wrappedDeclaredSetType().get();
+ }
+
+ /**
+ * {@code true} if the set type is the raw {@link Set} type.
+ */
+ boolean isRawType() {
+ return declaredSetType().getTypeArguments().isEmpty();
+ }
+
+ /**
+ * The element type.
+ */
+ TypeMirror elementType() {
+ return declaredSetType().getTypeArguments().get(0);
+ }
+
+ /**
+ * {@code true} if {@link #elementType()} is a {@code clazz}.
+ */
+ boolean elementsAreTypeOf(Class<?> clazz) {
+ return MoreTypes.isType(elementType()) && MoreTypes.isTypeOf(clazz, elementType());
+ }
+
+ /**
+ * {@code T} if {@link #elementType()} is a {@code WrappingClass<T>}.
+ *
+ * @throws IllegalStateException if {@link #elementType()} is not a {@code WrappingClass<T>}
+ * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
+ * parameter
+ */
+ TypeMirror unwrappedElementType(Class<?> wrappingClass) {
+ checkArgument(
+ wrappingClass.getTypeParameters().length == 1,
+ "%s must have exactly one type parameter",
+ wrappingClass);
+ checkArgument(
+ elementsAreTypeOf(wrappingClass),
+ "expected elements to be %s, but this type is %s",
+ wrappingClass,
+ declaredSetType());
+ return MoreTypes.asDeclared(elementType()).getTypeArguments().get(0);
+ }
+
+ /**
+ * {@code true} if {@code type} is a {@link Set} type.
+ */
+ static boolean isSet(TypeMirror type) {
+ return MoreTypes.isType(type) && MoreTypes.isTypeOf(Set.class, type);
+ }
+
+ /**
+ * {@code true} if {@code key.type()} is a {@link Set} type.
+ */
+ static boolean isSet(Key key) {
+ return isSet(key.type());
+ }
+
+ /**
+ * Returns a {@link SetType} for {@code type}.
+ *
+ * @throws IllegalArgumentException if {@code type} is not a {@link Set} type
+ */
+ static SetType from(TypeMirror type) {
+ checkArgument(isSet(type), "%s must be a Set", type);
+ return new AutoValue_SetType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
+ }
+
+ /**
+ * Returns a {@link SetType} for {@code key}'s {@link Key#type() type}.
+ *
+ * @throws IllegalArgumentException if {@code key.type()} is not a {@link Set} type
+ */
+ static SetType from(Key key) {
+ return from (key.type());
+ }
+}
diff --git a/java/dagger/internal/codegen/SimpleAnnotationMirror.java b/java/dagger/internal/codegen/SimpleAnnotationMirror.java
new file mode 100644
index 0000000..505c8ea
--- /dev/null
+++ b/java/dagger/internal/codegen/SimpleAnnotationMirror.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static javax.lang.model.util.ElementFilter.methodsIn;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import java.util.Map;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+
+/** A representation of an annotation. */
+final class SimpleAnnotationMirror implements AnnotationMirror {
+ private final TypeElement annotationType;
+ private final ImmutableMap<String, ? extends AnnotationValue> namedValues;
+ private final ImmutableMap<ExecutableElement, ? extends AnnotationValue> elementValues;
+
+ private SimpleAnnotationMirror(
+ TypeElement annotationType, Map<String, ? extends AnnotationValue> namedValues) {
+ checkArgument(
+ annotationType.getKind().equals(ElementKind.ANNOTATION_TYPE),
+ "annotationType must be an annotation: %s",
+ annotationType);
+ checkArgument(
+ FluentIterable.from(methodsIn(annotationType.getEnclosedElements()))
+ .transform(element -> element.getSimpleName().toString())
+ .toSet()
+ .equals(namedValues.keySet()),
+ "namedValues must have values for exactly the members in %s: %s",
+ annotationType,
+ namedValues);
+ this.annotationType = annotationType;
+ this.namedValues = ImmutableMap.copyOf(namedValues);
+ this.elementValues =
+ Maps.toMap(
+ methodsIn(annotationType.getEnclosedElements()),
+ Functions.compose(
+ Functions.forMap(namedValues), element -> element.getSimpleName().toString()));
+ }
+
+ @Override
+ public DeclaredType getAnnotationType() {
+ return MoreTypes.asDeclared(annotationType.asType());
+ }
+
+ @Override
+ public Map<ExecutableElement, ? extends AnnotationValue> getElementValues() {
+ return elementValues;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("@").append(annotationType.getQualifiedName());
+ if (!namedValues.isEmpty()) {
+ builder
+ .append('(')
+ .append(Joiner.on(", ").withKeyValueSeparator(" = ").join(namedValues))
+ .append(')');
+ }
+ return builder.toString();
+ }
+
+ /**
+ * An object representing an annotation instance.
+ *
+ * @param annotationType must be an annotation type with no members
+ */
+ static AnnotationMirror of(TypeElement annotationType) {
+ return of(annotationType, ImmutableMap.<String, AnnotationValue>of());
+ }
+
+ /**
+ * An object representing an annotation instance.
+ *
+ * @param annotationType must be an annotation type
+ * @param namedValues a value for every annotation member, including those with defaults, indexed
+ * by simple name
+ */
+ static AnnotationMirror of(
+ TypeElement annotationType, Map<String, ? extends AnnotationValue> namedValues) {
+ return new SimpleAnnotationMirror(annotationType, namedValues);
+ }
+}
diff --git a/java/dagger/internal/codegen/SimpleInvocationBindingExpression.java b/java/dagger/internal/codegen/SimpleInvocationBindingExpression.java
new file mode 100644
index 0000000..909d7ae
--- /dev/null
+++ b/java/dagger/internal/codegen/SimpleInvocationBindingExpression.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/** A simple binding expression for instance requests. Does not scope. */
+abstract class SimpleInvocationBindingExpression extends BindingExpression {
+ // TODO(dpb): Take ContributionBinding instead of ResolvedBindings.
+ private final ResolvedBindings resolvedBindings;
+
+ SimpleInvocationBindingExpression(ResolvedBindings resolvedBindings) {
+ this.resolvedBindings = checkNotNull(resolvedBindings);
+ }
+
+ @Override
+ boolean requiresMethodEncapsulation() {
+ return !resolvedBindings.contributionBinding().dependencies().isEmpty();
+ }
+}
diff --git a/java/dagger/internal/codegen/SimpleMethodBindingExpression.java b/java/dagger/internal/codegen/SimpleMethodBindingExpression.java
new file mode 100644
index 0000000..805ac7b
--- /dev/null
+++ b/java/dagger/internal/codegen/SimpleMethodBindingExpression.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 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.auto.common.MoreElements.asExecutable;
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.InjectionMethods.ProvisionMethod.requiresInjectionMethod;
+import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
+import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
+import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
+
+import com.google.auto.common.MoreTypes;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import dagger.internal.codegen.InjectionMethods.ProvisionMethod;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.DependencyRequest;
+import java.util.Optional;
+import java.util.function.Function;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * A binding expression that invokes methods or constructors directly (without attempting to scope)
+ * {@link dagger.model.RequestKind#INSTANCE} requests.
+ */
+final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpression {
+ private final CompilerOptions compilerOptions;
+ private final ProvisionBinding provisionBinding;
+ private final ComponentBindingExpressions componentBindingExpressions;
+ private final MembersInjectionMethods membersInjectionMethods;
+ private final ComponentRequirementExpressions componentRequirementExpressions;
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+ private final SourceVersion sourceVersion;
+
+ SimpleMethodBindingExpression(
+ ResolvedBindings resolvedBindings,
+ CompilerOptions compilerOptions,
+ ComponentBindingExpressions componentBindingExpressions,
+ MembersInjectionMethods membersInjectionMethods,
+ ComponentRequirementExpressions componentRequirementExpressions,
+ DaggerTypes types,
+ DaggerElements elements,
+ SourceVersion sourceVersion) {
+ super(resolvedBindings);
+ this.compilerOptions = compilerOptions;
+ this.provisionBinding = (ProvisionBinding) resolvedBindings.contributionBinding();
+ checkArgument(
+ provisionBinding.implicitDependencies().isEmpty(),
+ "framework deps are not currently supported");
+ checkArgument(provisionBinding.bindingElement().isPresent());
+ this.componentBindingExpressions = componentBindingExpressions;
+ this.membersInjectionMethods = membersInjectionMethods;
+ this.componentRequirementExpressions = componentRequirementExpressions;
+ this.types = types;
+ this.elements = elements;
+ this.sourceVersion = sourceVersion;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ ImmutableMap<DependencyRequest, Expression> arguments =
+ ImmutableMap.copyOf(
+ Maps.asMap(
+ provisionBinding.dependencies(),
+ request -> dependencyArgument(request, requestingClass)));
+ Function<DependencyRequest, CodeBlock> argumentsFunction =
+ request -> arguments.get(request).codeBlock();
+ return requiresInjectionMethod(
+ provisionBinding,
+ arguments.values().asList(),
+ compilerOptions,
+ requestingClass.packageName(),
+ types)
+ ? invokeInjectionMethod(argumentsFunction, requestingClass)
+ : invokeMethod(argumentsFunction, requestingClass);
+ }
+
+ private Expression invokeMethod(
+ Function<DependencyRequest, CodeBlock> argumentsFunction,
+ ClassName requestingClass) {
+ // TODO(dpb): align this with the contents of InlineMethods.create
+ CodeBlock arguments =
+ provisionBinding.dependencies().stream()
+ .map(argumentsFunction)
+ .collect(toParametersCodeBlock());
+ ExecutableElement method = asExecutable(provisionBinding.bindingElement().get());
+ CodeBlock invocation;
+ switch (method.getKind()) {
+ case CONSTRUCTOR:
+ invocation = CodeBlock.of("new $T($L)", constructorTypeName(requestingClass), arguments);
+ break;
+ case METHOD:
+ CodeBlock module =
+ moduleReference(requestingClass)
+ .orElse(CodeBlock.of("$T", provisionBinding.bindingTypeElement().get()));
+ invocation = CodeBlock.of("$L.$L($L)", module, method.getSimpleName(), arguments);
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+
+ return Expression.create(simpleMethodReturnType(), invocation);
+ }
+
+ private TypeName constructorTypeName(ClassName requestingClass) {
+ DeclaredType type = MoreTypes.asDeclared(provisionBinding.key().type());
+ TypeName typeName = TypeName.get(type);
+ if (type.getTypeArguments()
+ .stream()
+ .allMatch(t -> isTypeAccessibleFrom(t, requestingClass.packageName()))) {
+ return typeName;
+ }
+ return rawTypeName(typeName);
+ }
+
+ private Expression invokeInjectionMethod(
+ Function<DependencyRequest, CodeBlock> argumentsFunction, ClassName requestingClass) {
+ return injectMembers(
+ ProvisionMethod.invoke(
+ provisionBinding,
+ argumentsFunction,
+ requestingClass,
+ moduleReference(requestingClass),
+ compilerOptions,
+ elements));
+ }
+
+ private Expression dependencyArgument(DependencyRequest dependency, ClassName requestingClass) {
+ return componentBindingExpressions.getDependencyArgumentExpression(dependency, requestingClass);
+ }
+
+ private Expression injectMembers(CodeBlock instance) {
+ if (provisionBinding.injectionSites().isEmpty()) {
+ return Expression.create(simpleMethodReturnType(), instance);
+ }
+ if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
+ // Java 7 type inference can't figure out that instance in
+ // injectParameterized(Parameterized_Factory.newParameterized()) is Parameterized<T> and not
+ // Parameterized<Object>
+ if (!MoreTypes.asDeclared(provisionBinding.key().type()).getTypeArguments().isEmpty()) {
+ TypeName keyType = TypeName.get(provisionBinding.key().type());
+ instance = CodeBlock.of("($T) ($T) $L", keyType, rawTypeName(keyType), instance);
+ }
+ }
+ MethodSpec membersInjectionMethod = membersInjectionMethods.getOrCreate(provisionBinding.key());
+ TypeMirror returnType =
+ membersInjectionMethod.returnType.equals(TypeName.OBJECT)
+ ? elements.getTypeElement(Object.class).asType()
+ : provisionBinding.key().type();
+ return Expression.create(returnType, CodeBlock.of("$N($L)", membersInjectionMethod, instance));
+ }
+
+ private Optional<CodeBlock> moduleReference(ClassName requestingClass) {
+ return provisionBinding.requiresModuleInstance()
+ ? provisionBinding
+ .contributingModule()
+ .map(Element::asType)
+ .map(ComponentRequirement::forModule)
+ .map(module -> componentRequirementExpressions.getExpression(module, requestingClass))
+ : Optional.empty();
+ }
+
+ private TypeMirror simpleMethodReturnType() {
+ return provisionBinding.contributedPrimitiveType().orElse(provisionBinding.key().type());
+ }
+}
diff --git a/java/dagger/internal/codegen/SimpleTypeAnnotationValue.java b/java/dagger/internal/codegen/SimpleTypeAnnotationValue.java
new file mode 100644
index 0000000..7f043db
--- /dev/null
+++ b/java/dagger/internal/codegen/SimpleTypeAnnotationValue.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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 javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.type.TypeMirror;
+
+/** An {@link AnnotationValue} that contains a {@link TypeMirror}. */
+final class SimpleTypeAnnotationValue implements AnnotationValue {
+ private final TypeMirror value;
+
+ SimpleTypeAnnotationValue(TypeMirror value) {
+ this.value = value;
+ }
+
+ @Override
+ public TypeMirror getValue() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return value + ".class";
+ }
+
+ @Override
+ public <R, P> R accept(AnnotationValueVisitor<R, P> visitor, P parameter) {
+ return visitor.visitType(getValue(), parameter);
+ }
+}
diff --git a/java/dagger/internal/codegen/SourceFileGenerationException.java b/java/dagger/internal/codegen/SourceFileGenerationException.java
new file mode 100644
index 0000000..07c1c68
--- /dev/null
+++ b/java/dagger/internal/codegen/SourceFileGenerationException.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.squareup.javapoet.ClassName;
+import java.util.Optional;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.Element;
+
+/**
+ * An exception thrown to indicate that a source file could not be generated.
+ *
+ * <p>This exception <b>should not</b> be used to report detectable, logical errors as it may mask
+ * other errors that might have been caught upon further processing. Use a {@link ValidationReport}
+ * for that.
+ */
+final class SourceFileGenerationException extends Exception {
+ private final Element associatedElement;
+
+ SourceFileGenerationException(
+ Optional<ClassName> generatedClassName, Throwable cause, Element associatedElement) {
+ super(createMessage(generatedClassName, cause.getMessage()), cause);
+ this.associatedElement = checkNotNull(associatedElement);
+ }
+
+ private static String createMessage(Optional<ClassName> generatedClassName, String message) {
+ return String.format("Could not generate %s: %s.",
+ generatedClassName.isPresent()
+ ? generatedClassName.get()
+ : "unknown file",
+ message);
+ }
+
+ void printMessageTo(Messager messager) {
+ messager.printMessage(ERROR, getMessage(), associatedElement);
+ }
+}
diff --git a/java/dagger/internal/codegen/SourceFileGenerator.java b/java/dagger/internal/codegen/SourceFileGenerator.java
new file mode 100644
index 0000000..7dddc2f
--- /dev/null
+++ b/java/dagger/internal/codegen/SourceFileGenerator.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 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.auto.common.GeneratedAnnotations.generatedAnnotation;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Throwables;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.TypeSpec;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.Optional;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+
+/**
+ * A template class that provides a framework for properly handling IO while generating source files
+ * from an annotation processor. Particularly, it makes a best effort to ensure that files that
+ * fail to write successfully are deleted.
+ *
+ * @param <T> The input type from which source is to be generated.
+ */
+abstract class SourceFileGenerator<T> {
+ private static final String GENERATED_COMMENTS = "https://dagger.dev";
+
+ private final Filer filer;
+ private final DaggerElements elements;
+ private final SourceVersion sourceVersion;
+
+ SourceFileGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ this.filer = checkNotNull(filer);
+ this.elements = checkNotNull(elements);
+ this.sourceVersion = checkNotNull(sourceVersion);
+ }
+
+ SourceFileGenerator(SourceFileGenerator<T> delegate) {
+ this(delegate.filer, delegate.elements, delegate.sourceVersion);
+ }
+
+ /**
+ * Generates a source file to be compiled for {@code T}. Writes any generation exception to {@code
+ * messager} and does not throw.
+ */
+ void generate(T input, Messager messager) {
+ try {
+ generate(input);
+ } catch (SourceFileGenerationException e) {
+ e.printMessageTo(messager);
+ }
+ }
+
+ /** Generates a source file to be compiled for {@code T}. */
+ void generate(T input) throws SourceFileGenerationException {
+ ClassName generatedTypeName = nameGeneratedType(input);
+ Optional<TypeSpec.Builder> type = write(generatedTypeName, input);
+ if (!type.isPresent()) {
+ return;
+ }
+ try {
+ buildJavaFile(generatedTypeName, input, type.get()).writeTo(filer);
+ } catch (Exception e) {
+ // if the code above threw a SFGE, use that
+ Throwables.propagateIfPossible(e, SourceFileGenerationException.class);
+ // otherwise, throw a new one
+ throw new SourceFileGenerationException(
+ Optional.empty(), e, originatingElement(input));
+ }
+ }
+
+ private JavaFile buildJavaFile(
+ ClassName generatedTypeName, T input, TypeSpec.Builder typeSpecBuilder) {
+ typeSpecBuilder.addOriginatingElement(originatingElement(input));
+ Optional<AnnotationSpec> generatedAnnotation =
+ generatedAnnotation(elements, sourceVersion)
+ .map(
+ annotation ->
+ AnnotationSpec.builder(ClassName.get(annotation))
+ .addMember("value", "$S", "dagger.internal.codegen.ComponentProcessor")
+ .addMember("comments", "$S", GENERATED_COMMENTS)
+ .build());
+ generatedAnnotation.ifPresent(typeSpecBuilder::addAnnotation);
+ JavaFile.Builder javaFileBuilder =
+ JavaFile.builder(generatedTypeName.packageName(), typeSpecBuilder.build())
+ .skipJavaLangImports(true);
+ if (!generatedAnnotation.isPresent()) {
+ javaFileBuilder.addFileComment("Generated by Dagger ($L).", GENERATED_COMMENTS);
+ }
+ return javaFileBuilder.build();
+ }
+
+ /**
+ * Implementations should return the {@link ClassName} for the top-level type to be generated.
+ */
+ abstract ClassName nameGeneratedType(T input);
+
+ /** Returns the originating element of the generating type. */
+ abstract Element originatingElement(T input);
+
+ /**
+ * Returns a {@link TypeSpec.Builder type} to be generated for {@code T}, or {@link
+ * Optional#empty()} if no file should be generated.
+ */
+ // TODO(ronshapiro): write() makes more sense in JavaWriter where all writers are mutable.
+ // consider renaming to something like typeBuilder() which conveys the mutability of the result
+ abstract Optional<TypeSpec.Builder> write(ClassName generatedTypeName, T input);
+}
diff --git a/java/dagger/internal/codegen/SourceFileGeneratorsModule.java b/java/dagger/internal/codegen/SourceFileGeneratorsModule.java
index 426afae..c32262a 100644
--- a/java/dagger/internal/codegen/SourceFileGeneratorsModule.java
+++ b/java/dagger/internal/codegen/SourceFileGeneratorsModule.java
@@ -18,49 +18,48 @@
import dagger.Module;
import dagger.Provides;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProductionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.writing.FactoryGenerator;
-import dagger.internal.codegen.writing.HjarSourceFileGenerator;
-import dagger.internal.codegen.writing.MembersInjectorGenerator;
-import dagger.internal.codegen.writing.ModuleGenerator;
-import dagger.internal.codegen.writing.ModuleProxies.ModuleConstructorProxyGenerator;
-import dagger.internal.codegen.writing.ProducerFactoryGenerator;
+import dagger.internal.codegen.SourceFileGeneratorsModule.ComponentModule;
+import dagger.internal.codegen.SourceFileGeneratorsModule.MembersInjectionModule;
+import dagger.internal.codegen.SourceFileGeneratorsModule.ProductionModule;
+import dagger.internal.codegen.SourceFileGeneratorsModule.ProvisionModule;
import javax.lang.model.element.TypeElement;
-@Module
-abstract class SourceFileGeneratorsModule {
-
- @Provides
- static SourceFileGenerator<ProvisionBinding> factoryGenerator(
- FactoryGenerator generator, CompilerOptions compilerOptions) {
- return hjarWrapper(generator, compilerOptions);
+@Module(
+ includes = {
+ ProvisionModule.class,
+ ProductionModule.class,
+ MembersInjectionModule.class,
+ ComponentModule.class
+ })
+interface SourceFileGeneratorsModule {
+ @Module
+ abstract class GeneratorModule<T, G extends SourceFileGenerator<T>> {
+ @Provides
+ SourceFileGenerator<T> generator(G generator, CompilerOptions compilerOptions) {
+ return compilerOptions.headerCompilation()
+ ? HjarSourceFileGenerator.wrap(generator)
+ : generator;
+ }
}
- @Provides
- static SourceFileGenerator<ProductionBinding> producerFactoryGenerator(
- ProducerFactoryGenerator generator, CompilerOptions compilerOptions) {
- return hjarWrapper(generator, compilerOptions);
- }
+ @Module
+ class ProvisionModule extends GeneratorModule<ProvisionBinding, FactoryGenerator> {}
- @Provides
- static SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator(
- MembersInjectorGenerator generator, CompilerOptions compilerOptions) {
- return hjarWrapper(generator, compilerOptions);
- }
+ @Module
+ class ProductionModule extends GeneratorModule<ProductionBinding, ProducerFactoryGenerator> {}
+ @Module
+ class MembersInjectionModule
+ extends GeneratorModule<MembersInjectionBinding, MembersInjectorGenerator> {}
+
+ @Module
+ class ComponentModule extends GeneratorModule<BindingGraph, ComponentGenerator> {}
+
+ // the abstract module is not available because we're using a qualifier
@Provides
@ModuleGenerator
- static SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator(
+ static SourceFileGenerator<TypeElement> generator(
ModuleConstructorProxyGenerator generator, CompilerOptions compilerOptions) {
- return hjarWrapper(generator, compilerOptions);
- }
-
- private static <T> SourceFileGenerator<T> hjarWrapper(
- SourceFileGenerator<T> generator, CompilerOptions compilerOptions) {
return compilerOptions.headerCompilation()
? HjarSourceFileGenerator.wrap(generator)
: generator;
diff --git a/java/dagger/internal/codegen/SourceFiles.java b/java/dagger/internal/codegen/SourceFiles.java
new file mode 100644
index 0000000..fd93d0d
--- /dev/null
+++ b/java/dagger/internal/codegen/SourceFiles.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2014 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Verify.verify;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.Optionals.optionalComparator;
+import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCED_PRODUCER;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCER_PRODUCER;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_PRODUCER;
+import static dagger.internal.codegen.javapoet.TypeNames.MAP_PROVIDER_FACTORY;
+import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER_OF_LAZY;
+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.model.BindingKind.INJECTION;
+import static dagger.model.BindingKind.MULTIBOUND_MAP;
+import static dagger.model.BindingKind.MULTIBOUND_SET;
+import static java.util.Comparator.comparing;
+import static javax.lang.model.SourceVersion.isName;
+
+import com.google.auto.common.MoreElements;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+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.Maps;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.SetFactory;
+import dagger.model.DependencyRequest;
+import dagger.model.Key;
+import dagger.model.RequestKind;
+import dagger.producers.Produced;
+import dagger.producers.Producer;
+import dagger.producers.internal.SetOfProducedProducer;
+import dagger.producers.internal.SetProducer;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import javax.inject.Provider;
+import javax.lang.model.SourceVersion;
+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.TypeParameterElement;
+
+/**
+ * Utilities for generating files.
+ */
+class SourceFiles {
+
+ private static final Joiner CLASS_FILE_NAME_JOINER = Joiner.on('_');
+
+ /**
+ * Sorts {@link DependencyRequest} instances in an order likely to reflect their logical
+ * importance.
+ */
+ static final Comparator<DependencyRequest> DEPENDENCY_ORDERING =
+ // put fields before parameters
+ comparing(
+ (DependencyRequest request) -> request.requestElement().map(Element::getKind),
+ optionalComparator())
+ // order by dependency kind
+ .thenComparing(DependencyRequest::kind)
+ // then sort by name
+ .thenComparing(
+ request ->
+ request.requestElement().map(element -> element.getSimpleName().toString()),
+ optionalComparator());
+
+ /**
+ * Generates names and keys for the factory class fields needed to hold the framework classes for
+ * all of the dependencies of {@code binding}. It is responsible for choosing a name that
+ *
+ * <ul>
+ * <li>represents all of the dependency requests for this key
+ * <li>is <i>probably</i> associated with the type being bound
+ * <li>is unique within the class
+ * </ul>
+ *
+ * @param binding must be an unresolved binding (type parameters must match its type element's)
+ */
+ static ImmutableMap<Key, FrameworkField> generateBindingFieldsForDependencies(
+ Binding binding) {
+ checkArgument(!binding.unresolved().isPresent(), "binding must be unresolved: %s", binding);
+
+ ImmutableMap.Builder<Key, FrameworkField> bindingFields = ImmutableMap.builder();
+ for (Binding.DependencyAssociation dependencyAssociation : binding.dependencyAssociations()) {
+ FrameworkDependency frameworkDependency = dependencyAssociation.frameworkDependency();
+ bindingFields.put(
+ frameworkDependency.key(),
+ FrameworkField.create(
+ ClassName.get(frameworkDependency.frameworkClass()),
+ TypeName.get(frameworkDependency.key().type()),
+ fieldNameForDependency(dependencyAssociation.dependencyRequests())));
+ }
+ return bindingFields.build();
+ }
+
+ private static String fieldNameForDependency(ImmutableSet<DependencyRequest> dependencyRequests) {
+ // collect together all of the names that we would want to call the provider
+ ImmutableSet<String> dependencyNames =
+ dependencyRequests.stream().map(DependencyVariableNamer::name).collect(toImmutableSet());
+
+ if (dependencyNames.size() == 1) {
+ // if there's only one name, great! use it!
+ return Iterables.getOnlyElement(dependencyNames);
+ } else {
+ // in the event that a field is being used for a bunch of deps with different names,
+ // add all the names together with "And"s in the middle. E.g.: stringAndS
+ Iterator<String> namesIterator = dependencyNames.iterator();
+ String first = namesIterator.next();
+ StringBuilder compositeNameBuilder = new StringBuilder(first);
+ while (namesIterator.hasNext()) {
+ compositeNameBuilder
+ .append("And")
+ .append(CaseFormat.LOWER_CAMEL.to(UPPER_CAMEL, namesIterator.next()));
+ }
+ return compositeNameBuilder.toString();
+ }
+ }
+
+ static CodeBlock frameworkTypeUsageStatement(
+ CodeBlock frameworkTypeMemberSelect, RequestKind dependencyKind) {
+ switch (dependencyKind) {
+ case LAZY:
+ return CodeBlock.of("$T.lazy($L)", DOUBLE_CHECK, frameworkTypeMemberSelect);
+ case INSTANCE:
+ case FUTURE:
+ return CodeBlock.of("$L.get()", frameworkTypeMemberSelect);
+ case PROVIDER:
+ case PRODUCER:
+ return frameworkTypeMemberSelect;
+ case PROVIDER_OF_LAZY:
+ return CodeBlock.of("$T.create($L)", PROVIDER_OF_LAZY, frameworkTypeMemberSelect);
+ default: // including PRODUCED
+ throw new AssertionError(dependencyKind);
+ }
+ }
+
+ /**
+ * Returns a mapping of {@link DependencyRequest}s to {@link CodeBlock}s that {@linkplain
+ * #frameworkTypeUsageStatement(CodeBlock, RequestKind) use them}.
+ */
+ static ImmutableMap<DependencyRequest, CodeBlock> frameworkFieldUsages(
+ ImmutableSet<DependencyRequest> dependencies, ImmutableMap<Key, FieldSpec> fields) {
+ return Maps.toMap(
+ dependencies,
+ dep ->
+ frameworkTypeUsageStatement(CodeBlock.of("$N", fields.get(dep.key())), dep.kind()));
+ }
+
+ /**
+ * Returns the generated factory or members injector name for a binding.
+ */
+ static ClassName generatedClassNameForBinding(Binding binding) {
+ switch (binding.bindingType()) {
+ case PROVISION:
+ case PRODUCTION:
+ ContributionBinding contribution = (ContributionBinding) binding;
+ switch (contribution.kind()) {
+ case INJECTION:
+ case PROVISION:
+ case PRODUCTION:
+ return elementBasedClassName(
+ MoreElements.asExecutable(binding.bindingElement().get()), "Factory");
+
+ default:
+ throw new AssertionError();
+ }
+
+ case MEMBERS_INJECTION:
+ return membersInjectorNameForType(
+ ((MembersInjectionBinding) binding).membersInjectedType());
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Calculates an appropriate {@link ClassName} for a generated class that is based on {@code
+ * element}, appending {@code suffix} at the end.
+ *
+ * <p>This will always return a {@linkplain ClassName#topLevelClassName() top level class name},
+ * even if {@code element}'s enclosing class is a nested type.
+ */
+ static ClassName elementBasedClassName(ExecutableElement element, String suffix) {
+ ClassName enclosingClassName =
+ ClassName.get(MoreElements.asType(element.getEnclosingElement()));
+ String methodName =
+ element.getKind().equals(ElementKind.CONSTRUCTOR)
+ ? ""
+ : LOWER_CAMEL.to(UPPER_CAMEL, element.getSimpleName().toString());
+ return ClassName.get(
+ enclosingClassName.packageName(),
+ classFileName(enclosingClassName) + "_" + methodName + suffix);
+ }
+
+ static TypeName parameterizedGeneratedTypeNameForBinding(Binding binding) {
+ ClassName className = generatedClassNameForBinding(binding);
+ ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding);
+ return typeParameters.isEmpty()
+ ? className
+ : ParameterizedTypeName.get(className, Iterables.toArray(typeParameters, TypeName.class));
+ }
+
+ static ClassName membersInjectorNameForType(TypeElement typeElement) {
+ return siblingClassName(typeElement, "_MembersInjector");
+ }
+
+ static String classFileName(ClassName className) {
+ return CLASS_FILE_NAME_JOINER.join(className.simpleNames());
+ }
+
+ static ClassName generatedMonitoringModuleName(
+ TypeElement componentElement) {
+ return siblingClassName(componentElement, "_MonitoringModule");
+ }
+
+ // TODO(ronshapiro): when JavaPoet migration is complete, replace the duplicated code
+ // which could use this.
+ private static ClassName siblingClassName(TypeElement typeElement, String suffix) {
+ ClassName className = ClassName.get(typeElement);
+ return className.topLevelClassName().peerClass(classFileName(className) + suffix);
+ }
+
+ /**
+ * The {@link java.util.Set} factory class name appropriate for set bindings.
+ *
+ * <ul>
+ * <li>{@link SetFactory} for provision bindings.
+ * <li>{@link SetProducer} for production bindings for {@code Set<T>}.
+ * <li>{@link SetOfProducedProducer} for production bindings for {@code Set<Produced<T>>}.
+ * </ul>
+ */
+ static ClassName setFactoryClassName(ContributionBinding binding) {
+ checkArgument(binding.kind().equals(MULTIBOUND_SET));
+ if (binding.bindingType().equals(BindingType.PROVISION)) {
+ return SET_FACTORY;
+ } else {
+ SetType setType = SetType.from(binding.key());
+ return setType.elementsAreTypeOf(Produced.class) ? SET_OF_PRODUCED_PRODUCER : SET_PRODUCER;
+ }
+ }
+
+ /** The {@link java.util.Map} factory class name appropriate for map bindings. */
+ static ClassName mapFactoryClassName(ContributionBinding binding) {
+ checkState(binding.kind().equals(MULTIBOUND_MAP), binding.kind());
+ MapType mapType = MapType.from(binding.key());
+ switch (binding.bindingType()) {
+ case PROVISION:
+ return mapType.valuesAreTypeOf(Provider.class) ? MAP_PROVIDER_FACTORY : MAP_FACTORY;
+ case PRODUCTION:
+ return mapType.valuesAreFrameworkType()
+ ? mapType.valuesAreTypeOf(Producer.class)
+ ? MAP_OF_PRODUCER_PRODUCER
+ : MAP_OF_PRODUCED_PRODUCER
+ : MAP_PRODUCER;
+ default:
+ throw new IllegalArgumentException(binding.bindingType().toString());
+ }
+ }
+
+ static ImmutableList<TypeVariableName> bindingTypeElementTypeVariableNames(Binding binding) {
+ if (binding instanceof ContributionBinding) {
+ ContributionBinding contributionBinding = (ContributionBinding) binding;
+ if (!contributionBinding.kind().equals(INJECTION)
+ && !contributionBinding.requiresModuleInstance()) {
+ return ImmutableList.of();
+ }
+ }
+ List<? extends TypeParameterElement> typeParameters =
+ binding.bindingTypeElement().get().getTypeParameters();
+ return typeParameters.stream().map(TypeVariableName::get).collect(toImmutableList());
+ }
+
+ /**
+ * Returns a name to be used for variables of the given {@linkplain TypeElement type}. Prefer
+ * semantically meaningful variable names, but if none can be derived, this will produce something
+ * readable.
+ */
+ // TODO(gak): maybe this should be a function of TypeMirrors instead of Elements?
+ static String simpleVariableName(TypeElement typeElement) {
+ String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString());
+ String variableName = protectAgainstKeywords(candidateName);
+ verify(isName(variableName), "'%s' was expected to be a valid variable name");
+ return variableName;
+ }
+
+ static String protectAgainstKeywords(String candidateName) {
+ switch (candidateName) {
+ case "package":
+ return "pkg";
+ case "boolean":
+ return "b";
+ case "double":
+ return "d";
+ case "byte":
+ return "b";
+ case "int":
+ return "i";
+ case "short":
+ return "s";
+ case "char":
+ return "c";
+ case "void":
+ return "v";
+ case "class":
+ return "clazz";
+ case "float":
+ return "f";
+ case "long":
+ return "l";
+ default:
+ return SourceVersion.isKeyword(candidateName) ? candidateName + '_' : candidateName;
+ }
+ }
+
+ private SourceFiles() {}
+}
diff --git a/java/dagger/internal/codegen/SpiModule.java b/java/dagger/internal/codegen/SpiModule.java
index a4f537b..a8f13e1 100644
--- a/java/dagger/internal/codegen/SpiModule.java
+++ b/java/dagger/internal/codegen/SpiModule.java
@@ -24,7 +24,6 @@
import com.google.common.collect.ImmutableSet;
import dagger.Module;
import dagger.Provides;
-import dagger.internal.codegen.validation.BindingGraphValidator;
import dagger.spi.BindingGraphPlugin;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -41,21 +40,16 @@
@Provides
@Singleton
static ImmutableSet<BindingGraphPlugin> externalPlugins(
- @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins,
- @ProcessorClassLoader ClassLoader processorClassLoader) {
+ @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins) {
return testingPlugins.orElseGet(
() ->
ImmutableSet.copyOf(
- ServiceLoader.load(BindingGraphPlugin.class, processorClassLoader)));
+ ServiceLoader.load(
+ BindingGraphPlugin.class, BindingGraphValidator.class.getClassLoader())));
}
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, PARAMETER, METHOD})
@interface TestingPlugins {}
-
- @Qualifier
- @Retention(RUNTIME)
- @Target({PARAMETER, METHOD})
- @interface ProcessorClassLoader {}
}
diff --git a/java/dagger/internal/codegen/SubcomponentCreatorBindingEdgeImpl.java b/java/dagger/internal/codegen/SubcomponentCreatorBindingEdgeImpl.java
new file mode 100644
index 0000000..c97024e
--- /dev/null
+++ b/java/dagger/internal/codegen/SubcomponentCreatorBindingEdgeImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.collect.Iterables.getOnlyElement;
+import static dagger.internal.codegen.DaggerStreams.presentValues;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.collect.ImmutableSet;
+import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
+import javax.lang.model.element.TypeElement;
+
+/** An implementation of {@link SubcomponentCreatorBindingEdge}. */
+final class SubcomponentCreatorBindingEdgeImpl implements SubcomponentCreatorBindingEdge {
+
+ private final ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations;
+
+ SubcomponentCreatorBindingEdgeImpl(
+ ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
+ this.subcomponentDeclarations = subcomponentDeclarations;
+ }
+
+ @Override
+ public ImmutableSet<TypeElement> declaringModules() {
+ return subcomponentDeclarations.stream()
+ .map(SubcomponentDeclaration::contributingModule)
+ .flatMap(presentValues())
+ .collect(toImmutableSet());
+ }
+
+ @Override
+ public String toString() {
+ return "subcomponent declared by "
+ + (subcomponentDeclarations.size() == 1
+ ? getOnlyElement(declaringModules()).getQualifiedName()
+ : declaringModules().stream()
+ .map(TypeElement::getQualifiedName)
+ .collect(joining(", ", "{", "}")));
+ }
+}
diff --git a/java/dagger/internal/codegen/SubcomponentCreatorBindingExpression.java b/java/dagger/internal/codegen/SubcomponentCreatorBindingExpression.java
new file mode 100644
index 0000000..b415d3f
--- /dev/null
+++ b/java/dagger/internal/codegen/SubcomponentCreatorBindingExpression.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 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 com.squareup.javapoet.ClassName;
+import dagger.internal.codegen.javapoet.Expression;
+import javax.lang.model.type.TypeMirror;
+
+/** A binding expression for a subcomponent creator that just invokes the constructor. */
+final class SubcomponentCreatorBindingExpression extends SimpleInvocationBindingExpression {
+ private final TypeMirror creatorType;
+ private final String creatorImplementationName;
+
+ SubcomponentCreatorBindingExpression(
+ ResolvedBindings resolvedBindings, String creatorImplementationName) {
+ super(resolvedBindings);
+ this.creatorType = resolvedBindings.key().type();
+ this.creatorImplementationName = creatorImplementationName;
+ }
+
+ @Override
+ Expression getDependencyExpression(ClassName requestingClass) {
+ return Expression.create(creatorType, "new $L()", creatorImplementationName);
+ }
+}
diff --git a/java/dagger/internal/codegen/SubcomponentDeclaration.java b/java/dagger/internal/codegen/SubcomponentDeclaration.java
new file mode 100644
index 0000000..5677857
--- /dev/null
+++ b/java/dagger/internal/codegen/SubcomponentDeclaration.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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.auto.common.AnnotationMirrors.getAnnotationElementAndValue;
+import static dagger.internal.codegen.ConfigurationAnnotations.getSubcomponentCreator;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableSet;
+import dagger.model.Key;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A declaration for a subcomponent that is included in a module via {@link
+ * dagger.Module#subcomponents()}.
+ */
+@AutoValue
+abstract class SubcomponentDeclaration extends BindingDeclaration {
+ /**
+ * Key for the {@link dagger.Subcomponent.Builder} or {@link
+ * dagger.producers.ProductionSubcomponent.Builder} of {@link #subcomponentType()}.
+ */
+ @Override
+ public abstract Key key();
+
+ /**
+ * The type element that defines the {@link dagger.Subcomponent} or {@link
+ * dagger.producers.ProductionSubcomponent} for this declaration.
+ */
+ abstract TypeElement subcomponentType();
+
+ /** The module annotation. */
+ abstract ModuleAnnotation moduleAnnotation();
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ static class Factory {
+ private final KeyFactory keyFactory;
+
+ @Inject
+ Factory(KeyFactory keyFactory) {
+ this.keyFactory = keyFactory;
+ }
+
+ ImmutableSet<SubcomponentDeclaration> forModule(TypeElement module) {
+ ImmutableSet.Builder<SubcomponentDeclaration> declarations = ImmutableSet.builder();
+ ModuleAnnotation moduleAnnotation = ModuleAnnotation.moduleAnnotation(module).get();
+ Element subcomponentAttribute =
+ getAnnotationElementAndValue(moduleAnnotation.annotation(), "subcomponents").getKey();
+ for (TypeElement subcomponent : moduleAnnotation.subcomponents()) {
+ declarations.add(
+ new AutoValue_SubcomponentDeclaration(
+ Optional.of(subcomponentAttribute),
+ Optional.of(module),
+ keyFactory.forSubcomponentCreator(
+ getSubcomponentCreator(subcomponent).get().asType()),
+ subcomponent,
+ moduleAnnotation));
+ }
+ return declarations.build();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/SubcomponentFactoryMethodValidator.java b/java/dagger/internal/codegen/SubcomponentFactoryMethodValidator.java
new file mode 100644
index 0000000..0c6a006
--- /dev/null
+++ b/java/dagger/internal/codegen/SubcomponentFactoryMethodValidator.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 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.auto.common.MoreTypes.asDeclared;
+import static com.google.auto.common.MoreTypes.asExecutable;
+import static com.google.auto.common.MoreTypes.asTypeElements;
+import static com.google.common.collect.Sets.union;
+import static dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.BindingGraph;
+import dagger.model.BindingGraph.ChildFactoryMethodEdge;
+import dagger.model.BindingGraph.ComponentNode;
+import dagger.spi.BindingGraphPlugin;
+import dagger.spi.DiagnosticReporter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import javax.inject.Inject;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+
+/** Reports an error if a subcomponent factory method is missing required modules. */
+final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
+
+ private final DaggerTypes types;
+ private final Map<ComponentNode, Set<TypeElement>> inheritedModulesCache = new HashMap<>();
+
+ @Inject
+ SubcomponentFactoryMethodValidator(DaggerTypes types) {
+ this.types = types;
+ }
+
+ @Override
+ public String pluginName() {
+ return "Dagger/SubcomponentFactoryMethodMissingModule";
+ }
+
+ @Override
+ public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
+ if (!bindingGraph.rootComponentNode().isRealComponent()
+ || bindingGraph.rootComponentNode().isSubcomponent()) {
+ // We don't know all the modules that might be owned by the child until we know the real root
+ // component, which we don't if the root component node is really a module or a subcomponent.
+ return;
+ }
+ bindingGraph.network().edges().stream()
+ .flatMap(instancesOf(ChildFactoryMethodEdge.class))
+ .forEach(
+ edge -> {
+ ImmutableSet<TypeElement> missingModules = findMissingModules(edge, bindingGraph);
+ if (!missingModules.isEmpty()) {
+ reportMissingModuleParameters(
+ edge, missingModules, bindingGraph, diagnosticReporter);
+ }
+ });
+ }
+
+ private ImmutableSet<TypeElement> findMissingModules(
+ ChildFactoryMethodEdge edge, BindingGraph graph) {
+ ImmutableSet<TypeElement> factoryMethodParameters =
+ subgraphFactoryMethodParameters(edge, graph);
+ ComponentNode child = (ComponentNode) graph.network().incidentNodes(edge).target();
+ SetView<TypeElement> modulesOwnedByChild = ownedModules(child, graph);
+ return graph.bindings().stream()
+ // bindings owned by child
+ .filter(binding -> binding.componentPath().equals(child.componentPath()))
+ // that require a module instance
+ .filter(binding -> binding.requiresModuleInstance())
+ .map(binding -> binding.contributingModule().get())
+ .distinct()
+ // module owned by child
+ .filter(module -> modulesOwnedByChild.contains(module))
+ // module not in the method parameters
+ .filter(module -> !factoryMethodParameters.contains(module))
+ // module doesn't have an accessible no-arg constructor
+ .filter(moduleType -> !componentCanMakeNewInstances(moduleType))
+ .collect(toImmutableSet());
+ }
+
+ private ImmutableSet<TypeElement> subgraphFactoryMethodParameters(
+ ChildFactoryMethodEdge edge, BindingGraph bindingGraph) {
+ ComponentNode parent = (ComponentNode) bindingGraph.network().incidentNodes(edge).source();
+ DeclaredType parentType = asDeclared(parent.componentPath().currentComponent().asType());
+ ExecutableType factoryMethodType =
+ asExecutable(types.asMemberOf(parentType, edge.factoryMethod()));
+ return asTypeElements(factoryMethodType.getParameterTypes());
+ }
+
+ private SetView<TypeElement> ownedModules(ComponentNode component, BindingGraph graph) {
+ return Sets.difference(
+ ((ComponentNodeImpl) component).componentDescriptor().moduleTypes(),
+ inheritedModules(component, graph));
+ }
+
+ private Set<TypeElement> inheritedModules(ComponentNode component, BindingGraph graph) {
+ return Util.reentrantComputeIfAbsent(
+ inheritedModulesCache, component, uncachedInheritedModules(graph));
+ }
+
+ private Function<ComponentNode, Set<TypeElement>> uncachedInheritedModules(BindingGraph graph) {
+ return componentNode ->
+ componentNode.componentPath().atRoot()
+ ? ImmutableSet.of()
+ : graph
+ .componentNode(componentNode.componentPath().parent())
+ .map(parent -> union(ownedModules(parent, graph), inheritedModules(parent, graph)))
+ .get();
+ }
+
+ private void reportMissingModuleParameters(
+ ChildFactoryMethodEdge edge,
+ ImmutableSet<TypeElement> missingModules,
+ BindingGraph graph,
+ DiagnosticReporter diagnosticReporter) {
+ diagnosticReporter.reportSubcomponentFactoryMethod(
+ ERROR,
+ edge,
+ "%s requires modules which have no visible default constructors. "
+ + "Add the following modules as parameters to this method: %s",
+ graph
+ .network()
+ .incidentNodes(edge)
+ .target()
+ .componentPath()
+ .currentComponent()
+ .getQualifiedName(),
+ Joiner.on(", ").join(missingModules));
+ }
+}
diff --git a/java/dagger/internal/codegen/SubcomponentNames.java b/java/dagger/internal/codegen/SubcomponentNames.java
new file mode 100644
index 0000000..f2ffd83
--- /dev/null
+++ b/java/dagger/internal/codegen/SubcomponentNames.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static dagger.internal.codegen.DaggerStreams.toImmutableMap;
+import static java.lang.Character.isUpperCase;
+import static java.lang.String.format;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimaps;
+import dagger.model.Key;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Holds the unique simple names for all subcomponents, keyed by their {@link ComponentDescriptor}
+ * and {@link Key} of the subcomponent builder.
+ */
+final class SubcomponentNames {
+ private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
+
+ private final ImmutableMap<ComponentDescriptor, String> namesByDescriptor;
+ private final ImmutableMap<Key, ComponentDescriptor> descriptorsByCreatorKey;
+
+ SubcomponentNames(BindingGraph graph, KeyFactory keyFactory) {
+ this.namesByDescriptor = namesByDescriptor(graph);
+ this.descriptorsByCreatorKey = descriptorsByCreatorKey(keyFactory, namesByDescriptor.keySet());
+ }
+
+ /** Returns the simple component name for the given {@link ComponentDescriptor}. */
+ String get(ComponentDescriptor componentDescriptor) {
+ return namesByDescriptor.get(componentDescriptor);
+ }
+
+ /**
+ * Returns the simple name for the subcomponent creator implementation with the given {@link Key}.
+ */
+ String getCreatorName(Key key) {
+ return getCreatorName(descriptorsByCreatorKey.get(key));
+ }
+
+ /**
+ * Returns the simple name for the subcomponent creator implementation for the given {@link
+ * ComponentDescriptor}.
+ */
+ String getCreatorName(ComponentDescriptor componentDescriptor) {
+ checkArgument(componentDescriptor.creatorDescriptor().isPresent());
+ ComponentCreatorDescriptor creatorDescriptor = componentDescriptor.creatorDescriptor().get();
+ return get(componentDescriptor) + creatorDescriptor.kind().typeName();
+ }
+
+ private static ImmutableMap<ComponentDescriptor, String> namesByDescriptor(BindingGraph graph) {
+ ImmutableListMultimap<String, ComponentDescriptor> componentDescriptorsBySimpleName =
+ Multimaps.index(
+ graph.componentDescriptors(),
+ componentDescriptor -> componentDescriptor.typeElement().getSimpleName().toString());
+ ImmutableMap<ComponentDescriptor, Namer> componentNamers =
+ qualifiedNames(graph.componentDescriptors());
+ Map<ComponentDescriptor, String> subcomponentImplSimpleNames = new LinkedHashMap<>();
+ componentDescriptorsBySimpleName
+ .asMap()
+ .values()
+ .forEach(
+ components ->
+ subcomponentImplSimpleNames.putAll(
+ disambiguateConflictingSimpleNames(components, componentNamers)));
+ subcomponentImplSimpleNames.remove(graph.componentDescriptor());
+ return ImmutableMap.copyOf(subcomponentImplSimpleNames);
+ }
+
+ private static ImmutableMap<Key, ComponentDescriptor> descriptorsByCreatorKey(
+ KeyFactory keyFactory, ImmutableSet<ComponentDescriptor> subcomponents) {
+ return subcomponents.stream()
+ .filter(subcomponent -> subcomponent.creatorDescriptor().isPresent())
+ .collect(
+ toImmutableMap(
+ subcomponent ->
+ keyFactory.forSubcomponentCreator(
+ subcomponent.creatorDescriptor().get().typeElement().asType()),
+ subcomponent -> subcomponent));
+ }
+
+ private static ImmutableBiMap<ComponentDescriptor, String> disambiguateConflictingSimpleNames(
+ Collection<ComponentDescriptor> components,
+ ImmutableMap<ComponentDescriptor, Namer> componentNamers) {
+ Map<String, ComponentDescriptor> generatedSimpleNames = new LinkedHashMap<>();
+
+ // Let's see if we can get away with using simpleName() everywhere.
+ for (ComponentDescriptor component : components) {
+ Namer namer = componentNamers.get(component);
+ if (generatedSimpleNames.containsKey(namer.simpleName())) {
+ break;
+ }
+ generatedSimpleNames.put(namer.simpleName(), component);
+ }
+
+ if (generatedSimpleNames.size() != components.size()) {
+ // Simple approach didn't work out, let's use more complicated names.
+ // We keep them small to fix https://github.com/google/dagger/issues/421.
+ generatedSimpleNames.clear();
+ UniqueNameSet nameSet = new UniqueNameSet();
+ for (ComponentDescriptor component : components) {
+ Namer namer = componentNamers.get(component);
+ String simpleName = namer.simpleName();
+ String basePrefix = namer.uniquingPrefix();
+ generatedSimpleNames.put(
+ format("%s_%s", nameSet.getUniqueName(basePrefix), simpleName), component);
+ }
+ }
+ return ImmutableBiMap.copyOf(generatedSimpleNames).inverse();
+ }
+
+ private static ImmutableMap<ComponentDescriptor, Namer> qualifiedNames(
+ Iterable<ComponentDescriptor> componentDescriptors) {
+ ImmutableMap.Builder<ComponentDescriptor, Namer> builder = ImmutableMap.builder();
+ for (ComponentDescriptor component : componentDescriptors) {
+ builder.put(component, new Namer(component.typeElement()));
+ }
+ return builder.build();
+ }
+
+ private static final class Namer {
+ final TypeElement typeElement;
+
+ Namer(TypeElement typeElement) {
+ this.typeElement = typeElement;
+ }
+
+ String simpleName() {
+ return typeElement.getSimpleName().toString();
+ }
+
+ /** Returns a prefix that could make {@link #simpleName()} more unique. */
+ String uniquingPrefix() {
+ String containerName = typeElement.getEnclosingElement().getSimpleName().toString();
+
+ // If parent element looks like a class, use its initials as a prefix.
+ if (!containerName.isEmpty() && isUpperCase(containerName.charAt(0))) {
+ return CharMatcher.javaLowerCase().removeFrom(containerName);
+ }
+
+ // Not in a normally named class. Prefix with the initials of the elements leading here.
+ Name qualifiedName = typeElement.getQualifiedName();
+ Iterator<String> pieces = QUALIFIED_NAME_SPLITTER.split(qualifiedName).iterator();
+ StringBuilder b = new StringBuilder();
+
+ while (pieces.hasNext()) {
+ String next = pieces.next();
+ if (pieces.hasNext()) {
+ b.append(next.charAt(0));
+ }
+ }
+
+ // Note that a top level class in the root package will be prefixed "$_".
+ return b.length() > 0 ? b.toString() : "$";
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/SwitchingProviders.java b/java/dagger/internal/codegen/SwitchingProviders.java
new file mode 100644
index 0000000..29633d9
--- /dev/null
+++ b/java/dagger/internal/codegen/SwitchingProviders.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getLast;
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.squareup.javapoet.MethodSpec.methodBuilder;
+import static com.squareup.javapoet.TypeSpec.classBuilder;
+import static dagger.internal.codegen.DaggerStreams.toImmutableList;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
+import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
+import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.TypeVariableName;
+import dagger.internal.codegen.javapoet.CodeBlocks;
+import dagger.internal.codegen.javapoet.Expression;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.model.Key;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Keeps track of all provider expression requests for a component.
+ *
+ * <p>The provider expression request will be satisfied by a single generated {@code Provider} inner
+ * class that can provide instances for all types by switching on an id.
+ */
+// TODO(ronshapiro): either merge this with InnerSwitchingProviders, or repurpose this for
+// SwitchingProducers
+abstract class SwitchingProviders {
+ /**
+ * Defines the {@linkplain Expression expressions} for a switch case in a {@code SwitchProvider}
+ * for a particular binding.
+ */
+ // TODO(user): Consider handling SwitchingProviders with dependency arguments in this class,
+ // then we wouldn't need the getProviderExpression method.
+ // TODO(user): Consider making this an abstract class with equals/hashCode defined by the key
+ // and then using this class directly in Map types instead of Key.
+ interface SwitchCase {
+ /** Returns the {@link Key} for this switch case. */
+ Key key();
+
+ /** Returns the {@link Expression} that returns the provided instance for this case. */
+ Expression getReturnExpression(ClassName switchingProviderClass);
+
+ /**
+ * Returns the {@link Expression} that returns the {@code SwitchProvider} instance for this
+ * case.
+ */
+ Expression getProviderExpression(ClassName switchingProviderClass, int switchId);
+ }
+
+ /**
+ * Each switch size is fixed at 100 cases each and put in its own method. This is to limit the
+ * size of the methods so that we don't reach the "huge" method size limit for Android that will
+ * prevent it from being AOT compiled in some versions of Android (b/77652521). This generally
+ * starts to happen around 1500 cases, but we are choosing 100 to be safe.
+ */
+ // TODO(user): Include a proguard_spec in the Dagger library to prevent inlining these methods?
+ // TODO(ronshapiro): Consider making this configurable via a flag.
+ private static final int MAX_CASES_PER_SWITCH = 100;
+
+ private static final long MAX_CASES_PER_CLASS = MAX_CASES_PER_SWITCH * MAX_CASES_PER_SWITCH;
+ private static final TypeVariableName T = TypeVariableName.get("T");
+
+ /**
+ * Maps a {@link Key} to an instance of a {@link SwitchingProviderBuilder}. Each group of {@code
+ * MAX_CASES_PER_CLASS} keys will share the same instance.
+ */
+ private final Map<Key, SwitchingProviderBuilder> switchingProviderBuilders =
+ new LinkedHashMap<>();
+
+ private final ComponentImplementation componentImplementation;
+ private final ClassName owningComponent;
+ private final DaggerTypes types;
+ private final UniqueNameSet switchingProviderNames = new UniqueNameSet();
+
+ SwitchingProviders(ComponentImplementation componentImplementation, DaggerTypes types) {
+ this.componentImplementation = checkNotNull(componentImplementation);
+ this.types = checkNotNull(types);
+ this.owningComponent = checkNotNull(componentImplementation).name();
+ }
+
+ /** Returns the {@link TypeSpec} for a {@code SwitchingProvider} based on the given builder. */
+ protected abstract TypeSpec createSwitchingProviderType(TypeSpec.Builder builder);
+
+ /**
+ * Returns the {@link Expression} that returns the {@code SwitchProvider} instance for the case.
+ */
+ protected final Expression getProviderExpression(SwitchCase switchCase) {
+ return switchingProviderBuilders
+ .computeIfAbsent(switchCase.key(), key -> getSwitchingProviderBuilder())
+ .getProviderExpression(switchCase);
+ }
+
+ private SwitchingProviderBuilder getSwitchingProviderBuilder() {
+ if (switchingProviderBuilders.size() % MAX_CASES_PER_CLASS == 0) {
+ String name = switchingProviderNames.getUniqueName("SwitchingProvider");
+ SwitchingProviderBuilder switchingProviderBuilder =
+ new SwitchingProviderBuilder(owningComponent.nestedClass(name));
+ componentImplementation.addSwitchingProvider(switchingProviderBuilder::build);
+ return switchingProviderBuilder;
+ }
+ return getLast(switchingProviderBuilders.values());
+ }
+
+ // TODO(user): Consider just merging this class with SwitchingProviders.
+ private final class SwitchingProviderBuilder {
+ // Keep the switch cases ordered by switch id. The switch Ids are assigned in pre-order
+ // traversal, but the switch cases are assigned in post-order traversal of the binding graph.
+ private final Map<Integer, CodeBlock> switchCases = new TreeMap<>();
+ private final Map<Key, Integer> switchIds = new HashMap<>();
+ private final ClassName switchingProviderType;
+
+ SwitchingProviderBuilder(ClassName switchingProviderType) {
+ this.switchingProviderType = checkNotNull(switchingProviderType);
+ }
+
+ Expression getProviderExpression(SwitchCase switchCase) {
+ Key key = switchCase.key();
+ if (!switchIds.containsKey(key)) {
+ int switchId = switchIds.size();
+ switchIds.put(key, switchId);
+ switchCases.put(switchId, createSwitchCaseCodeBlock(switchCase));
+ }
+ return switchCase.getProviderExpression(switchingProviderType, switchIds.get(key));
+ }
+
+ private CodeBlock createSwitchCaseCodeBlock(SwitchCase switchCase) {
+ CodeBlock instanceCodeBlock =
+ switchCase.getReturnExpression(switchingProviderType).box(types).codeBlock();
+
+ return CodeBlock.builder()
+ // TODO(user): Is there something else more useful than the key?
+ .add("case $L: // $L \n", switchIds.get(switchCase.key()), switchCase.key())
+ .addStatement("return ($T) $L", T, instanceCodeBlock)
+ .build();
+ }
+
+ private TypeSpec build() {
+ return createSwitchingProviderType(
+ classBuilder(switchingProviderType)
+ .addTypeVariable(T)
+ .addSuperinterface(providerOf(T))
+ .addMethods(getMethods()));
+ }
+
+ private ImmutableList<MethodSpec> getMethods() {
+ ImmutableList<CodeBlock> switchCodeBlockPartitions = switchCodeBlockPartitions();
+ if (switchCodeBlockPartitions.size() == 1) {
+ // There are less than MAX_CASES_PER_SWITCH cases, so no need for extra get methods.
+ return ImmutableList.of(
+ methodBuilder("get")
+ .addModifiers(PUBLIC)
+ .addAnnotation(suppressWarnings(UNCHECKED))
+ .addAnnotation(Override.class)
+ .returns(T)
+ .addCode(getOnlyElement(switchCodeBlockPartitions))
+ .build());
+ }
+
+ // This is the main public "get" method that will route to private getter methods.
+ MethodSpec.Builder routerMethod =
+ methodBuilder("get")
+ .addModifiers(PUBLIC)
+ .addAnnotation(Override.class)
+ .returns(T)
+ .beginControlFlow("switch (id / $L)", MAX_CASES_PER_SWITCH);
+
+ ImmutableList.Builder<MethodSpec> getMethods = ImmutableList.builder();
+ for (int i = 0; i < switchCodeBlockPartitions.size(); i++) {
+ MethodSpec method =
+ methodBuilder("get" + i)
+ .addModifiers(PRIVATE)
+ .addAnnotation(suppressWarnings(UNCHECKED))
+ .returns(T)
+ .addCode(switchCodeBlockPartitions.get(i))
+ .build();
+ getMethods.add(method);
+ routerMethod.addStatement("case $L: return $N()", i, method);
+ }
+
+ routerMethod.addStatement("default: throw new $T(id)", AssertionError.class).endControlFlow();
+
+ return getMethods.add(routerMethod.build()).build();
+ }
+
+ private ImmutableList<CodeBlock> switchCodeBlockPartitions() {
+ return Lists.partition(ImmutableList.copyOf(switchCases.values()), MAX_CASES_PER_SWITCH)
+ .stream()
+ .map(
+ partitionCases ->
+ CodeBlock.builder()
+ .beginControlFlow("switch (id)")
+ .add(CodeBlocks.concat(partitionCases))
+ .addStatement("default: throw new $T(id)", AssertionError.class)
+ .endControlFlow()
+ .build())
+ .collect(toImmutableList());
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/SystemComponentsModule.java b/java/dagger/internal/codegen/SystemComponentsModule.java
new file mode 100644
index 0000000..3f59b24
--- /dev/null
+++ b/java/dagger/internal/codegen/SystemComponentsModule.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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 com.google.common.base.Ticker;
+import dagger.Module;
+import dagger.Provides;
+
+/** Module to provide system-level dependencies (such as time-related objects). */
+@Module
+interface SystemComponentsModule {
+
+ @Provides
+ static Ticker ticker() {
+ return Ticker.systemTicker();
+ }
+}
diff --git a/java/dagger/internal/codegen/TopLevel.java b/java/dagger/internal/codegen/TopLevel.java
new file mode 100644
index 0000000..4f456f2
--- /dev/null
+++ b/java/dagger/internal/codegen/TopLevel.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import javax.inject.Qualifier;
+
+/**
+ * A {@link Qualifier} for bindings that are associated with the top level component implementation.
+ */
+@Retention(RUNTIME)
+@Qualifier
+@interface TopLevel {}
diff --git a/java/dagger/internal/codegen/TopLevelImplementationComponent.java b/java/dagger/internal/codegen/TopLevelImplementationComponent.java
new file mode 100644
index 0000000..306c05d
--- /dev/null
+++ b/java/dagger/internal/codegen/TopLevelImplementationComponent.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 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 dagger.BindsInstance;
+import dagger.Module;
+import dagger.Subcomponent;
+
+/**
+ * A shared subcomponent for a top-level {@link ComponentImplementation} and any nested child
+ * implementations.
+ */
+@PerGeneratedFile
+@Subcomponent
+interface TopLevelImplementationComponent {
+ CurrentImplementationSubcomponent.Builder currentImplementationSubcomponentBuilder();
+
+ @Subcomponent.Builder
+ interface Builder {
+ @BindsInstance
+ Builder topLevelComponent(@TopLevel ComponentImplementation topLevelImplementation);
+ TopLevelImplementationComponent build();
+ }
+
+ @Module(subcomponents = TopLevelImplementationComponent.class)
+ interface InstallationModule {}
+}
diff --git a/java/dagger/internal/codegen/TypeCheckingProcessingStep.java b/java/dagger/internal/codegen/TypeCheckingProcessingStep.java
new file mode 100644
index 0000000..00769b2
--- /dev/null
+++ b/java/dagger/internal/codegen/TypeCheckingProcessingStep.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
+import java.lang.annotation.Annotation;
+import java.util.function.Function;
+import javax.lang.model.element.Element;
+
+/**
+ * A {@link ProcessingStep} that processes one element at a time and defers any for which {@link
+ * TypeNotPresentException} is thrown.
+ */
+// TODO(dpb): Contribute to auto-common.
+abstract class TypeCheckingProcessingStep<E extends Element> implements ProcessingStep {
+ private final Function<Element, E> downcaster;
+
+ TypeCheckingProcessingStep(Function<Element, E> downcaster) {
+ this.downcaster = checkNotNull(downcaster);
+ }
+
+ @Override
+ public ImmutableSet<Element> process(
+ SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+ ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
+ ImmutableSetMultimap.copyOf(elementsByAnnotation)
+ .inverse()
+ .asMap()
+ .forEach(
+ (element, annotations) -> {
+ try {
+ process(downcaster.apply(element), ImmutableSet.copyOf(annotations));
+ } catch (TypeNotPresentException e) {
+ deferredElements.add(element);
+ }
+ });
+ return deferredElements.build();
+ }
+
+ /**
+ * Processes one element. If this method throws {@link TypeNotPresentException}, the element will
+ * be deferred until the next round of processing.
+ *
+ * @param annotations the subset of {@link ProcessingStep#annotations()} that annotate {@code
+ * element}
+ */
+ protected abstract void process(E element, ImmutableSet<Class<? extends Annotation>> annotations);
+}
diff --git a/java/dagger/internal/codegen/TypeProtoConverter.java b/java/dagger/internal/codegen/TypeProtoConverter.java
new file mode 100644
index 0000000..c703bd8
--- /dev/null
+++ b/java/dagger/internal/codegen/TypeProtoConverter.java
@@ -0,0 +1,122 @@
+/*
+ * 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.internal.codegen;
+
+import static javax.lang.model.util.ElementFilter.typesIn;
+
+import com.google.auto.common.MoreTypes;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.serialization.TypeProto;
+import dagger.internal.codegen.serialization.TypeProto.PrimitiveKind;
+import javax.inject.Inject;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.WildcardType;
+
+/** Converts {@link TypeMirror}s to {@link TypeProto}s and vice-versa. */
+final class TypeProtoConverter {
+ // TODO(ronshapiro): if DaggerTypes and DaggerElements become public, move this file to
+ // dagger.internal.codegen.serialization
+ private final DaggerTypes types;
+ private final DaggerElements elements;
+
+ @Inject
+ TypeProtoConverter(DaggerTypes types, DaggerElements elements) {
+ this.types = types;
+ this.elements = elements;
+ }
+
+ /** Translates a {@link TypeMirror} to a proto representation. */
+ static TypeProto toProto(TypeMirror type) {
+ TypeProto.Builder builder = TypeProto.newBuilder();
+ int arrayDimensions = 0;
+ while (type.getKind().equals(TypeKind.ARRAY)) {
+ type = MoreTypes.asArray(type).getComponentType();
+ arrayDimensions++;
+ }
+ builder.setArrayDimensions(arrayDimensions);
+ if (type.getKind().isPrimitive()) {
+ builder.setPrimitiveKind(PrimitiveKind.valueOf(type.getKind().name()));
+ } else if (type.getKind().equals(TypeKind.WILDCARD)) {
+ WildcardType wildcardType = MoreTypes.asWildcard(type);
+ TypeProto.Wildcard.Builder wildcardBuilder = TypeProto.Wildcard.newBuilder();
+ if (wildcardType.getExtendsBound() != null) {
+ wildcardBuilder.setExtendsBound(toProto(wildcardType.getExtendsBound()));
+ } else if (wildcardType.getSuperBound() != null) {
+ wildcardBuilder.setSuperBound(toProto(wildcardType.getSuperBound()));
+ }
+ builder.setWildcard(wildcardBuilder);
+ } else {
+ TypeElement typeElement = MoreTypes.asTypeElement(type);
+ DeclaredType declaredType = MoreTypes.asDeclared(type);
+ TypeMirror enclosingType = declaredType.getEnclosingType();
+ if (enclosingType.getKind().equals(TypeKind.NONE)) {
+ builder.setQualifiedName(typeElement.getQualifiedName().toString());
+ } else {
+ builder
+ .setEnclosingType(toProto(enclosingType))
+ .setSimpleName(typeElement.getSimpleName().toString());
+ }
+ declaredType.getTypeArguments().stream()
+ .map(TypeProtoConverter::toProto)
+ .forEachOrdered(builder::addTypeArguments);
+ }
+ return builder.build();
+ }
+
+ /** Creates an {@link TypeMirror} from its proto representation. */
+ TypeMirror fromProto(TypeProto type) {
+ if (type.hasWildcard()) {
+ return wildcardType(type.getWildcard());
+ }
+
+ TypeMirror[] typeArguments =
+ type.getTypeArgumentsList().stream().map(this::fromProto).toArray(TypeMirror[]::new);
+ TypeMirror typeMirror;
+ if (!type.getPrimitiveKind().equals(PrimitiveKind.UNKNOWN)) {
+ typeMirror = types.getPrimitiveType(TypeKind.valueOf(type.getPrimitiveKind().name()));
+ } else if (type.hasEnclosingType()) {
+ DeclaredType enclosingType = MoreTypes.asDeclared(fromProto(type.getEnclosingType()));
+ TypeElement typeElement =
+ typesIn(enclosingType.asElement().getEnclosedElements()).stream()
+ .filter(inner -> inner.getSimpleName().contentEquals(type.getSimpleName()))
+ .findFirst()
+ .get();
+ typeMirror = types.getDeclaredType(enclosingType, typeElement, typeArguments);
+ } else {
+ typeMirror =
+ types.getDeclaredType(elements.getTypeElement(type.getQualifiedName()), typeArguments);
+ }
+ for (int i = 0; i < type.getArrayDimensions(); i++) {
+ typeMirror = types.getArrayType(typeMirror);
+ }
+ return typeMirror;
+ }
+
+ private TypeMirror wildcardType(TypeProto.Wildcard wildcard) {
+ if (wildcard.hasExtendsBound()) {
+ return types.getWildcardType(fromProto(wildcard.getExtendsBound()), null);
+ } else if (wildcard.hasSuperBound()) {
+ return types.getWildcardType(null, fromProto(wildcard.getSuperBound()));
+ } else {
+ return types.getWildcardType(null, null);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/UniqueNameSet.java b/java/dagger/internal/codegen/UniqueNameSet.java
new file mode 100644
index 0000000..11c48b3
--- /dev/null
+++ b/java/dagger/internal/codegen/UniqueNameSet.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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 java.util.HashSet;
+import java.util.Set;
+
+/** A collector for names to be used in the same namespace that should not conflict. */
+final class UniqueNameSet {
+ private final Set<String> uniqueNames = new HashSet<>();
+
+ /**
+ * Generates a unique name using {@code base}. If {@code base} has not yet been added, it will be
+ * returned as-is. If your {@code base} is healthy, this will always return {@code base}.
+ */
+ String getUniqueName(CharSequence base) {
+ String name = base.toString();
+ for (int differentiator = 2; !uniqueNames.add(name); differentiator++) {
+ name = base.toString() + differentiator;
+ }
+ return name;
+ }
+
+ /**
+ * Adds {@code name} without any modification to the name set. Has no effect if {@code name} is
+ * already present in the set.
+ */
+ void claim(CharSequence name) {
+ uniqueNames.add(name.toString());
+ }
+}
diff --git a/java/dagger/internal/codegen/UnwrappedMapKeyGenerator.java b/java/dagger/internal/codegen/UnwrappedMapKeyGenerator.java
new file mode 100644
index 0000000..2b7b02c
--- /dev/null
+++ b/java/dagger/internal/codegen/UnwrappedMapKeyGenerator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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 dagger.MapKey;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import java.util.Set;
+import javax.annotation.processing.Filer;
+import javax.inject.Inject;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Generates classes that create annotation instances for an unwrapped {@link MapKey} annotation
+ * type whose nested value is an annotation. The generated class will have a private empty
+ * constructor and a static method that creates each annotation type that is nested in the top-level
+ * annotation type.
+ *
+ * <p>So for an example {@link MapKey} annotation:
+ *
+ * <pre>
+ * {@literal @MapKey}(unwrapValue = true)
+ * {@literal @interface} Foo {
+ * Bar bar();
+ * }
+ *
+ * {@literal @interface} Bar {
+ * {@literal Class<?> baz();}
+ * }
+ * </pre>
+ *
+ * the generated class will look like:
+ *
+ * <pre>
+ * public final class FooCreator {
+ * private FooCreator() {}
+ *
+ * public static Bar createBar({@literal Class<?> baz}) { … }
+ * }
+ * </pre>
+ */
+final class UnwrappedMapKeyGenerator extends AnnotationCreatorGenerator {
+
+ @Inject
+ UnwrappedMapKeyGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
+ super(filer, elements, sourceVersion);
+ }
+
+ @Override
+ protected Set<TypeElement> annotationsToCreate(TypeElement annotationElement) {
+ Set<TypeElement> nestedAnnotationElements = super.annotationsToCreate(annotationElement);
+ nestedAnnotationElements.remove(annotationElement);
+ return nestedAnnotationElements;
+ }
+}
diff --git a/java/dagger/internal/codegen/Util.java b/java/dagger/internal/codegen/Util.java
new file mode 100644
index 0000000..1869b7c
--- /dev/null
+++ b/java/dagger/internal/codegen/Util.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 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 javax.lang.model.element.ElementKind.CONSTRUCTOR;
+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 java.util.Map;
+import java.util.function.Function;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Utilities for handling types in annotation processors
+ */
+final class Util {
+ /**
+ * Returns true if and only if a component can instantiate new instances (typically of a module)
+ * rather than requiring that they be passed.
+ */
+ static boolean componentCanMakeNewInstances(TypeElement typeElement) {
+ switch (typeElement.getKind()) {
+ case CLASS:
+ break;
+ case ENUM:
+ case ANNOTATION_TYPE:
+ case INTERFACE:
+ return false;
+ default:
+ throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind());
+ }
+
+ if (typeElement.getModifiers().contains(ABSTRACT)) {
+ return false;
+ }
+
+ if (requiresEnclosingInstance(typeElement)) {
+ return false;
+ }
+
+ for (Element enclosed : typeElement.getEnclosedElements()) {
+ if (enclosed.getKind().equals(CONSTRUCTOR)
+ && ((ExecutableElement) enclosed).getParameters().isEmpty()
+ && !enclosed.getModifiers().contains(PRIVATE)) {
+ return true;
+ }
+ }
+
+ // TODO(gak): still need checks for visibility
+
+ return false;
+ }
+
+ private static boolean requiresEnclosingInstance(TypeElement typeElement) {
+ switch (typeElement.getNestingKind()) {
+ case TOP_LEVEL:
+ return false;
+ case MEMBER:
+ return !typeElement.getModifiers().contains(STATIC);
+ case ANONYMOUS:
+ case LOCAL:
+ return true;
+ }
+ throw new AssertionError(
+ "TypeElement cannot have nesting kind: " + typeElement.getNestingKind());
+ }
+
+ /**
+ * A version of {@link Map#computeIfAbsent(Object, Function)} that allows {@code mappingFunction}
+ * to update {@code map}.
+ */
+ static <K, V> V reentrantComputeIfAbsent(
+ Map<K, V> map, K key, Function<? super K, ? extends V> mappingFunction) {
+ V value = map.get(key);
+ if (value == null) {
+ value = mappingFunction.apply(key);
+ if (value != null) {
+ map.put(key, value);
+ }
+ }
+ return value;
+ }
+
+ private Util() {}
+}
diff --git a/java/dagger/internal/codegen/Validation.java b/java/dagger/internal/codegen/Validation.java
new file mode 100644
index 0000000..f6a4b3f
--- /dev/null
+++ b/java/dagger/internal/codegen/Validation.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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 java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.inject.Qualifier;
+
+/**
+ * Qualifier annotation for the {@link dagger.spi.BindingGraphPlugin}s that are used to implement
+ * core Dagger validation.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+@interface Validation {}
diff --git a/java/dagger/internal/codegen/ValidationReport.java b/java/dagger/internal/codegen/ValidationReport.java
new file mode 100644
index 0000000..d7c3252
--- /dev/null
+++ b/java/dagger/internal/codegen/ValidationReport.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2014 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 dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.ElementFormatter.elementToString;
+import static javax.tools.Diagnostic.Kind.ERROR;
+import static javax.tools.Diagnostic.Kind.NOTE;
+import static javax.tools.Diagnostic.Kind.WARNING;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.graph.Traverser;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import com.google.errorprone.annotations.CheckReturnValue;
+import java.util.Optional;
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.tools.Diagnostic;
+import javax.tools.Diagnostic.Kind;
+
+/** A collection of issues to report for source code. */
+@AutoValue
+abstract class ValidationReport<T extends Element> {
+
+ /**
+ * The subject of the report. Should be an element within a compilation unit being processed by
+ * this compilation task.
+ */
+ abstract T subject();
+
+ /** The items to report for the {@linkplain #subject() subject}. */
+ abstract ImmutableSet<Item> items();
+
+ /** Returns the {@link #items()} from this report and all transitive subreports. */
+ ImmutableSet<Item> allItems() {
+ return allReports()
+ .stream()
+ .flatMap(report -> report.items().stream())
+ .collect(toImmutableSet());
+ }
+
+ /** Other reports associated with this one. */
+ abstract ImmutableSet<ValidationReport<?>> subreports();
+
+ private static final Traverser<ValidationReport<?>> SUBREPORTS =
+ Traverser.forTree(ValidationReport::subreports);
+
+ /** Returns this report and all transitive subreports. */
+ ImmutableSet<ValidationReport<?>> allReports() {
+ return ImmutableSet.copyOf(SUBREPORTS.depthFirstPreOrder(this));
+ }
+
+ /**
+ * {@code true} if {@link #isClean()} should return {@code false} even if there are no error items
+ * in this report.
+ */
+ abstract boolean markedDirty();
+
+ /**
+ * Returns {@code true} if there are no errors in this report or any subreports and {@link
+ * #markedDirty()} is {@code false}.
+ */
+ boolean isClean() {
+ if (markedDirty()) {
+ return false;
+ }
+ for (Item item : items()) {
+ switch (item.kind()) {
+ case ERROR:
+ return false;
+ default:
+ break;
+ }
+ }
+ for (ValidationReport<?> subreport : subreports()) {
+ if (!subreport.isClean()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Prints all {@linkplain #items() messages} to {@code messager} (and recurs for subreports). If a
+ * message's {@linkplain Item#element() element} is contained within the report's {@linkplain
+ * #subject() subject}, associates the message with the message's element. Otherwise, since
+ * {@link Diagnostic} reporting is expected to be associated with elements that are currently
+ * being compiled, associates the message with the subject itself and prepends a reference to the
+ * item's element.
+ */
+ void printMessagesTo(Messager messager) {
+ for (Item item : items()) {
+ if (isEnclosedIn(subject(), item.element())) {
+ if (item.annotation().isPresent()) {
+ if (item.annotationValue().isPresent()) {
+ messager.printMessage(
+ item.kind(),
+ item.message(),
+ item.element(),
+ item.annotation().get(),
+ item.annotationValue().get());
+ } else {
+ messager.printMessage(
+ item.kind(), item.message(), item.element(), item.annotation().get());
+ }
+ } else {
+ messager.printMessage(item.kind(), item.message(), item.element());
+ }
+ } else {
+ String message = String.format("[%s] %s", elementToString(item.element()), item.message());
+ messager.printMessage(item.kind(), message, subject());
+ }
+ }
+ for (ValidationReport<?> subreport : subreports()) {
+ subreport.printMessagesTo(messager);
+ }
+ }
+
+ private static boolean isEnclosedIn(Element parent, Element child) {
+ Element current = child;
+ while (current != null) {
+ if (current.equals(parent)) {
+ return true;
+ }
+ current = current.getEnclosingElement();
+ }
+ return false;
+ }
+
+ @AutoValue
+ static abstract class Item {
+ abstract String message();
+ abstract Kind kind();
+ abstract Element element();
+ abstract Optional<AnnotationMirror> annotation();
+ abstract Optional<AnnotationValue> annotationValue();
+ }
+
+ static <T extends Element> Builder<T> about(T subject) {
+ return new Builder<>(subject);
+ }
+
+ @CanIgnoreReturnValue
+ static final class Builder<T extends Element> {
+ private final T subject;
+ private final ImmutableSet.Builder<Item> items = ImmutableSet.builder();
+ private final ImmutableSet.Builder<ValidationReport<?>> subreports = ImmutableSet.builder();
+ private boolean markedDirty;
+
+ private Builder(T subject) {
+ this.subject = subject;
+ }
+
+ @CheckReturnValue
+ T getSubject() {
+ return subject;
+ }
+
+ Builder<T> addItems(Iterable<Item> newItems) {
+ items.addAll(newItems);
+ return this;
+ }
+
+ Builder<T> addError(String message) {
+ return addError(message, subject);
+ }
+
+ Builder<T> addError(String message, Element element) {
+ return addItem(message, ERROR, element);
+ }
+
+ Builder<T> addError(String message, Element element, AnnotationMirror annotation) {
+ return addItem(message, ERROR, element, annotation);
+ }
+
+ Builder<T> addError(
+ String message,
+ Element element,
+ AnnotationMirror annotation,
+ AnnotationValue annotationValue) {
+ return addItem(message, ERROR, element, annotation, annotationValue);
+ }
+
+ Builder<T> addWarning(String message) {
+ return addWarning(message, subject);
+ }
+
+ Builder<T> addWarning(String message, Element element) {
+ return addItem(message, WARNING, element);
+ }
+
+ Builder<T> addWarning(String message, Element element, AnnotationMirror annotation) {
+ return addItem(message, WARNING, element, annotation);
+ }
+
+ Builder<T> addWarning(
+ String message,
+ Element element,
+ AnnotationMirror annotation,
+ AnnotationValue annotationValue) {
+ return addItem(message, WARNING, element, annotation, annotationValue);
+ }
+
+ Builder<T> addNote(String message) {
+ return addNote(message, subject);
+ }
+
+ Builder<T> addNote(String message, Element element) {
+ return addItem(message, NOTE, element);
+ }
+
+ Builder<T> addNote(String message, Element element, AnnotationMirror annotation) {
+ return addItem(message, NOTE, element, annotation);
+ }
+
+ Builder<T> addNote(
+ String message,
+ Element element,
+ AnnotationMirror annotation,
+ AnnotationValue annotationValue) {
+ return addItem(message, NOTE, element, annotation, annotationValue);
+ }
+
+ Builder<T> addItem(String message, Kind kind, Element element) {
+ return addItem(message, kind, element, Optional.empty(), Optional.empty());
+ }
+
+ Builder<T> addItem(String message, Kind kind, Element element, AnnotationMirror annotation) {
+ return addItem(message, kind, element, Optional.of(annotation), Optional.empty());
+ }
+
+ Builder<T> addItem(
+ String message,
+ Kind kind,
+ Element element,
+ AnnotationMirror annotation,
+ AnnotationValue annotationValue) {
+ return addItem(message, kind, element, Optional.of(annotation), Optional.of(annotationValue));
+ }
+
+ private Builder<T> addItem(
+ String message,
+ Kind kind,
+ Element element,
+ Optional<AnnotationMirror> annotation,
+ Optional<AnnotationValue> annotationValue) {
+ items.add(
+ new AutoValue_ValidationReport_Item(message, kind, element, annotation, annotationValue));
+ return this;
+ }
+
+ /**
+ * If called, then {@link #isClean()} will return {@code false} even if there are no error items
+ * in the report.
+ */
+ void markDirty() {
+ this.markedDirty = true;
+ }
+
+ Builder<T> addSubreport(ValidationReport<?> subreport) {
+ subreports.add(subreport);
+ return this;
+ }
+
+ @CheckReturnValue
+ ValidationReport<T> build() {
+ return new AutoValue_ValidationReport<>(
+ subject, items.build(), subreports.build(), markedDirty);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/ValidationType.java b/java/dagger/internal/codegen/ValidationType.java
new file mode 100644
index 0000000..5d19dc1
--- /dev/null
+++ b/java/dagger/internal/codegen/ValidationType.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Dagger Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dagger.internal.codegen;
+
+import java.util.Optional;
+import javax.tools.Diagnostic;
+
+/**
+ * Allows options to control how component process validates things such as scope cycles
+ * or nullability.
+ */
+enum ValidationType {
+ ERROR,
+ WARNING,
+ NONE;
+
+ Optional<Diagnostic.Kind> diagnosticKind() {
+ switch (this) {
+ case ERROR:
+ return Optional.of(Diagnostic.Kind.ERROR);
+ case WARNING:
+ return Optional.of(Diagnostic.Kind.WARNING);
+ default:
+ return Optional.empty();
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/base/BUILD b/java/dagger/internal/codegen/base/BUILD
deleted file mode 100644
index 0bcbb12..0000000
--- a/java/dagger/internal/codegen/base/BUILD
+++ /dev/null
@@ -1,66 +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.
-
-# Description:
-# Sources related to compiler options.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-SHARED_SOURCES = [
- "ClearableCache.java",
- "MoreAnnotationMirrors.java",
- "MoreAnnotationValues.java",
-]
-
-java_library(
- name = "base",
- srcs = glob(
- ["*.java"],
- exclude = SHARED_SOURCES,
- ),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- exports = [":shared"],
- deps = [
- ":shared",
- "//java/dagger:core",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-# TODO(bcorso): Remove this target but first remove spi and producers from :base
-java_library(
- name = "shared",
- srcs = SHARED_SOURCES,
- tags = ["maven:merged"],
- deps = [
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/base/ClearableCache.java b/java/dagger/internal/codegen/base/ClearableCache.java
deleted file mode 100644
index 61e9482..0000000
--- a/java/dagger/internal/codegen/base/ClearableCache.java
+++ /dev/null
@@ -1,23 +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.internal.codegen.base;
-
-/** A cache of objects that can be cleared. */
-public interface ClearableCache {
- /** Releases cached references. */
- void clearCache();
-}
diff --git a/java/dagger/internal/codegen/base/ComponentAnnotation.java b/java/dagger/internal/codegen/base/ComponentAnnotation.java
deleted file mode 100644
index c9b3580..0000000
--- a/java/dagger/internal/codegen/base/ComponentAnnotation.java
+++ /dev/null
@@ -1,326 +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.internal.codegen.base;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asTypeElements;
-import static com.google.auto.common.MoreTypes.isTypeOf;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_MODULE;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
-
-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.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import dagger.Component;
-import dagger.Subcomponent;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A {@code @Component}, {@code @Subcomponent}, {@code @ProductionComponent}, or
- * {@code @ProductionSubcomponent} annotation, or a {@code @Module} or {@code @ProducerModule}
- * annotation that is being treated as a component annotation when validating full binding graphs
- * for modules.
- */
-public abstract class ComponentAnnotation {
- /** The root component annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> ROOT_COMPONENT_ANNOTATIONS =
- ImmutableSet.of(Component.class, ProductionComponent.class);
-
- /** The subcomponent annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_ANNOTATIONS =
- ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
-
- /** All component annotation types. */
- private static final ImmutableSet<Class<? extends Annotation>> ALL_COMPONENT_ANNOTATIONS =
- ImmutableSet.<Class<? extends Annotation>>builder()
- .addAll(ROOT_COMPONENT_ANNOTATIONS)
- .addAll(SUBCOMPONENT_ANNOTATIONS)
- .build();
-
- /** The annotation itself. */
- public abstract AnnotationMirror annotation();
-
- /** The simple name of the annotation type. */
- public String simpleName() {
- return MoreAnnotationMirrors.simpleName(annotation()).toString();
- }
-
- /**
- * Returns {@code true} if the annotation is a {@code @Subcomponent} or
- * {@code @ProductionSubcomponent}.
- */
- public abstract boolean isSubcomponent();
-
- /**
- * Returns {@code true} if the annotation is a {@code @ProductionComponent},
- * {@code @ProductionSubcomponent}, or {@code @ProducerModule}.
- */
- public abstract boolean isProduction();
-
- /**
- * Returns {@code true} if the annotation is a real component annotation and not a module
- * annotation.
- */
- public abstract boolean isRealComponent();
-
- /** The values listed as {@code dependencies}. */
- public abstract ImmutableList<AnnotationValue> dependencyValues();
-
- /** The types listed as {@code dependencies}. */
- public ImmutableList<TypeMirror> dependencyTypes() {
- return dependencyValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
- }
-
- /**
- * The types listed as {@code dependencies}.
- *
- * @throws IllegalArgumentException if any of {@link #dependencyTypes()} are error types
- */
- public ImmutableList<TypeElement> dependencies() {
- return asTypeElements(dependencyTypes()).asList();
- }
-
- /** The values listed as {@code modules}. */
- public abstract ImmutableList<AnnotationValue> moduleValues();
-
- /** The types listed as {@code modules}. */
- public ImmutableList<TypeMirror> moduleTypes() {
- return moduleValues().stream().map(MoreAnnotationValues::asType).collect(toImmutableList());
- }
-
- /**
- * The types listed as {@code modules}.
- *
- * @throws IllegalArgumentException if any of {@link #moduleTypes()} are error types
- */
- public ImmutableSet<TypeElement> modules() {
- return asTypeElements(moduleTypes());
- }
-
- protected final ImmutableList<AnnotationValue> getAnnotationValues(String parameterName) {
- return asAnnotationValues(getAnnotationValue(annotation(), parameterName));
- }
-
- /**
- * Returns an object representing a root component annotation, not a subcomponent annotation, if
- * one is present on {@code typeElement}.
- */
- public static Optional<ComponentAnnotation> rootComponentAnnotation(TypeElement typeElement) {
- return anyComponentAnnotation(typeElement, ROOT_COMPONENT_ANNOTATIONS);
- }
-
- /**
- * Returns an object representing a subcomponent annotation, if one is present on {@code
- * typeElement}.
- */
- public static Optional<ComponentAnnotation> subcomponentAnnotation(TypeElement typeElement) {
- return anyComponentAnnotation(typeElement, SUBCOMPONENT_ANNOTATIONS);
- }
-
- /**
- * Returns an object representing a root component or subcomponent annotation, if one is present
- * on {@code typeElement}.
- */
- public static Optional<ComponentAnnotation> anyComponentAnnotation(TypeElement typeElement) {
- return anyComponentAnnotation(typeElement, ALL_COMPONENT_ANNOTATIONS);
- }
-
- private static Optional<ComponentAnnotation> anyComponentAnnotation(
- TypeElement typeElement, Collection<Class<? extends Annotation>> annotations) {
- return getAnyAnnotation(typeElement, annotations).map(ComponentAnnotation::componentAnnotation);
- }
-
- /** Returns {@code true} if the argument is a component annotation. */
- public static boolean isComponentAnnotation(AnnotationMirror annotation) {
- return ALL_COMPONENT_ANNOTATIONS.stream()
- .anyMatch(annotationClass -> isTypeOf(annotationClass, annotation.getAnnotationType()));
- }
-
- /** Creates an object representing a component or subcomponent annotation. */
- public static ComponentAnnotation componentAnnotation(AnnotationMirror annotation) {
- RealComponentAnnotation.Builder annotationBuilder =
- RealComponentAnnotation.builder().annotation(annotation);
-
- if (isTypeOf(Component.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(false).isSubcomponent(false).build();
- }
- if (isTypeOf(Subcomponent.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(false).isSubcomponent(true).build();
- }
- if (isTypeOf(ProductionComponent.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(true).isSubcomponent(false).build();
- }
- if (isTypeOf(ProductionSubcomponent.class, annotation.getAnnotationType())) {
- return annotationBuilder.isProduction(true).isSubcomponent(true).build();
- }
- throw new IllegalArgumentException(
- annotation
- + " must be a Component, Subcomponent, ProductionComponent, "
- + "or ProductionSubcomponent annotation");
- }
-
- /** Creates a fictional component annotation representing a module. */
- public static ComponentAnnotation fromModuleAnnotation(ModuleAnnotation moduleAnnotation) {
- return new AutoValue_ComponentAnnotation_FictionalComponentAnnotation(moduleAnnotation);
- }
-
- /** The root component annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> rootComponentAnnotations() {
- return ROOT_COMPONENT_ANNOTATIONS;
- }
-
- /** The subcomponent annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> subcomponentAnnotations() {
- return SUBCOMPONENT_ANNOTATIONS;
- }
-
- /** All component annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> allComponentAnnotations() {
- return ALL_COMPONENT_ANNOTATIONS;
- }
-
- /**
- * An actual component annotation.
- *
- * @see FictionalComponentAnnotation
- */
- @AutoValue
- abstract static class RealComponentAnnotation extends ComponentAnnotation {
-
- @Override
- @Memoized
- public ImmutableList<AnnotationValue> dependencyValues() {
- return isSubcomponent() ? ImmutableList.of() : getAnnotationValues("dependencies");
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeMirror> dependencyTypes() {
- return super.dependencyTypes();
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeElement> dependencies() {
- return super.dependencies();
- }
-
- @Override
- public boolean isRealComponent() {
- return true;
- }
-
- @Override
- @Memoized
- public ImmutableList<AnnotationValue> moduleValues() {
- return getAnnotationValues("modules");
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeMirror> moduleTypes() {
- return super.moduleTypes();
- }
-
- @Override
- @Memoized
- public ImmutableSet<TypeElement> modules() {
- return super.modules();
- }
-
- static Builder builder() {
- return new AutoValue_ComponentAnnotation_RealComponentAnnotation.Builder();
- }
-
- @AutoValue.Builder
- interface Builder {
- Builder annotation(AnnotationMirror annotation);
-
- Builder isSubcomponent(boolean isSubcomponent);
-
- Builder isProduction(boolean isProduction);
-
- RealComponentAnnotation build();
- }
- }
-
- /**
- * A fictional component annotation used to represent modules or other collections of bindings as
- * a component.
- */
- @AutoValue
- abstract static class FictionalComponentAnnotation extends ComponentAnnotation {
-
- @Override
- public AnnotationMirror annotation() {
- return moduleAnnotation().annotation();
- }
-
- @Override
- public boolean isSubcomponent() {
- return false;
- }
-
- @Override
- public boolean isProduction() {
- return ClassName.get(asType(moduleAnnotation().annotation().getAnnotationType().asElement()))
- .equals(PRODUCER_MODULE);
- }
-
- @Override
- public boolean isRealComponent() {
- return false;
- }
-
- @Override
- public ImmutableList<AnnotationValue> dependencyValues() {
- return ImmutableList.of();
- }
-
- @Override
- public ImmutableList<AnnotationValue> moduleValues() {
- return moduleAnnotation().includesAsAnnotationValues();
- }
-
- @Override
- @Memoized
- public ImmutableList<TypeMirror> moduleTypes() {
- return super.moduleTypes();
- }
-
- @Override
- @Memoized
- public ImmutableSet<TypeElement> modules() {
- return super.modules();
- }
-
- public abstract ModuleAnnotation moduleAnnotation();
- }
-}
diff --git a/java/dagger/internal/codegen/base/ContributionType.java b/java/dagger/internal/codegen/base/ContributionType.java
deleted file mode 100644
index c046daa..0000000
--- a/java/dagger/internal/codegen/base/ContributionType.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import javax.lang.model.element.Element;
-
-/** Whether a binding or declaration is for a unique contribution or a map or set multibinding. */
-public enum ContributionType {
- /** Represents map bindings. */
- MAP,
- /** Represents set bindings. */
- SET,
- /** Represents set values bindings. */
- SET_VALUES,
- /** Represents a valid non-collection binding. */
- UNIQUE,
- ;
-
- /** An object that is associated with a {@link ContributionType}. */
- public interface HasContributionType {
-
- /** The contribution type of this object. */
- ContributionType contributionType();
- }
-
- /** {@code true} if this is for a multibinding. */
- public boolean isMultibinding() {
- return !this.equals(UNIQUE);
- }
-
- /**
- * The contribution type from a binding element's annotations. Presumes a well-formed binding
- * element (at most one of @IntoSet, @IntoMap, @ElementsIntoSet and @Provides.type). {@link
- * dagger.internal.codegen.validation.BindingMethodValidator} and {@link
- * dagger.internal.codegen.validation.BindsInstanceProcessingStep} validate correctness on their
- * own.
- */
- public static ContributionType fromBindingElement(Element element) {
- // TODO(bcorso): Replace these class references with ClassName.
- if (isAnnotationPresent(element, IntoMap.class)) {
- return ContributionType.MAP;
- } else if (isAnnotationPresent(element, IntoSet.class)) {
- return ContributionType.SET;
- } else if (isAnnotationPresent(element, ElementsIntoSet.class)) {
- return ContributionType.SET_VALUES;
- }
- return ContributionType.UNIQUE;
- }
-}
diff --git a/java/dagger/internal/codegen/base/DiagnosticFormatting.java b/java/dagger/internal/codegen/base/DiagnosticFormatting.java
deleted file mode 100644
index 93e445c..0000000
--- a/java/dagger/internal/codegen/base/DiagnosticFormatting.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 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.base;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Utility methods for formatting diagnostics to the {@link javax.annotation.processing.Messager}.
- */
-public final class DiagnosticFormatting {
-
- /**
- * A regular expression to match a small list of specific packages deemed to be unhelpful to
- * display in fully qualified types in error messages.
- *
- * <p>Note: This should never be applied to messages themselves.
- */
- private static final Pattern COMMON_PACKAGE_PATTERN =
- Pattern.compile(
- "(?:^|[^.a-z_])" // What we want to match on but not capture.
- + "((?:" // Start a group with a non-capturing or part
- + "java[.]lang"
- + "|java[.]util"
- + "|javax[.]inject"
- + "|dagger"
- + "|dagger[.]multibindings"
- + "|com[.]google[.]common[.]base"
- + "|com[.]google[.]common[.]collect"
- + ")[.])" // Always end with a literal .
- + "[A-Z]"); // What we want to match on but not capture.
-
- /**
- * A method to strip out common packages and a few rare type prefixes from types' string
- * representation before being used in error messages.
- *
- * <p>This type assumes a String value that is a valid fully qualified (and possibly
- * parameterized) type, and should NOT be used with arbitrary text, especially prose error
- * messages.
- *
- * <p>TODO(user): Tighten these to take type representations (mirrors and elements) to avoid
- * accidental mis-use by running errors through this method.
- */
- public static String stripCommonTypePrefixes(String type) {
- // Do regex magic to remove common packages we care to shorten.
- Matcher matcher = COMMON_PACKAGE_PATTERN.matcher(type);
- StringBuilder result = new StringBuilder();
- int index = 0;
- while (matcher.find()) {
- result.append(type.subSequence(index, matcher.start(1)));
- index = matcher.end(1); // Skip the matched pattern content.
- }
- result.append(type.subSequence(index, type.length()));
- return result.toString();
- }
-
- private DiagnosticFormatting() {}
-}
diff --git a/java/dagger/internal/codegen/base/ElementFormatter.java b/java/dagger/internal/codegen/base/ElementFormatter.java
deleted file mode 100644
index f85fbfd..0000000
--- a/java/dagger/internal/codegen/base/ElementFormatter.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2013 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.base;
-
-import static com.google.auto.common.MoreElements.asExecutable;
-import static java.util.stream.Collectors.joining;
-
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementVisitor;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementKindVisitor8;
-
-/**
- * Formats elements into a useful string representation.
- *
- * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name.
- *
- * <p>Parameters are given with their enclosing executable, with other parameters elided.
- */
-public final class ElementFormatter extends Formatter<Element> {
- @Inject
- ElementFormatter() {}
-
- @Override
- public String format(Element element) {
- return elementToString(element);
- }
-
- /**
- * Returns a useful string form for an element.
- *
- * <p>Elements directly enclosed by a type are preceded by the enclosing type's qualified name.
- *
- * <p>Parameters are given with their enclosing executable, with other parameters elided.
- */
- public static String elementToString(Element element) {
- return element.accept(ELEMENT_TO_STRING, null);
- }
-
- private static final ElementVisitor<String, Void> ELEMENT_TO_STRING =
- new ElementKindVisitor8<String, Void>() {
- @Override
- public String visitExecutable(ExecutableElement executableElement, Void aVoid) {
- return enclosingTypeAndMemberName(executableElement)
- .append(
- executableElement.getParameters().stream()
- .map(parameter -> parameter.asType().toString())
- .collect(joining(", ", "(", ")")))
- .toString();
- }
-
- @Override
- public String visitVariableAsParameter(VariableElement parameter, Void aVoid) {
- ExecutableElement methodOrConstructor = asExecutable(parameter.getEnclosingElement());
- return enclosingTypeAndMemberName(methodOrConstructor)
- .append('(')
- .append(
- formatArgumentInList(
- methodOrConstructor.getParameters().indexOf(parameter),
- methodOrConstructor.getParameters().size(),
- parameter.getSimpleName()))
- .append(')')
- .toString();
- }
-
- @Override
- public String visitVariableAsField(VariableElement field, Void aVoid) {
- return enclosingTypeAndMemberName(field).toString();
- }
-
- @Override
- public String visitType(TypeElement type, Void aVoid) {
- return type.getQualifiedName().toString();
- }
-
- @Override
- protected String defaultAction(Element element, Void aVoid) {
- throw new UnsupportedOperationException(
- "Can't determine string for " + element.getKind() + " element " + element);
- }
-
- private StringBuilder enclosingTypeAndMemberName(Element element) {
- StringBuilder name = new StringBuilder(element.getEnclosingElement().accept(this, null));
- if (!element.getSimpleName().contentEquals("<init>")) {
- name.append('.').append(element.getSimpleName());
- }
- return name;
- }
- };
-}
diff --git a/java/dagger/internal/codegen/base/Formatter.java b/java/dagger/internal/codegen/base/Formatter.java
deleted file mode 100644
index c5e2357..0000000
--- a/java/dagger/internal/codegen/base/Formatter.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2014 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.base;
-
-import static com.google.common.base.Preconditions.checkElementIndex;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-
-/**
- * A formatter which transforms an instance of a particular type into a string
- * representation.
- *
- * @param <T> the type of the object to be transformed.
- */
-public abstract class Formatter<T> implements Function<T, String> {
-
- public static final String INDENT = " ";
- public static final String DOUBLE_INDENT = INDENT + INDENT;
- private static final int LIST_LIMIT = 10;
-
- /**
- * Performs the transformation of an object into a string representation.
- */
- public abstract String format(T object);
-
- /**
- * Performs the transformation of an object into a string representation in conformity with the
- * {@link Function}{@code <T, String>} contract, delegating to {@link #format(Object)}.
- *
- * @deprecated Call {@link #format(Object)} instead. This method exists to make formatters easy to
- * use when functions are required, but shouldn't be called directly.
- */
- @SuppressWarnings("javadoc")
- @Deprecated
- @Override
- public final String apply(T object) {
- return format(object);
- }
-
- /** Formats {@code items}, one per line. Stops after {@value #LIST_LIMIT} items. */
- public void formatIndentedList(
- StringBuilder builder, Iterable<? extends T> items, int indentLevel) {
- for (T item : Iterables.limit(items, LIST_LIMIT)) {
- String formatted = format(item);
- if (formatted.isEmpty()) {
- continue;
- }
- builder.append('\n');
- appendIndent(builder, indentLevel);
- builder.append(formatted);
- }
- int numberOfOtherItems = Iterables.size(items) - LIST_LIMIT;
- if (numberOfOtherItems > 0) {
- builder.append('\n');
- appendIndent(builder, indentLevel);
- builder.append("and ").append(numberOfOtherItems).append(" other");
- }
- if (numberOfOtherItems > 1) {
- builder.append('s');
- }
- }
-
- private void appendIndent(StringBuilder builder, int indentLevel) {
- for (int i = 0; i < indentLevel; i++) {
- builder.append(INDENT);
- }
- }
-
- public static String formatArgumentInList(int index, int size, CharSequence name) {
- checkElementIndex(index, size);
- StringBuilder builder = new StringBuilder();
- if (index > 0) {
- builder.append("…, ");
- }
- builder.append(name);
- if (index < size - 1) {
- builder.append(", …");
- }
- return builder.toString();
- }
-}
diff --git a/java/dagger/internal/codegen/base/FrameworkTypes.java b/java/dagger/internal/codegen/base/FrameworkTypes.java
deleted file mode 100644
index 4cd54a3..0000000
--- a/java/dagger/internal/codegen/base/FrameworkTypes.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import static com.google.auto.common.MoreTypes.isType;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.Lazy;
-import dagger.MembersInjector;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.Set;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A collection of utility methods for dealing with Dagger framework types. A framework type is any
- * type that the framework itself defines.
- */
-public final class FrameworkTypes {
- private static final ImmutableSet<Class<?>> PROVISION_TYPES =
- ImmutableSet.of(Provider.class, Lazy.class, MembersInjector.class);
-
- // NOTE(beder): ListenableFuture is not considered a producer framework type because it is not
- // defined by the framework, so we can't treat it specially in ordinary Dagger.
- private static final ImmutableSet<Class<?>> PRODUCTION_TYPES =
- ImmutableSet.of(Produced.class, Producer.class);
-
- /** Returns true if the type represents a producer-related framework type. */
- public static boolean isProducerType(TypeMirror type) {
- return isType(type) && typeIsOneOf(PRODUCTION_TYPES, type);
- }
-
- /** Returns true if the type represents a framework type. */
- public static boolean isFrameworkType(TypeMirror type) {
- return isType(type)
- && (typeIsOneOf(PROVISION_TYPES, type)
- || typeIsOneOf(PRODUCTION_TYPES, type));
- }
-
- private static boolean typeIsOneOf(Set<Class<?>> classes, TypeMirror type) {
- for (Class<?> clazz : classes) {
- if (MoreTypes.isTypeOf(clazz, type)) {
- return true;
- }
- }
- return false;
- }
-
- private FrameworkTypes() {}
-}
diff --git a/java/dagger/internal/codegen/base/Keys.java b/java/dagger/internal/codegen/base/Keys.java
deleted file mode 100644
index a25f996..0000000
--- a/java/dagger/internal/codegen/base/Keys.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 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.base;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleTypeVisitor6;
-
-/** Utility methods related to {@link Key}s. */
-public final class Keys {
- public static boolean isValidMembersInjectionKey(Key key) {
- return !key.qualifier().isPresent()
- && !key.multibindingContributionIdentifier().isPresent()
- && key.type().getKind().equals(TypeKind.DECLARED);
- }
-
- /**
- * Returns {@code true} if this is valid as an implicit key (that is, if it's valid for a
- * just-in-time binding by discovering an {@code @Inject} constructor).
- */
- public static boolean isValidImplicitProvisionKey(Key key, DaggerTypes types) {
- return isValidImplicitProvisionKey(key.qualifier(), key.type(), types);
- }
-
- /**
- * Returns {@code true} if a key with {@code qualifier} and {@code type} is valid as an implicit
- * key (that is, if it's valid for a just-in-time binding by discovering an {@code @Inject}
- * constructor).
- */
- public static boolean isValidImplicitProvisionKey(
- Optional<? extends AnnotationMirror> qualifier, TypeMirror type, final DaggerTypes types) {
- // Qualifiers disqualify implicit provisioning.
- if (qualifier.isPresent()) {
- return false;
- }
-
- return type.accept(
- new SimpleTypeVisitor6<Boolean, Void>(false) {
- @Override
- public Boolean visitDeclared(DeclaredType type, Void ignored) {
- // Non-classes or abstract classes aren't allowed.
- TypeElement element = MoreElements.asType(type.asElement());
- if (!element.getKind().equals(ElementKind.CLASS)
- || element.getModifiers().contains(Modifier.ABSTRACT)) {
- return false;
- }
-
- // If the key has type arguments, validate that each type argument is declared.
- // Otherwise the type argument may be a wildcard (or other type), and we can't
- // resolve that to actual types.
- for (TypeMirror arg : type.getTypeArguments()) {
- if (arg.getKind() != TypeKind.DECLARED) {
- return false;
- }
- }
-
- // Also validate that the key is not the erasure of a generic type.
- // If it is, that means the user referred to Foo<T> as just 'Foo',
- // which we don't allow. (This is a judgement call -- we *could*
- // allow it and instantiate the type bounds... but we don't.)
- return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
- || !types.isSameType(types.erasure(element.asType()), type);
- }
- },
- null);
- }
-}
diff --git a/java/dagger/internal/codegen/base/MapKeyAccessibility.java b/java/dagger/internal/codegen/base/MapKeyAccessibility.java
deleted file mode 100644
index 93c265a..0000000
--- a/java/dagger/internal/codegen/base/MapKeyAccessibility.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 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.base;
-
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-
-import dagger.internal.codegen.langmodel.Accessibility;
-import java.util.Collection;
-import java.util.List;
-import java.util.function.Predicate;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-
-/** Utility class for checking the visibility of an annotation. */
-public final class MapKeyAccessibility extends SimpleAnnotationValueVisitor8<Boolean, Void> {
- private final Predicate<TypeMirror> accessibilityChecker;
-
- private MapKeyAccessibility(Predicate<TypeMirror> accessibilityChecker) {
- this.accessibilityChecker = accessibilityChecker;
- }
-
- @Override
- public Boolean visitAnnotation(AnnotationMirror annotation, Void aVoid) {
- // The annotation type is not checked, as the generated code will refer to the @AutoAnnotation
- // generated type which is always public
- return visitValues(annotation.getElementValues().values());
- }
-
- @Override
- public Boolean visitArray(List<? extends AnnotationValue> values, Void aVoid) {
- return visitValues(values);
- }
-
- private boolean visitValues(Collection<? extends AnnotationValue> values) {
- return values.stream().allMatch(value -> value.accept(this, null));
- }
-
- @Override
- public Boolean visitEnumConstant(VariableElement enumConstant, Void aVoid) {
- return accessibilityChecker.test(enumConstant.getEnclosingElement().asType());
- }
-
- @Override
- public Boolean visitType(TypeMirror type, Void aVoid) {
- return accessibilityChecker.test(type);
- }
-
- @Override
- protected Boolean defaultAction(Object o, Void aVoid) {
- return true;
- }
-
- public static boolean isMapKeyAccessibleFrom(
- AnnotationMirror annotation, String accessingPackage) {
- return new MapKeyAccessibility(type -> isTypeAccessibleFrom(type, accessingPackage))
- .visitAnnotation(annotation, null);
- }
-
- public static boolean isMapKeyPubliclyAccessible(AnnotationMirror annotation) {
- return new MapKeyAccessibility(Accessibility::isTypePubliclyAccessible)
- .visitAnnotation(annotation, null);
- }
-}
diff --git a/java/dagger/internal/codegen/base/MapType.java b/java/dagger/internal/codegen/base/MapType.java
deleted file mode 100644
index 4e2307a..0000000
--- a/java/dagger/internal/codegen/base/MapType.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import dagger.model.Key;
-import java.util.Map;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Information about a {@link Map} {@link TypeMirror}.
- */
-@AutoValue
-public abstract class MapType {
- /**
- * The map type itself, wrapped using {@link MoreTypes#equivalence()}. Use
- * {@link #declaredMapType()} instead.
- */
- protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredMapType();
-
- /**
- * The map type itself.
- */
- private DeclaredType declaredMapType() {
- return wrappedDeclaredMapType().get();
- }
-
- /**
- * {@code true} if the map type is the raw {@link Map} type.
- */
- public boolean isRawType() {
- return declaredMapType().getTypeArguments().isEmpty();
- }
-
- /**
- * The map key type.
- *
- * @throws IllegalStateException if {@link #isRawType()} is true.
- */
- public TypeMirror keyType() {
- checkState(!isRawType());
- return declaredMapType().getTypeArguments().get(0);
- }
-
- /**
- * The map value type.
- *
- * @throws IllegalStateException if {@link #isRawType()} is true.
- */
- public TypeMirror valueType() {
- checkState(!isRawType());
- return declaredMapType().getTypeArguments().get(1);
- }
-
- /**
- * {@code true} if {@link #valueType()} is a {@code clazz}.
- *
- * @throws IllegalStateException if {@link #isRawType()} is true.
- */
- public boolean valuesAreTypeOf(Class<?> clazz) {
- return MoreTypes.isType(valueType()) && MoreTypes.isTypeOf(clazz, valueType());
- }
-
- /**
- * Returns {@code true} if the {@linkplain #valueType() value type} of the {@link Map} is a
- * {@linkplain FrameworkTypes#isFrameworkType(TypeMirror) framework type}.
- */
- public boolean valuesAreFrameworkType() {
- return FrameworkTypes.isFrameworkType(valueType());
- }
-
- /**
- * {@code V} if {@link #valueType()} is a framework type like {@code Provider<V>} or {@code
- * Producer<V>}.
- *
- * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
- * framework type
- */
- public TypeMirror unwrappedFrameworkValueType() {
- checkState(
- valuesAreFrameworkType(), "called unwrappedFrameworkValueType() on %s", declaredMapType());
- return uncheckedUnwrappedValueType();
- }
-
- /**
- * {@code V} if {@link #valueType()} is a {@code WrappingClass<V>}.
- *
- * @throws IllegalStateException if {@link #isRawType()} is true or {@link #valueType()} is not a
- * {@code WrappingClass<V>}
- * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
- * parameter
- */
- public TypeMirror unwrappedValueType(Class<?> wrappingClass) {
- checkArgument(
- wrappingClass.getTypeParameters().length == 1,
- "%s must have exactly one type parameter",
- wrappingClass);
- checkState(valuesAreTypeOf(wrappingClass), "expected values to be %s: %s", wrappingClass, this);
- return uncheckedUnwrappedValueType();
- }
-
- private TypeMirror uncheckedUnwrappedValueType() {
- return MoreTypes.asDeclared(valueType()).getTypeArguments().get(0);
- }
-
- /**
- * {@code true} if {@code type} is a {@link Map} type.
- */
- public static boolean isMap(TypeMirror type) {
- return MoreTypes.isType(type) && MoreTypes.isTypeOf(Map.class, type);
- }
-
- /**
- * {@code true} if {@code key.type()} is a {@link Map} type.
- */
- public static boolean isMap(Key key) {
- return isMap(key.type());
- }
-
- /**
- * Returns a {@link MapType} for {@code type}.
- *
- * @throws IllegalArgumentException if {@code type} is not a {@link Map} type
- */
- public static MapType from(TypeMirror type) {
- checkArgument(isMap(type), "%s is not a Map", type);
- return new AutoValue_MapType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
- }
-
- /**
- * Returns a {@link MapType} for {@code key}'s {@link Key#type() type}.
- *
- * @throws IllegalArgumentException if {@code key.type()} is not a {@link Map} type
- */
- public static MapType from(Key key) {
- return from(key.type());
- }
-}
diff --git a/java/dagger/internal/codegen/base/ModuleAnnotation.java b/java/dagger/internal/codegen/base/ModuleAnnotation.java
deleted file mode 100644
index 1688736..0000000
--- a/java/dagger/internal/codegen/base/ModuleAnnotation.java
+++ /dev/null
@@ -1,127 +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.internal.codegen.base;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
-
-import com.google.auto.common.MoreTypes;
-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.ImmutableSet;
-import dagger.Module;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.TypeElement;
-
-/** A {@code @Module} or {@code @ProducerModule} annotation. */
-@AutoValue
-public abstract class ModuleAnnotation {
- private static final ImmutableSet<Class<? extends Annotation>> MODULE_ANNOTATIONS =
- ImmutableSet.of(Module.class, ProducerModule.class);
-
- /** The annotation itself. */
- // This does not use AnnotationMirrors.equivalence() because we want the actual annotation
- // instance.
- public abstract AnnotationMirror annotation();
-
- /** The simple name of the annotation. */
- public String annotationName() {
- return annotation().getAnnotationType().asElement().getSimpleName().toString();
- }
-
- /**
- * The types specified in the {@code includes} attribute.
- *
- * @throws IllegalArgumentException if any of the values are error types
- */
- @Memoized
- public ImmutableList<TypeElement> includes() {
- return includesAsAnnotationValues().stream()
- .map(MoreAnnotationValues::asType)
- .map(MoreTypes::asTypeElement)
- .collect(toImmutableList());
- }
-
- /** The values specified in the {@code includes} attribute. */
- @Memoized
- public ImmutableList<AnnotationValue> includesAsAnnotationValues() {
- return asAnnotationValues(getAnnotationValue(annotation(), "includes"));
- }
-
- /**
- * The types specified in the {@code subcomponents} attribute.
- *
- * @throws IllegalArgumentException if any of the values are error types
- */
- @Memoized
- public ImmutableList<TypeElement> subcomponents() {
- return subcomponentsAsAnnotationValues().stream()
- .map(MoreAnnotationValues::asType)
- .map(MoreTypes::asTypeElement)
- .collect(toImmutableList());
- }
-
- /** The values specified in the {@code subcomponents} attribute. */
- @Memoized
- public ImmutableList<AnnotationValue> subcomponentsAsAnnotationValues() {
- return asAnnotationValues(getAnnotationValue(annotation(), "subcomponents"));
- }
-
- /** Returns {@code true} if the argument is a {@code @Module} or {@code @ProducerModule}. */
- public static boolean isModuleAnnotation(AnnotationMirror annotation) {
- return MODULE_ANNOTATIONS.stream()
- .map(Class::getCanonicalName)
- .anyMatch(asTypeElement(annotation.getAnnotationType()).getQualifiedName()::contentEquals);
- }
-
- /** The module annotation types. */
- public static ImmutableSet<Class<? extends Annotation>> moduleAnnotations() {
- return MODULE_ANNOTATIONS;
- }
-
- /**
- * Creates an object that represents a {@code @Module} or {@code @ProducerModule}.
- *
- * @throws IllegalArgumentException if {@link #isModuleAnnotation(AnnotationMirror)} returns
- * {@code false}
- */
- public static ModuleAnnotation moduleAnnotation(AnnotationMirror annotation) {
- checkArgument(
- isModuleAnnotation(annotation),
- "%s is not a Module or ProducerModule annotation",
- annotation);
- return new AutoValue_ModuleAnnotation(annotation);
- }
-
- /**
- * Returns an object representing the {@code @Module} or {@code @ProducerModule} annotation if one
- * annotates {@code typeElement}.
- */
- public static Optional<ModuleAnnotation> moduleAnnotation(TypeElement typeElement) {
- return getAnyAnnotation(typeElement, Module.class, ProducerModule.class)
- .map(ModuleAnnotation::moduleAnnotation);
- }
-}
diff --git a/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java b/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java
deleted file mode 100644
index 234ecc1..0000000
--- a/java/dagger/internal/codegen/base/MoreAnnotationMirrors.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2016 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.base;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asAnnotationValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
-import com.google.auto.common.AnnotationMirrors;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableList;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Name;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A utility class for working with {@link AnnotationMirror} instances, similar to {@link
- * AnnotationMirrors}.
- */
-public final class MoreAnnotationMirrors {
-
- private MoreAnnotationMirrors() {}
-
- /**
- * Wraps an {@link Optional} of a type in an {@code Optional} of a {@link Equivalence.Wrapper} for
- * that type.
- */
- public static Optional<Equivalence.Wrapper<AnnotationMirror>> wrapOptionalInEquivalence(
- Optional<AnnotationMirror> optional) {
- return optional.map(AnnotationMirrors.equivalence()::wrap);
- }
-
- /**
- * Unwraps an {@link Optional} of a {@link Equivalence.Wrapper} into an {@code Optional} of the
- * underlying type.
- */
- public static Optional<AnnotationMirror> unwrapOptionalEquivalence(
- Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedOptional) {
- return wrappedOptional.map(Equivalence.Wrapper::get);
- }
-
- public static Name simpleName(AnnotationMirror annotationMirror) {
- return annotationMirror.getAnnotationType().asElement().getSimpleName();
- }
-
- /**
- * Returns the list of types that is the value named {@code name} from {@code annotationMirror}.
- *
- * @throws IllegalArgumentException unless that member represents an array of types
- */
- public static ImmutableList<TypeMirror> getTypeListValue(
- AnnotationMirror annotationMirror, String name) {
- return asAnnotationValues(getAnnotationValue(annotationMirror, name))
- .stream()
- .map(MoreAnnotationValues::asType)
- .collect(toImmutableList());
- }
-}
diff --git a/java/dagger/internal/codegen/base/MoreAnnotationValues.java b/java/dagger/internal/codegen/base/MoreAnnotationValues.java
deleted file mode 100644
index 1ee50da..0000000
--- a/java/dagger/internal/codegen/base/MoreAnnotationValues.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2013 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.base;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
-
-import com.google.common.collect.ImmutableList;
-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.type.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-
-/** Utility methods for working with {@link AnnotationValue} instances. */
-public final class MoreAnnotationValues {
- /**
- * Returns the list of values represented by an array annotation value.
- *
- * @throws IllegalArgumentException unless {@code annotationValue} represents an array
- */
- public static ImmutableList<AnnotationValue> asAnnotationValues(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);
- }
- };
-
- /**
- * Returns the type represented by an annotation value.
- *
- * @throws IllegalArgumentException unless {@code annotationValue} represents a single type
- */
- public static TypeMirror asType(AnnotationValue annotationValue) {
- return AS_TYPE.visit(annotationValue);
- }
-
- private static final AnnotationValueVisitor<TypeMirror, Void> AS_TYPE =
- new SimpleAnnotationValueVisitor8<TypeMirror, Void>() {
- @Override
- public TypeMirror visitType(TypeMirror t, Void p) {
- return t;
- }
-
- @Override
- protected TypeMirror defaultAction(Object o, Void p) {
- throw new TypeNotPresentException(o.toString(), null);
- }
- };
-
- /** 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 asAnnotationValues(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 asAnnotationValues(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));
- }
-
- private MoreAnnotationValues() {}
-}
diff --git a/java/dagger/internal/codegen/base/MultibindingAnnotations.java b/java/dagger/internal/codegen/base/MultibindingAnnotations.java
deleted file mode 100644
index 424f92a..0000000
--- a/java/dagger/internal/codegen/base/MultibindingAnnotations.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2016 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.base;
-
-import static dagger.internal.codegen.langmodel.DaggerElements.getAllAnnotations;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-
-/**
- * Utility methods related to processing {@link IntoSet}, {@link ElementsIntoSet}, and {@link
- * IntoMap}.
- */
-public final class MultibindingAnnotations {
- public static ImmutableSet<AnnotationMirror> forElement(Element method) {
- return getAllAnnotations(method, IntoSet.class, ElementsIntoSet.class, IntoMap.class);
- }
-}
diff --git a/java/dagger/internal/codegen/base/OptionalType.java b/java/dagger/internal/codegen/base/OptionalType.java
deleted file mode 100644
index 1505682..0000000
--- a/java/dagger/internal/codegen/base/OptionalType.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2016 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.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import dagger.model.Key;
-import java.util.Optional;
-import javax.lang.model.element.Name;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/**
- * Information about an {@code Optional} {@link TypeMirror}.
- *
- * <p>{@link com.google.common.base.Optional} and {@link java.util.Optional} are supported.
- */
-@AutoValue
-public abstract class OptionalType {
-
- /** A variant of {@code Optional}. */
- public enum OptionalKind {
- /** {@link com.google.common.base.Optional}. */
- GUAVA_OPTIONAL(com.google.common.base.Optional.class, "absent"),
-
- /** {@link java.util.Optional}. */
- JDK_OPTIONAL(java.util.Optional.class, "empty"),
- ;
-
- private final Class<?> clazz;
- private final String absentFactoryMethodName;
-
- OptionalKind(Class<?> clazz, String absentFactoryMethodName) {
- this.clazz = clazz;
- this.absentFactoryMethodName = absentFactoryMethodName;
- }
-
- /** Returns {@code valueType} wrapped in the correct class. */
- public ParameterizedTypeName of(TypeName valueType) {
- return ParameterizedTypeName.get(ClassName.get(clazz), valueType);
- }
-
- /** Returns an expression for the absent/empty value. */
- public CodeBlock absentValueExpression() {
- return CodeBlock.of("$T.$L()", clazz, absentFactoryMethodName);
- }
-
- /**
- * Returns an expression for the absent/empty value, parameterized with {@link #valueType()}.
- */
- public CodeBlock parameterizedAbsentValueExpression(OptionalType optionalType) {
- return CodeBlock.of("$T.<$T>$L()", clazz, optionalType.valueType(), absentFactoryMethodName);
- }
-
- /** Returns an expression for the present {@code value}. */
- public CodeBlock presentExpression(CodeBlock value) {
- return CodeBlock.of("$T.of($L)", clazz, value);
- }
-
- /**
- * Returns an expression for the present {@code value}, returning {@code Optional<Object>} no
- * matter what type the value is.
- */
- public CodeBlock presentObjectExpression(CodeBlock value) {
- return CodeBlock.of("$T.<$T>of($L)", clazz, Object.class, value);
- }
- }
-
- private static final TypeVisitor<Optional<OptionalKind>, Void> OPTIONAL_KIND =
- new SimpleTypeVisitor8<Optional<OptionalKind>, Void>(Optional.empty()) {
- @Override
- public Optional<OptionalKind> visitDeclared(DeclaredType t, Void p) {
- for (OptionalKind optionalKind : OptionalKind.values()) {
- Name qualifiedName = MoreElements.asType(t.asElement()).getQualifiedName();
- if (qualifiedName.contentEquals(optionalKind.clazz.getCanonicalName())) {
- return Optional.of(optionalKind);
- }
- }
- return Optional.empty();
- }
- };
-
- /**
- * The optional type itself, wrapped using {@link MoreTypes#equivalence()}.
- *
- * @deprecated Use {@link #declaredOptionalType()} instead.
- */
- @Deprecated
- protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredOptionalType();
-
- /** The optional type itself. */
- @SuppressWarnings("deprecation")
- private DeclaredType declaredOptionalType() {
- return wrappedDeclaredOptionalType().get();
- }
-
- /** Which {@code Optional} type is used. */
- public OptionalKind kind() {
- return declaredOptionalType().accept(OPTIONAL_KIND, null).get();
- }
-
- /** The value type. */
- public TypeMirror valueType() {
- return declaredOptionalType().getTypeArguments().get(0);
- }
-
- /** Returns {@code true} if {@code type} is an {@code Optional} type. */
- private static boolean isOptional(TypeMirror type) {
- return type.accept(OPTIONAL_KIND, null).isPresent();
- }
-
- /** Returns {@code true} if {@code key.type()} is an {@code Optional} type. */
- public static boolean isOptional(Key key) {
- return isOptional(key.type());
- }
-
- /**
- * Returns a {@link OptionalType} for {@code type}.
- *
- * @throws IllegalArgumentException if {@code type} is not an {@code Optional} type
- */
- public static OptionalType from(TypeMirror type) {
- checkArgument(isOptional(type), "%s must be an Optional", type);
- return new AutoValue_OptionalType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
- }
-
- /**
- * Returns a {@link OptionalType} for {@code key}'s {@link Key#type() type}.
- *
- * @throws IllegalArgumentException if {@code key.type()} is not an {@code Optional} type
- */
- public static OptionalType from(Key key) {
- return from(key.type());
- }
-}
diff --git a/java/dagger/internal/codegen/base/RequestKinds.java b/java/dagger/internal/codegen/base/RequestKinds.java
deleted file mode 100644
index 95d5ef4..0000000
--- a/java/dagger/internal/codegen/base/RequestKinds.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2014 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.base;
-
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.isType;
-import static com.google.auto.common.MoreTypes.isTypeOf;
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.javapoet.TypeNames.lazyOf;
-import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
-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.langmodel.DaggerTypes.checkTypePresent;
-import static dagger.model.RequestKind.LAZY;
-import static dagger.model.RequestKind.PRODUCED;
-import static dagger.model.RequestKind.PRODUCER;
-import static dagger.model.RequestKind.PROVIDER;
-import static dagger.model.RequestKind.PROVIDER_OF_LAZY;
-import static javax.lang.model.type.TypeKind.DECLARED;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.squareup.javapoet.TypeName;
-import dagger.Lazy;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/** Utility methods for {@link RequestKind}s. */
-public final class RequestKinds {
-
- /** Returns the type of a request of this kind for a key with a given type. */
- public static TypeMirror requestType(
- RequestKind requestKind, TypeMirror type, DaggerTypes types) {
- switch (requestKind) {
- case INSTANCE:
- return type;
-
- case PROVIDER_OF_LAZY:
- return types.wrapType(requestType(LAZY, type, types), Provider.class);
-
- case FUTURE:
- return types.wrapType(type, ListenableFuture.class);
-
- default:
- return types.wrapType(type, frameworkClass(requestKind));
- }
- }
-
- /** Returns the type of a request of this kind for a key with a given type. */
- public static TypeName requestTypeName(RequestKind requestKind, TypeName keyType) {
- switch (requestKind) {
- case INSTANCE:
- return keyType;
-
- case PROVIDER:
- return providerOf(keyType);
-
- case LAZY:
- return lazyOf(keyType);
-
- case PROVIDER_OF_LAZY:
- return providerOf(lazyOf(keyType));
-
- case PRODUCER:
- return producerOf(keyType);
-
- case PRODUCED:
- return producedOf(keyType);
-
- case FUTURE:
- return listenableFutureOf(keyType);
-
- default:
- throw new AssertionError(requestKind);
- }
- }
-
- private static final ImmutableMap<RequestKind, Class<?>> FRAMEWORK_CLASSES =
- ImmutableMap.of(
- PROVIDER, Provider.class,
- LAZY, Lazy.class,
- PRODUCER, Producer.class,
- PRODUCED, Produced.class);
-
- /** Returns the {@link RequestKind} that matches the wrapping types (if any) of {@code type}. */
- public static RequestKind getRequestKind(TypeMirror type) {
- checkTypePresent(type);
- if (!isType(type) // TODO(b/147320669): isType check can be removed once this bug is fixed.
- || !type.getKind().equals(DECLARED)
- || asDeclared(type).getTypeArguments().isEmpty()) {
- // If the type is not a declared type (i.e. class or interface) with type arguments, then we
- // know it can't be a parameterized type of one of the framework classes, so return INSTANCE.
- return RequestKind.INSTANCE;
- }
- for (RequestKind kind : FRAMEWORK_CLASSES.keySet()) {
- if (isTypeOf(frameworkClass(kind), type)) {
- if (kind.equals(PROVIDER) && getRequestKind(DaggerTypes.unwrapType(type)).equals(LAZY)) {
- return PROVIDER_OF_LAZY;
- }
- return kind;
- }
- }
- return RequestKind.INSTANCE;
- }
-
- /**
- * Unwraps the framework class(es) of {@code requestKind} from {@code type}. If {@code
- * requestKind} is {@link RequestKind#INSTANCE}, this acts as an identity function.
- *
- * @throws TypeNotPresentException if {@code type} is an {@link javax.lang.model.type.ErrorType},
- * which may mean that the type will be generated in a later round of processing
- * @throws IllegalArgumentException if {@code type} is not wrapped with {@code requestKind}'s
- * framework class(es).
- */
- public static TypeMirror extractKeyType(TypeMirror type) {
- return extractKeyType(getRequestKind(type), type);
- }
-
- private static TypeMirror extractKeyType(RequestKind requestKind, TypeMirror type) {
- switch (requestKind) {
- case INSTANCE:
- return type;
- case PROVIDER_OF_LAZY:
- return extractKeyType(LAZY, extractKeyType(PROVIDER, type));
- default:
- checkArgument(isType(type));
- return DaggerTypes.unwrapType(type);
- }
- }
-
- /**
- * A dagger- or {@code javax.inject}-defined class for {@code requestKind} that that can wrap
- * another type but share the same {@link dagger.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.
- *
- * <p>This concept is not well defined and should probably be removed and inlined into the cases
- * that need it. For example, {@link RequestKind#PROVIDER_OF_LAZY} has <em>2</em> wrapping
- * classes, and {@link RequestKind#FUTURE} is wrapped with a {@link ListenableFuture}, but for
- * historical/implementation reasons has not had an associated framework class.
- */
- public static Class<?> frameworkClass(RequestKind requestKind) {
- Class<?> result = FRAMEWORK_CLASSES.get(requestKind);
- checkArgument(result != null, "no framework class for %s", requestKind);
- return result;
- }
-
- /**
- * Returns {@code true} if requests for {@code requestKind} can be satisfied by a production
- * binding.
- */
- public static boolean canBeSatisfiedByProductionBinding(RequestKind requestKind) {
- switch (requestKind) {
- case INSTANCE:
- case PROVIDER:
- case LAZY:
- case PROVIDER_OF_LAZY:
- case MEMBERS_INJECTION:
- return false;
- case PRODUCER:
- case PRODUCED:
- case FUTURE:
- return true;
- }
- throw new AssertionError();
- }
-
- private RequestKinds() {}
-}
diff --git a/java/dagger/internal/codegen/base/Scopes.java b/java/dagger/internal/codegen/base/Scopes.java
deleted file mode 100644
index f2c39ce..0000000
--- a/java/dagger/internal/codegen/base/Scopes.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 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.base;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.AnnotationMirrors;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.Scope;
-import dagger.producers.ProductionScope;
-import java.lang.annotation.Annotation;
-import java.util.Optional;
-import javax.inject.Singleton;
-import javax.lang.model.element.Element;
-
-/** Common names and convenience methods for {@link Scope}s. */
-public final class Scopes {
-
- /** Returns a representation for {@link ProductionScope @ProductionScope} scope. */
- public static Scope productionScope(DaggerElements elements) {
- return scope(elements, ProductionScope.class);
- }
-
- /** Returns a representation for {@link Singleton @Singleton} scope. */
- public static Scope singletonScope(DaggerElements elements) {
- return scope(elements, Singleton.class);
- }
-
- /**
- * Creates a {@link Scope} object from the {@link javax.inject.Scope}-annotated annotation type.
- */
- private static Scope scope(
- DaggerElements elements, Class<? extends Annotation> scopeAnnotationClass) {
- return Scope.scope(SimpleAnnotationMirror.of(elements.getTypeElement(scopeAnnotationClass)));
- }
-
- /**
- * Returns at most one associated scoped annotation from the source code element, throwing an
- * exception if there are more than one.
- */
- public static Optional<Scope> uniqueScopeOf(Element element) {
- // TODO(ronshapiro): Use MoreCollectors.toOptional() once we can use guava-jre
- return Optional.ofNullable(getOnlyElement(scopesOf(element), null));
- }
-
- /**
- * Returns the readable source representation (name with @ prefix) of the scope's annotation type.
- *
- * <p>It's readable source because it has had common package prefixes removed, e.g.
- * {@code @javax.inject.Singleton} is returned as {@code @Singleton}.
- */
- public static String getReadableSource(Scope scope) {
- return stripCommonTypePrefixes(scope.toString());
- }
-
- /** Returns all of the associated scopes for a source code element. */
- public static ImmutableSet<Scope> scopesOf(Element element) {
- return AnnotationMirrors.getAnnotatedAnnotations(element, javax.inject.Scope.class)
- .stream()
- .map(Scope::scope)
- .collect(toImmutableSet());
- }
-}
diff --git a/java/dagger/internal/codegen/base/SetType.java b/java/dagger/internal/codegen/base/SetType.java
deleted file mode 100644
index a75a6d3..0000000
--- a/java/dagger/internal/codegen/base/SetType.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import dagger.model.Key;
-import java.util.Set;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Information about a {@link Set} {@link TypeMirror}.
- */
-@AutoValue
-public abstract class SetType {
- /**
- * The set type itself, wrapped using {@link MoreTypes#equivalence()}. Use
- * {@link #declaredSetType()} instead.
- */
- protected abstract Equivalence.Wrapper<DeclaredType> wrappedDeclaredSetType();
-
- /**
- * The set type itself.
- */
- private DeclaredType declaredSetType() {
- return wrappedDeclaredSetType().get();
- }
-
- /**
- * {@code true} if the set type is the raw {@link Set} type.
- */
- public boolean isRawType() {
- return declaredSetType().getTypeArguments().isEmpty();
- }
-
- /**
- * The element type.
- */
- public TypeMirror elementType() {
- return declaredSetType().getTypeArguments().get(0);
- }
-
- /**
- * {@code true} if {@link #elementType()} is a {@code clazz}.
- */
- public boolean elementsAreTypeOf(Class<?> clazz) {
- return MoreTypes.isType(elementType()) && MoreTypes.isTypeOf(clazz, elementType());
- }
-
- /**
- * {@code T} if {@link #elementType()} is a {@code WrappingClass<T>}.
- *
- * @throws IllegalStateException if {@link #elementType()} is not a {@code WrappingClass<T>}
- * @throws IllegalArgumentException if {@code wrappingClass} does not have exactly one type
- * parameter
- */
- public TypeMirror unwrappedElementType(Class<?> wrappingClass) {
- checkArgument(
- wrappingClass.getTypeParameters().length == 1,
- "%s must have exactly one type parameter",
- wrappingClass);
- checkArgument(
- elementsAreTypeOf(wrappingClass),
- "expected elements to be %s, but this type is %s",
- wrappingClass,
- declaredSetType());
- return MoreTypes.asDeclared(elementType()).getTypeArguments().get(0);
- }
-
- /**
- * {@code true} if {@code type} is a {@link Set} type.
- */
- public static boolean isSet(TypeMirror type) {
- return MoreTypes.isType(type) && MoreTypes.isTypeOf(Set.class, type);
- }
-
- /**
- * {@code true} if {@code key.type()} is a {@link Set} type.
- */
- public static boolean isSet(Key key) {
- return isSet(key.type());
- }
-
- /**
- * Returns a {@link SetType} for {@code type}.
- *
- * @throws IllegalArgumentException if {@code type} is not a {@link Set} type
- */
- public static SetType from(TypeMirror type) {
- checkArgument(isSet(type), "%s must be a Set", type);
- return new AutoValue_SetType(MoreTypes.equivalence().wrap(MoreTypes.asDeclared(type)));
- }
-
- /**
- * Returns a {@link SetType} for {@code key}'s {@link Key#type() type}.
- *
- * @throws IllegalArgumentException if {@code key.type()} is not a {@link Set} type
- */
- public static SetType from(Key key) {
- return from (key.type());
- }
-}
diff --git a/java/dagger/internal/codegen/base/SimpleAnnotationMirror.java b/java/dagger/internal/codegen/base/SimpleAnnotationMirror.java
deleted file mode 100644
index 9690691..0000000
--- a/java/dagger/internal/codegen/base/SimpleAnnotationMirror.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 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.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Functions;
-import com.google.common.base.Joiner;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import java.util.Map;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-
-/** A representation of an annotation. */
-public final class SimpleAnnotationMirror implements AnnotationMirror {
- private final TypeElement annotationType;
- private final ImmutableMap<String, ? extends AnnotationValue> namedValues;
- private final ImmutableMap<ExecutableElement, ? extends AnnotationValue> elementValues;
-
- private SimpleAnnotationMirror(
- TypeElement annotationType, Map<String, ? extends AnnotationValue> namedValues) {
- checkArgument(
- annotationType.getKind().equals(ElementKind.ANNOTATION_TYPE),
- "annotationType must be an annotation: %s",
- annotationType);
- checkArgument(
- FluentIterable.from(methodsIn(annotationType.getEnclosedElements()))
- .transform(element -> element.getSimpleName().toString())
- .toSet()
- .equals(namedValues.keySet()),
- "namedValues must have values for exactly the members in %s: %s",
- annotationType,
- namedValues);
- this.annotationType = annotationType;
- this.namedValues = ImmutableMap.copyOf(namedValues);
- this.elementValues =
- Maps.toMap(
- methodsIn(annotationType.getEnclosedElements()),
- Functions.compose(
- Functions.forMap(namedValues), element -> element.getSimpleName().toString()));
- }
-
- @Override
- public DeclaredType getAnnotationType() {
- return MoreTypes.asDeclared(annotationType.asType());
- }
-
- @Override
- public Map<ExecutableElement, ? extends AnnotationValue> getElementValues() {
- return elementValues;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("@").append(annotationType.getQualifiedName());
- if (!namedValues.isEmpty()) {
- builder
- .append('(')
- .append(Joiner.on(", ").withKeyValueSeparator(" = ").join(namedValues))
- .append(')');
- }
- return builder.toString();
- }
-
- /**
- * An object representing an annotation instance.
- *
- * @param annotationType must be an annotation type with no members
- */
- public static AnnotationMirror of(TypeElement annotationType) {
- return of(annotationType, ImmutableMap.<String, AnnotationValue>of());
- }
-
- /**
- * An object representing an annotation instance.
- *
- * @param annotationType must be an annotation type
- * @param namedValues a value for every annotation member, including those with defaults, indexed
- * by simple name
- */
- private static AnnotationMirror of(
- TypeElement annotationType, Map<String, ? extends AnnotationValue> namedValues) {
- return new SimpleAnnotationMirror(annotationType, namedValues);
- }
-}
diff --git a/java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java b/java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java
deleted file mode 100644
index d595bcb..0000000
--- a/java/dagger/internal/codegen/base/SimpleTypeAnnotationValue.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 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.base;
-
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.AnnotationValueVisitor;
-import javax.lang.model.type.TypeMirror;
-
-/** An {@link AnnotationValue} that contains a {@link TypeMirror}. */
-final class SimpleTypeAnnotationValue implements AnnotationValue {
- private final TypeMirror value;
-
- SimpleTypeAnnotationValue(TypeMirror value) {
- this.value = value;
- }
-
- @Override
- public TypeMirror getValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return value + ".class";
- }
-
- @Override
- public <R, P> R accept(AnnotationValueVisitor<R, P> visitor, P parameter) {
- return visitor.visitType(getValue(), parameter);
- }
-}
diff --git a/java/dagger/internal/codegen/base/SourceFileGenerationException.java b/java/dagger/internal/codegen/base/SourceFileGenerationException.java
deleted file mode 100644
index 5553dd8..0000000
--- a/java/dagger/internal/codegen/base/SourceFileGenerationException.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2014 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.base;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.squareup.javapoet.ClassName;
-import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.Element;
-
-/**
- * An exception thrown to indicate that a source file could not be generated.
- *
- * <p>This exception <b>should not</b> be used to report detectable, logical errors as it may mask
- * other errors that might have been caught upon further processing. Use a {@link ValidationReport}
- * for that.
- */
-public final class SourceFileGenerationException extends Exception {
- private final Element associatedElement;
-
- SourceFileGenerationException(
- Optional<ClassName> generatedClassName, Throwable cause, Element associatedElement) {
- super(createMessage(generatedClassName, cause.getMessage()), cause);
- this.associatedElement = checkNotNull(associatedElement);
- }
-
- private static String createMessage(Optional<ClassName> generatedClassName, String message) {
- return String.format("Could not generate %s: %s.",
- generatedClassName.isPresent()
- ? generatedClassName.get()
- : "unknown file",
- message);
- }
-
- public void printMessageTo(Messager messager) {
- messager.printMessage(ERROR, getMessage(), associatedElement);
- }
-}
diff --git a/java/dagger/internal/codegen/base/SourceFileGenerator.java b/java/dagger/internal/codegen/base/SourceFileGenerator.java
deleted file mode 100644
index 02348a4..0000000
--- a/java/dagger/internal/codegen/base/SourceFileGenerator.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2014 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.base;
-
-import static com.google.auto.common.GeneratedAnnotations.generatedAnnotation;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-
-/**
- * A template class that provides a framework for properly handling IO while generating source files
- * from an annotation processor. Particularly, it makes a best effort to ensure that files that fail
- * to write successfully are deleted.
- *
- * @param <T> The input type from which source is to be generated.
- */
-public abstract class SourceFileGenerator<T> {
- private static final String GENERATED_COMMENTS = "https://dagger.dev";
-
- private final Filer filer;
- private final DaggerElements elements;
- private final SourceVersion sourceVersion;
-
- public SourceFileGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
- this.filer = checkNotNull(filer);
- this.elements = checkNotNull(elements);
- this.sourceVersion = checkNotNull(sourceVersion);
- }
-
- public SourceFileGenerator(SourceFileGenerator<T> delegate) {
- this(delegate.filer, delegate.elements, delegate.sourceVersion);
- }
-
- /**
- * Generates a source file to be compiled for {@code T}. Writes any generation exception to {@code
- * messager} and does not throw.
- */
- public void generate(T input, Messager messager) {
- try {
- generate(input);
- } catch (SourceFileGenerationException e) {
- e.printMessageTo(messager);
- }
- }
-
- /** Generates a source file to be compiled for {@code T}. */
- public void generate(T input) throws SourceFileGenerationException {
- Optional<TypeSpec.Builder> type = write(input);
- if (!type.isPresent()) {
- return;
- }
- try {
- buildJavaFile(input, type.get()).writeTo(filer);
- } catch (Exception e) {
- // if the code above threw a SFGE, use that
- Throwables.propagateIfPossible(e, SourceFileGenerationException.class);
- // otherwise, throw a new one
- throw new SourceFileGenerationException(Optional.empty(), e, originatingElement(input));
- }
- }
-
- private JavaFile buildJavaFile(T input, TypeSpec.Builder typeSpecBuilder) {
- typeSpecBuilder.addOriginatingElement(originatingElement(input));
- Optional<AnnotationSpec> generatedAnnotation =
- generatedAnnotation(elements, sourceVersion)
- .map(
- annotation ->
- AnnotationSpec.builder(ClassName.get(annotation))
- .addMember("value", "$S", "dagger.internal.codegen.ComponentProcessor")
- .addMember("comments", "$S", GENERATED_COMMENTS)
- .build());
- generatedAnnotation.ifPresent(typeSpecBuilder::addAnnotation);
-
- // TODO(b/134590785): remove this and only suppress annotations locally, if necessary
- typeSpecBuilder.addAnnotation(
- AnnotationSpecs.suppressWarnings(
- ImmutableSet.<Suppression>builder()
- .addAll(warningSuppressions())
- .add(UNCHECKED, RAWTYPES)
- .build()));
-
- JavaFile.Builder javaFileBuilder =
- JavaFile.builder(nameGeneratedType(input).packageName(), typeSpecBuilder.build())
- .skipJavaLangImports(true);
- if (!generatedAnnotation.isPresent()) {
- javaFileBuilder.addFileComment("Generated by Dagger ($L).", GENERATED_COMMENTS);
- }
- return javaFileBuilder.build();
- }
-
- /** Implementations should return the {@link ClassName} for the top-level type to be generated. */
- public abstract ClassName nameGeneratedType(T input);
-
- /** Returns the originating element of the generating type. */
- public abstract Element originatingElement(T input);
-
- /**
- * Returns a {@link TypeSpec.Builder type} to be generated for {@code T}, or {@link
- * Optional#empty()} if no file should be generated.
- */
- // TODO(ronshapiro): write() makes more sense in JavaWriter where all writers are mutable.
- // consider renaming to something like typeBuilder() which conveys the mutability of the result
- public abstract Optional<TypeSpec.Builder> write(T input);
-
- /** Returns {@link Suppression}s that are applied to files generated by this generator. */
- // TODO(b/134590785): When suppressions are removed locally, remove this and inline the usages
- protected ImmutableSet<Suppression> warningSuppressions() {
- return ImmutableSet.of();
- }
-}
diff --git a/java/dagger/internal/codegen/base/UniqueNameSet.java b/java/dagger/internal/codegen/base/UniqueNameSet.java
deleted file mode 100644
index c1ffe47..0000000
--- a/java/dagger/internal/codegen/base/UniqueNameSet.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 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.base;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/** A collector for names to be used in the same namespace that should not conflict. */
-public final class UniqueNameSet {
- private final Set<String> uniqueNames = new HashSet<>();
-
- /**
- * Generates a unique name using {@code base}. If {@code base} has not yet been added, it will be
- * returned as-is. If your {@code base} is healthy, this will always return {@code base}.
- */
- public String getUniqueName(CharSequence base) {
- String name = base.toString();
- for (int differentiator = 2; !uniqueNames.add(name); differentiator++) {
- name = base.toString() + differentiator;
- }
- return name;
- }
-
- /**
- * Adds {@code name} without any modification to the name set. Has no effect if {@code name} is
- * already present in the set.
- */
- public void claim(CharSequence name) {
- uniqueNames.add(name.toString());
- }
-}
diff --git a/java/dagger/internal/codegen/base/Util.java b/java/dagger/internal/codegen/base/Util.java
deleted file mode 100644
index e92b8ab..0000000
--- a/java/dagger/internal/codegen/base/Util.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2013 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.base;
-
-import java.util.Map;
-import java.util.function.Function;
-
-/** General utilities for the annotation processor. */
-public final class Util {
-
- /**
- * A version of {@link Map#computeIfAbsent(Object, Function)} that allows {@code mappingFunction}
- * to update {@code map}.
- */
- public static <K, V> V reentrantComputeIfAbsent(
- Map<K, V> map, K key, Function<? super K, ? extends V> mappingFunction) {
- V value = map.get(key);
- if (value == null) {
- value = mappingFunction.apply(key);
- if (value != null) {
- map.put(key, value);
- }
- }
- return value;
- }
-
- private Util() {}
-}
diff --git a/java/dagger/internal/codegen/binding/AnnotationExpression.java b/java/dagger/internal/codegen/binding/AnnotationExpression.java
deleted file mode 100644
index de0aea5..0000000
--- a/java/dagger/internal/codegen/binding/AnnotationExpression.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
-import static dagger.internal.codegen.binding.SourceFiles.classFileName;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static java.util.stream.Collectors.toList;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeName;
-import java.util.List;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-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.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor6;
-import javax.lang.model.util.SimpleTypeVisitor6;
-
-/**
- * Returns an expression creating an instance of the visited annotation type. Its parameter must be
- * a class as generated by {@link dagger.internal.codegen.writing.AnnotationCreatorGenerator}.
- *
- * <p>Note that {@link AnnotationValue#toString()} is the source-code representation of the value
- * <em>when used in an annotation</em>, which is not always the same as the representation needed
- * when creating the value in a method body.
- *
- * <p>For example, inside an annotation, a nested array of {@code int}s is simply {@code {1, 2, 3}},
- * but in code it would have to be {@code new int[] {1, 2, 3}}.
- */
-public class AnnotationExpression
- extends SimpleAnnotationValueVisitor6<CodeBlock, AnnotationValue> {
-
- private final AnnotationMirror annotation;
- private final ClassName creatorClass;
-
- AnnotationExpression(AnnotationMirror annotation) {
- this.annotation = annotation;
- this.creatorClass =
- getAnnotationCreatorClassName(
- MoreTypes.asTypeElement(annotation.getAnnotationType()));
- }
-
- /**
- * Returns an expression that calls static methods on the annotation's creator class to create an
- * annotation instance equivalent the annotation passed to the constructor.
- */
- CodeBlock getAnnotationInstanceExpression() {
- return getAnnotationInstanceExpression(annotation);
- }
-
- private CodeBlock getAnnotationInstanceExpression(AnnotationMirror annotation) {
- return CodeBlock.of(
- "$T.$L($L)",
- creatorClass,
- createMethodName(
- MoreElements.asType(annotation.getAnnotationType().asElement())),
- makeParametersCodeBlock(
- getAnnotationValuesWithDefaults(annotation)
- .entrySet()
- .stream()
- .map(entry -> getValueExpression(entry.getKey().getReturnType(), entry.getValue()))
- .collect(toList())));
- }
-
- /**
- * Returns the name of the generated class that contains the static {@code create} methods for an
- * annotation type.
- */
- public static ClassName getAnnotationCreatorClassName(TypeElement annotationType) {
- ClassName annotationTypeName = ClassName.get(annotationType);
- return annotationTypeName
- .topLevelClassName()
- .peerClass(classFileName(annotationTypeName) + "Creator");
- }
-
- public static String createMethodName(TypeElement annotationType) {
- return "create" + annotationType.getSimpleName();
- }
-
- /**
- * Returns an expression that evaluates to a {@code value} of a given type on an {@code
- * annotation}.
- */
- CodeBlock getValueExpression(TypeMirror valueType, AnnotationValue value) {
- return ARRAY_LITERAL_PREFIX.visit(valueType, this.visit(value, value));
- }
-
- @Override
- public CodeBlock visitEnumConstant(VariableElement c, AnnotationValue p) {
- return CodeBlock.of("$T.$L", c.getEnclosingElement(), c.getSimpleName());
- }
-
- @Override
- public CodeBlock visitAnnotation(AnnotationMirror a, AnnotationValue p) {
- return getAnnotationInstanceExpression(a);
- }
-
- @Override
- public CodeBlock visitType(TypeMirror t, AnnotationValue p) {
- return CodeBlock.of("$T.class", t);
- }
-
- @Override
- public CodeBlock visitString(String s, AnnotationValue p) {
- return CodeBlock.of("$S", s);
- }
-
- @Override
- public CodeBlock visitByte(byte b, AnnotationValue p) {
- return CodeBlock.of("(byte) $L", b);
- }
-
- @Override
- public CodeBlock visitChar(char c, AnnotationValue p) {
- return CodeBlock.of("$L", p);
- }
-
- @Override
- public CodeBlock visitDouble(double d, AnnotationValue p) {
- return CodeBlock.of("$LD", d);
- }
-
- @Override
- public CodeBlock visitFloat(float f, AnnotationValue p) {
- return CodeBlock.of("$LF", f);
- }
-
- @Override
- public CodeBlock visitLong(long i, AnnotationValue p) {
- return CodeBlock.of("$LL", i);
- }
-
- @Override
- public CodeBlock visitShort(short s, AnnotationValue p) {
- return CodeBlock.of("(short) $L", s);
- }
-
- @Override
- protected CodeBlock defaultAction(Object o, AnnotationValue p) {
- return CodeBlock.of("$L", o);
- }
-
- @Override
- public CodeBlock visitArray(List<? extends AnnotationValue> values, AnnotationValue p) {
- ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
- for (AnnotationValue value : values) {
- codeBlocks.add(this.visit(value, p));
- }
- return CodeBlock.of("{$L}", makeParametersCodeBlock(codeBlocks.build()));
- }
-
- /**
- * If the visited type is an array, prefixes the parameter code block with {@code new T[]}, where
- * {@code T} is the raw array component type.
- */
- private static final SimpleTypeVisitor6<CodeBlock, CodeBlock> ARRAY_LITERAL_PREFIX =
- new SimpleTypeVisitor6<CodeBlock, CodeBlock>() {
-
- @Override
- public CodeBlock visitArray(ArrayType t, CodeBlock p) {
- return CodeBlock.of("new $T[] $L", RAW_TYPE_NAME.visit(t.getComponentType()), p);
- }
-
- @Override
- protected CodeBlock defaultAction(TypeMirror e, CodeBlock p) {
- return p;
- }
- };
-
- /**
- * If the visited type is an array, returns the name of its raw component type; otherwise returns
- * the name of the type itself.
- */
- private static final SimpleTypeVisitor6<TypeName, Void> RAW_TYPE_NAME =
- new SimpleTypeVisitor6<TypeName, Void>() {
- @Override
- public TypeName visitDeclared(DeclaredType t, Void p) {
- return ClassName.get(MoreTypes.asTypeElement(t));
- }
-
- @Override
- protected TypeName defaultAction(TypeMirror e, Void p) {
- return TypeName.get(e);
- }
- };
-}
diff --git a/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java b/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
deleted file mode 100644
index 8d6ee5d..0000000
--- a/java/dagger/internal/codegen/binding/AssistedInjectionAnnotations.java
+++ /dev/null
@@ -1,299 +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.internal.codegen.binding;
-
-import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getStringValue;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.util.ElementFilter.constructorsIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-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.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import java.util.List;
-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.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/** Assisted injection utility methods. */
-public final class AssistedInjectionAnnotations {
- /** Returns the factory method for the given factory {@link TypeElement}. */
- public static ExecutableElement assistedFactoryMethod(
- TypeElement factory, DaggerElements elements, DaggerTypes types) {
- return getOnlyElement(assistedFactoryMethods(factory, elements, types));
- }
-
- /** Returns the list of abstract factory methods for the given factory {@link TypeElement}. */
- public static ImmutableSet<ExecutableElement> assistedFactoryMethods(
- TypeElement factory, DaggerElements elements, DaggerTypes types) {
- return MoreElements.getLocalAndInheritedMethods(factory, types, elements).stream()
- .filter(method -> method.getModifiers().contains(ABSTRACT))
- .filter(method -> !method.isDefault())
- .collect(toImmutableSet());
- }
-
- /** Returns {@code true} if the element uses assisted injection. */
- public static boolean isAssistedInjectionType(TypeElement typeElement) {
- ImmutableSet<ExecutableElement> injectConstructors = assistedInjectedConstructors(typeElement);
- return !injectConstructors.isEmpty()
- && isAnnotationPresent(getOnlyElement(injectConstructors), AssistedInject.class);
- }
-
- /** Returns {@code true} if this binding is an assisted factory. */
- public static boolean isAssistedFactoryType(Element element) {
- return isAnnotationPresent(element, AssistedFactory.class);
- }
-
- /**
- * Returns the list of assisted parameters as {@link ParameterSpec}s.
- *
- * <p>The type of each parameter will be the resolved type given by the binding key, and the name
- * of each parameter will be the name given in the {@link
- * dagger.assisted.AssistedInject}-annotated constructor.
- */
- public static ImmutableList<ParameterSpec> assistedParameterSpecs(
- Binding binding, DaggerTypes types) {
- checkArgument(binding.kind() == BindingKind.ASSISTED_INJECTION);
- ExecutableElement constructor = asExecutable(binding.bindingElement().get());
- ExecutableType constructorType =
- asExecutable(types.asMemberOf(asDeclared(binding.key().type()), constructor));
- return assistedParameterSpecs(constructor.getParameters(), constructorType.getParameterTypes());
- }
-
- private static ImmutableList<ParameterSpec> assistedParameterSpecs(
- List<? extends VariableElement> paramElements, List<? extends TypeMirror> paramTypes) {
- ImmutableList.Builder<ParameterSpec> assistedParameterSpecs = ImmutableList.builder();
- for (int i = 0; i < paramElements.size(); i++) {
- VariableElement paramElement = paramElements.get(i);
- TypeMirror paramType = paramTypes.get(i);
- if (isAssistedParameter(paramElement)) {
- assistedParameterSpecs.add(
- ParameterSpec.builder(TypeName.get(paramType), paramElement.getSimpleName().toString())
- .build());
- }
- }
- return assistedParameterSpecs.build();
- }
-
- /**
- * Returns the list of assisted factory parameters as {@link ParameterSpec}s.
- *
- * <p>The type of each parameter will be the resolved type given by the binding key, and the name
- * of each parameter will be the name given in the {@link
- * dagger.assisted.AssistedInject}-annotated constructor.
- */
- public static ImmutableList<ParameterSpec> assistedFactoryParameterSpecs(
- Binding binding, DaggerElements elements, DaggerTypes types) {
- checkArgument(binding.kind() == BindingKind.ASSISTED_FACTORY);
-
- AssistedFactoryMetadata metadata =
- AssistedFactoryMetadata.create(binding.bindingElement().get().asType(), elements, types);
- ExecutableType factoryMethodType =
- asExecutable(types.asMemberOf(asDeclared(binding.key().type()), metadata.factoryMethod()));
- return assistedParameterSpecs(
- // Use the order of the parameters from the @AssistedFactory method but use the parameter
- // names of the @AssistedInject constructor.
- metadata.assistedFactoryAssistedParameters().stream()
- .map(metadata.assistedInjectAssistedParametersMap()::get)
- .collect(toImmutableList()),
- factoryMethodType.getParameterTypes());
- }
-
- /** Returns the constructors in {@code type} that are annotated with {@link AssistedInject}. */
- public static ImmutableSet<ExecutableElement> assistedInjectedConstructors(TypeElement type) {
- return constructorsIn(type.getEnclosedElements()).stream()
- .filter(constructor -> isAnnotationPresent(constructor, AssistedInject.class))
- .collect(toImmutableSet());
- }
-
- public static ImmutableList<VariableElement> assistedParameters(Binding binding) {
- return binding.kind() == BindingKind.ASSISTED_INJECTION
- ? assistedParameters(asExecutable(binding.bindingElement().get()))
- : ImmutableList.of();
- }
-
- private static ImmutableList<VariableElement> assistedParameters(ExecutableElement constructor) {
- return constructor.getParameters().stream()
- .filter(AssistedInjectionAnnotations::isAssistedParameter)
- .collect(toImmutableList());
- }
-
- /** Returns {@code true} if this binding is uses assisted injection. */
- public static boolean isAssistedParameter(VariableElement param) {
- return isAnnotationPresent(MoreElements.asVariable(param), Assisted.class);
- }
-
- /** Metadata about an {@link dagger.assisted.AssistedFactory} annotated type. */
- @AutoValue
- public abstract static class AssistedFactoryMetadata {
- public static AssistedFactoryMetadata create(
- TypeMirror factory, DaggerElements elements, DaggerTypes types) {
- DeclaredType factoryType = asDeclared(factory);
- TypeElement factoryElement = asTypeElement(factoryType);
- ExecutableElement factoryMethod = assistedFactoryMethod(factoryElement, elements, types);
- ExecutableType factoryMethodType = asExecutable(types.asMemberOf(factoryType, factoryMethod));
- DeclaredType assistedInjectType = asDeclared(factoryMethodType.getReturnType());
- return new AutoValue_AssistedInjectionAnnotations_AssistedFactoryMetadata(
- factoryElement,
- factoryType,
- factoryMethod,
- factoryMethodType,
- asTypeElement(assistedInjectType),
- assistedInjectType,
- AssistedInjectionAnnotations.assistedInjectAssistedParameters(assistedInjectType, types),
- AssistedInjectionAnnotations.assistedFactoryAssistedParameters(
- factoryMethod, factoryMethodType));
- }
-
- public abstract TypeElement factory();
-
- public abstract DeclaredType factoryType();
-
- public abstract ExecutableElement factoryMethod();
-
- public abstract ExecutableType factoryMethodType();
-
- public abstract TypeElement assistedInjectElement();
-
- public abstract DeclaredType assistedInjectType();
-
- public abstract ImmutableList<AssistedParameter> assistedInjectAssistedParameters();
-
- public abstract ImmutableList<AssistedParameter> assistedFactoryAssistedParameters();
-
- @Memoized
- public ImmutableMap<AssistedParameter, VariableElement> assistedInjectAssistedParametersMap() {
- ImmutableMap.Builder<AssistedParameter, VariableElement> builder = ImmutableMap.builder();
- for (AssistedParameter assistedParameter : assistedInjectAssistedParameters()) {
- builder.put(assistedParameter, assistedParameter.variableElement);
- }
- return builder.build();
- }
-
- @Memoized
- public ImmutableMap<AssistedParameter, VariableElement> assistedFactoryAssistedParametersMap() {
- ImmutableMap.Builder<AssistedParameter, VariableElement> builder = ImmutableMap.builder();
- for (AssistedParameter assistedParameter : assistedFactoryAssistedParameters()) {
- builder.put(assistedParameter, assistedParameter.variableElement);
- }
- return builder.build();
- }
- }
-
- /**
- * Metadata about an {@link Assisted} annotated parameter.
- *
- * <p>This parameter can represent an {@link Assisted} annotated parameter from an {@link
- * AssistedInject} constructor or an {@link AssistedFactory} method.
- */
- @AutoValue
- public abstract static class AssistedParameter {
- public static AssistedParameter create(VariableElement parameter, TypeMirror parameterType) {
- AssistedParameter assistedParameter =
- new AutoValue_AssistedInjectionAnnotations_AssistedParameter(
- getAnnotationMirror(parameter, Assisted.class)
- .map(assisted -> getStringValue(assisted, "value"))
- .orElse(""),
- MoreTypes.equivalence().wrap(parameterType));
- assistedParameter.variableElement = parameter;
- return assistedParameter;
- }
-
- private VariableElement variableElement;
-
- /** Returns the string qualifier from the {@link Assisted#value()}. */
- public abstract String qualifier();
-
- /** Returns the wrapper for the type annotated with {@link Assisted}. */
- public abstract Equivalence.Wrapper<TypeMirror> wrappedType();
-
- /** Returns the type annotated with {@link Assisted}. */
- public final TypeMirror type() {
- return wrappedType().get();
- }
-
- public final VariableElement variableElement() {
- return variableElement;
- }
-
- @Override
- public final String toString() {
- return qualifier().isEmpty()
- ? String.format("@Assisted %s", type())
- : String.format("@Assisted(\"%s\") %s", qualifier(), type());
- }
- }
-
- public static ImmutableList<AssistedParameter> assistedInjectAssistedParameters(
- DeclaredType assistedInjectType, DaggerTypes types) {
- // We keep track of the constructor both as an ExecutableElement to access @Assisted
- // parameters and as an ExecutableType to access the resolved parameter types.
- ExecutableElement assistedInjectConstructor =
- getOnlyElement(assistedInjectedConstructors(asTypeElement(assistedInjectType)));
- ExecutableType assistedInjectConstructorType =
- asExecutable(types.asMemberOf(assistedInjectType, assistedInjectConstructor));
-
- ImmutableList.Builder<AssistedParameter> builder = ImmutableList.builder();
- for (int i = 0; i < assistedInjectConstructor.getParameters().size(); i++) {
- VariableElement parameter = assistedInjectConstructor.getParameters().get(i);
- TypeMirror parameterType = assistedInjectConstructorType.getParameterTypes().get(i);
- if (isAnnotationPresent(parameter, Assisted.class)) {
- builder.add(AssistedParameter.create(parameter, parameterType));
- }
- }
- return builder.build();
- }
-
- public static ImmutableList<AssistedParameter> assistedFactoryAssistedParameters(
- ExecutableElement factoryMethod, ExecutableType factoryMethodType) {
- ImmutableList.Builder<AssistedParameter> builder = ImmutableList.builder();
- for (int i = 0; i < factoryMethod.getParameters().size(); i++) {
- VariableElement parameter = factoryMethod.getParameters().get(i);
- TypeMirror parameterType = factoryMethodType.getParameterTypes().get(i);
- builder.add(AssistedParameter.create(parameter, parameterType));
- }
- return builder.build();
- }
-
- private AssistedInjectionAnnotations() {}
-}
diff --git a/java/dagger/internal/codegen/binding/BUILD b/java/dagger/internal/codegen/binding/BUILD
deleted file mode 100644
index ff8db8f..0000000
--- a/java/dagger/internal/codegen/binding/BUILD
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) 2017 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:
-# JavaPoet extensions for use in Dagger
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "binding",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/internal/guava:graph",
- "//java/dagger/model:internal-proxies",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/binding/Binding.java b/java/dagger/internal/codegen/binding/Binding.java
deleted file mode 100644
index 0d4eef6..0000000
--- a/java/dagger/internal/codegen/binding/Binding.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.Suppliers.memoize;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Scope;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleTypeVisitor6;
-
-/**
- * An abstract type for classes representing a Dagger binding. Particularly, contains the {@link
- * Element} that generated the binding and the {@link DependencyRequest} instances that are required
- * to satisfy the binding, but leaves the specifics of the <i>mechanism</i> of the binding to the
- * subtypes.
- */
-public abstract class Binding extends BindingDeclaration {
-
- /**
- * Returns {@code true} if using this binding requires an instance of the {@link
- * #contributingModule()}.
- */
- public boolean requiresModuleInstance() {
- if (!bindingElement().isPresent() || !contributingModule().isPresent()) {
- return false;
- }
- Set<Modifier> modifiers = bindingElement().get().getModifiers();
- return !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC);
- }
-
- /**
- * 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}.
- */
- public abstract boolean isNullable();
-
- /** The kind of binding this instance represents. */
- public abstract BindingKind kind();
-
- /** The {@link BindingType} of this binding. */
- public abstract BindingType bindingType();
-
- /** The {@link FrameworkType} of this binding. */
- public final FrameworkType frameworkType() {
- return FrameworkType.forBindingType(bindingType());
- }
-
- /**
- * The explicit set of {@link DependencyRequest dependencies} required to satisfy this binding as
- * defined by the user-defined injection sites.
- */
- public abstract ImmutableSet<DependencyRequest> explicitDependencies();
-
- /**
- * The set of {@link DependencyRequest dependencies} that are added by the framework rather than a
- * user-defined injection site. This returns an unmodifiable set.
- */
- public ImmutableSet<DependencyRequest> implicitDependencies() {
- return ImmutableSet.of();
- }
-
- private final Supplier<ImmutableSet<DependencyRequest>> dependencies =
- memoize(
- () -> {
- ImmutableSet<DependencyRequest> implicitDependencies = implicitDependencies();
- return ImmutableSet.copyOf(
- implicitDependencies.isEmpty()
- ? explicitDependencies()
- : Sets.union(implicitDependencies, explicitDependencies()));
- });
-
- /**
- * The set of {@link DependencyRequest dependencies} required to satisfy this binding. This is the
- * union of {@link #explicitDependencies()} and {@link #implicitDependencies()}. This returns an
- * unmodifiable set.
- */
- public final ImmutableSet<DependencyRequest> dependencies() {
- return dependencies.get();
- }
-
- /**
- * If this binding's key's type parameters are different from those of the {@link
- * #bindingTypeElement()}, this is the binding for the {@link #bindingTypeElement()}'s unresolved
- * type.
- */
- public abstract Optional<? extends Binding> unresolved();
-
- public Optional<Scope> scope() {
- return Optional.empty();
- }
-
- // TODO(sameb): Remove the TypeElement parameter and pull it from the TypeMirror.
- static boolean hasNonDefaultTypeParameters(
- TypeElement element, TypeMirror type, DaggerTypes types) {
- // If the element has no type parameters, nothing can be wrong.
- if (element.getTypeParameters().isEmpty()) {
- return false;
- }
-
- List<TypeMirror> defaultTypes = Lists.newArrayList();
- for (TypeParameterElement parameter : element.getTypeParameters()) {
- defaultTypes.add(parameter.asType());
- }
-
- List<TypeMirror> actualTypes =
- type.accept(
- new SimpleTypeVisitor6<List<TypeMirror>, Void>() {
- @Override
- protected List<TypeMirror> defaultAction(TypeMirror e, Void p) {
- return ImmutableList.of();
- }
-
- @Override
- public List<TypeMirror> visitDeclared(DeclaredType t, Void p) {
- return ImmutableList.<TypeMirror>copyOf(t.getTypeArguments());
- }
- },
- null);
-
- // The actual type parameter size can be different if the user is using a raw type.
- if (defaultTypes.size() != actualTypes.size()) {
- return true;
- }
-
- for (int i = 0; i < defaultTypes.size(); i++) {
- if (!types.isSameType(defaultTypes.get(i), actualTypes.get(i))) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingDeclaration.java b/java/dagger/internal/codegen/binding/BindingDeclaration.java
deleted file mode 100644
index 712260f..0000000
--- a/java/dagger/internal/codegen/binding/BindingDeclaration.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static dagger.internal.codegen.extension.Optionals.emptiesLast;
-import static java.util.Comparator.comparing;
-
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.BindingKind;
-import dagger.model.Key;
-import java.util.Comparator;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/** An object that declares or specifies a binding. */
-public abstract class BindingDeclaration {
- /**
- * A comparator that compares binding declarations with elements.
- *
- * <p>Compares, in order:
- *
- * <ol>
- * <li>Contributing module or enclosing type name
- * <li>Binding element's simple name
- * <li>Binding element's type
- * </ol>
- *
- * Any binding declarations without elements are last.
- */
- public static final Comparator<BindingDeclaration> COMPARATOR =
- comparing(
- (BindingDeclaration declaration) ->
- declaration.contributingModule().isPresent()
- ? declaration.contributingModule()
- : declaration.bindingTypeElement(),
- emptiesLast(comparing((TypeElement type) -> type.getQualifiedName().toString())))
- .thenComparing(
- (BindingDeclaration declaration) -> declaration.bindingElement(),
- emptiesLast(
- comparing((Element element) -> element.getSimpleName().toString())
- .thenComparing((Element element) -> element.asType().toString())));
-
- /** The {@link Key} of this declaration. */
- public abstract Key key();
-
- /**
- * The {@link Element} 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.
- */
- public abstract Optional<Element> bindingElement();
-
- /**
- * The type enclosing the {@link #bindingElement()}, or {@link Optional#empty()} if {@link
- * #bindingElement()} is empty.
- */
- public final Optional<TypeElement> bindingTypeElement() {
- return bindingElement().map(DaggerElements::closestEnclosingTypeElement);
- }
-
- /**
- * The installed module class that contributed the {@link #bindingElement()}. May be a subclass of
- * the class that contains {@link #bindingElement()}. Absent if {@link #bindingElement()} is
- * empty.
- */
- public abstract Optional<TypeElement> contributingModule();
-}
diff --git a/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java b/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
deleted file mode 100644
index 8476497..0000000
--- a/java/dagger/internal/codegen/binding/BindingDeclarationFormatter.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.common.collect.Sets.immutableEnumSet;
-import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
-import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static javax.lang.model.element.ElementKind.PARAMETER;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.EXECUTABLE;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.base.Formatter;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-
-/**
- * Formats a {@link BindingDeclaration} into a {@link String} suitable for use in error messages.
- */
-public final class BindingDeclarationFormatter extends Formatter<BindingDeclaration> {
- private static final ImmutableSet<TypeKind> FORMATTABLE_ELEMENT_TYPE_KINDS =
- immutableEnumSet(EXECUTABLE, DECLARED);
-
- private final MethodSignatureFormatter methodSignatureFormatter;
-
- @Inject
- BindingDeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter) {
- this.methodSignatureFormatter = methodSignatureFormatter;
- }
-
- /**
- * Returns {@code true} for declarations that this formatter can format. Specifically bindings
- * from subcomponent declarations or those with {@linkplain BindingDeclaration#bindingElement()
- * binding elements} that are methods, constructors, or types.
- */
- public boolean canFormat(BindingDeclaration bindingDeclaration) {
- if (bindingDeclaration instanceof SubcomponentDeclaration) {
- return true;
- }
- if (bindingDeclaration.bindingElement().isPresent()) {
- Element bindingElement = bindingDeclaration.bindingElement().get();
- return bindingElement.getKind().equals(PARAMETER)
- || FORMATTABLE_ELEMENT_TYPE_KINDS.contains(bindingElement.asType().getKind());
- }
- // TODO(dpb): validate whether what this is doing is correct
- return false;
- }
-
- @Override
- public String format(BindingDeclaration bindingDeclaration) {
- if (bindingDeclaration instanceof SubcomponentDeclaration) {
- return formatSubcomponentDeclaration((SubcomponentDeclaration) bindingDeclaration);
- }
-
- if (bindingDeclaration.bindingElement().isPresent()) {
- Element bindingElement = bindingDeclaration.bindingElement().get();
- if (bindingElement.getKind().equals(PARAMETER)) {
- return elementToString(bindingElement);
- }
-
- switch (bindingElement.asType().getKind()) {
- case EXECUTABLE:
- return methodSignatureFormatter.format(
- MoreElements.asExecutable(bindingElement),
- bindingDeclaration
- .contributingModule()
- .map(module -> MoreTypes.asDeclared(module.asType())));
-
- case DECLARED:
- return stripCommonTypePrefixes(bindingElement.asType().toString());
-
- default:
- throw new IllegalArgumentException(
- "Formatting unsupported for element: " + bindingElement);
- }
- }
-
- return String.format(
- "Dagger-generated binding for %s",
- stripCommonTypePrefixes(bindingDeclaration.key().toString()));
- }
-
- private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
- ImmutableList<TypeElement> moduleSubcomponents =
- subcomponentDeclaration.moduleAnnotation().subcomponents();
- int index = moduleSubcomponents.indexOf(subcomponentDeclaration.subcomponentType());
- StringBuilder annotationValue = new StringBuilder();
- if (moduleSubcomponents.size() != 1) {
- annotationValue.append("{");
- }
- annotationValue.append(
- formatArgumentInList(
- index,
- moduleSubcomponents.size(),
- subcomponentDeclaration.subcomponentType().getQualifiedName() + ".class"));
- if (moduleSubcomponents.size() != 1) {
- annotationValue.append("}");
- }
-
- return String.format(
- "@%s(subcomponents = %s) for %s",
- subcomponentDeclaration.moduleAnnotation().annotationName(),
- annotationValue,
- subcomponentDeclaration.contributingModule().get());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingFactory.java b/java/dagger/internal/codegen/binding/BindingFactory.java
deleted file mode 100644
index 6f2fc80..0000000
--- a/java/dagger/internal/codegen/binding/BindingFactory.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkArgument;
-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.base.MoreAnnotationMirrors.wrapOptionalInEquivalence;
-import static dagger.internal.codegen.base.Scopes.uniqueScopeOf;
-import static dagger.internal.codegen.binding.Binding.hasNonDefaultTypeParameters;
-import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentProductionMethod;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
-import static dagger.internal.codegen.binding.ContributionBinding.bindingKindForMultibindingKey;
-import static dagger.internal.codegen.binding.MapKeys.getMapKey;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.model.BindingKind.ASSISTED_FACTORY;
-import static dagger.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.model.BindingKind.BOUND_INSTANCE;
-import static dagger.model.BindingKind.COMPONENT;
-import static dagger.model.BindingKind.COMPONENT_DEPENDENCY;
-import static dagger.model.BindingKind.COMPONENT_PRODUCTION;
-import static dagger.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.model.BindingKind.DELEGATE;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.MEMBERS_INJECTOR;
-import static dagger.model.BindingKind.OPTIONAL;
-import static dagger.model.BindingKind.PRODUCTION;
-import static dagger.model.BindingKind.PROVISION;
-import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
-import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
-import static javax.lang.model.element.ElementKind.METHOD;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Iterables;
-import dagger.Module;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.ProductionBinding.ProductionKind;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import java.util.Optional;
-import java.util.function.BiFunction;
-import javax.inject.Inject;
-import javax.inject.Provider;
-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.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/** A factory for {@link Binding} objects. */
-public final class BindingFactory {
- private final DaggerTypes types;
- private final KeyFactory keyFactory;
- private final DependencyRequestFactory dependencyRequestFactory;
- private final InjectionSiteFactory injectionSiteFactory;
- private final DaggerElements elements;
- private final InjectionAnnotations injectionAnnotations;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- BindingFactory(
- DaggerTypes types,
- DaggerElements elements,
- KeyFactory keyFactory,
- DependencyRequestFactory dependencyRequestFactory,
- InjectionSiteFactory injectionSiteFactory,
- InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil) {
- this.types = types;
- this.elements = elements;
- this.keyFactory = keyFactory;
- this.dependencyRequestFactory = dependencyRequestFactory;
- this.injectionSiteFactory = injectionSiteFactory;
- this.injectionAnnotations = injectionAnnotations;
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Returns an {@link dagger.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
- * binding should be for the parameterized type
- */
- // TODO(dpb): See if we can just pass the parameterized type and not also the constructor.
- public ProvisionBinding injectionBinding(
- ExecutableElement constructorElement, Optional<TypeMirror> resolvedType) {
- checkArgument(constructorElement.getKind().equals(CONSTRUCTOR));
- checkArgument(
- isAnnotationPresent(constructorElement, Inject.class)
- || isAnnotationPresent(constructorElement, AssistedInject.class));
- checkArgument(!injectionAnnotations.getQualifier(constructorElement).isPresent());
-
- ExecutableType constructorType = MoreTypes.asExecutable(constructorElement.asType());
- DeclaredType constructedType =
- MoreTypes.asDeclared(constructorElement.getEnclosingElement().asType());
- // If the class this is constructing has some type arguments, resolve everything.
- if (!constructedType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
- DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get());
- // Validate that we're resolving from the correct type.
- checkState(
- types.isSameType(types.erasure(resolved), types.erasure(constructedType)),
- "erased expected type: %s, erased actual type: %s",
- types.erasure(resolved),
- types.erasure(constructedType));
- constructorType = MoreTypes.asExecutable(types.asMemberOf(resolved, constructorElement));
- constructedType = resolved;
- }
-
- // Collect all dependency requests within the provision method.
- // Note: we filter out @Assisted parameters since these aren't considered dependency requests.
- ImmutableSet.Builder<DependencyRequest> provisionDependencies = ImmutableSet.builder();
- for (int i = 0; i < constructorElement.getParameters().size(); i++) {
- VariableElement parameter = constructorElement.getParameters().get(i);
- TypeMirror parameterType = constructorType.getParameterTypes().get(i);
- if (!AssistedInjectionAnnotations.isAssistedParameter(parameter)) {
- provisionDependencies.add(
- dependencyRequestFactory.forRequiredResolvedVariable(parameter, parameterType));
- }
- }
-
- Key key = keyFactory.forInjectConstructorWithResolvedType(constructedType);
- ProvisionBinding.Builder builder =
- ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .bindingElement(constructorElement)
- .key(key)
- .provisionDependencies(provisionDependencies.build())
- .injectionSites(injectionSiteFactory.getInjectionSites(constructedType))
- .kind(
- isAnnotationPresent(constructorElement, AssistedInject.class)
- ? ASSISTED_INJECTION
- : INJECTION)
- .scope(uniqueScopeOf(constructorElement.getEnclosingElement()));
-
- TypeElement bindingTypeElement = MoreElements.asType(constructorElement.getEnclosingElement());
- if (hasNonDefaultTypeParameters(bindingTypeElement, key.type(), types)) {
- builder.unresolved(injectionBinding(constructorElement, Optional.empty()));
- }
- return builder.build();
- }
-
- public ProvisionBinding assistedFactoryBinding(
- TypeElement factory, Optional<TypeMirror> resolvedType) {
-
- // If the class this is constructing has some type arguments, resolve everything.
- DeclaredType factoryType = MoreTypes.asDeclared(factory.asType());
- if (!factoryType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
- DeclaredType resolved = MoreTypes.asDeclared(resolvedType.get());
- // Validate that we're resolving from the correct type by checking that the erasure of the
- // resolvedType is the same as the erasure of the factoryType.
- checkState(
- types.isSameType(types.erasure(resolved), types.erasure(factoryType)),
- "erased expected type: %s, erased actual type: %s",
- types.erasure(resolved),
- types.erasure(factoryType));
- factoryType = resolved;
- }
-
- ExecutableElement factoryMethod =
- AssistedInjectionAnnotations.assistedFactoryMethod(factory, elements, types);
- ExecutableType factoryMethodType =
- MoreTypes.asExecutable(types.asMemberOf(factoryType, factoryMethod));
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .key(Key.builder(factoryType).build())
- .bindingElement(factory)
- .provisionDependencies(
- ImmutableSet.of(
- DependencyRequest.builder()
- .key(Key.builder(factoryMethodType.getReturnType()).build())
- .kind(RequestKind.PROVIDER)
- .build()))
- .kind(ASSISTED_FACTORY)
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#PROVISION} binding for a {@code @Provides}-annotated
- * method.
- *
- * @param contributedBy the installed module that declares or inherits the method
- */
- public ProvisionBinding providesMethodBinding(
- ExecutableElement providesMethod, TypeElement contributedBy) {
- return setMethodBindingProperties(
- ProvisionBinding.builder(),
- providesMethod,
- contributedBy,
- keyFactory.forProvidesMethod(providesMethod, contributedBy),
- this::providesMethodBinding)
- .kind(PROVISION)
- .scope(uniqueScopeOf(providesMethod))
- .nullableType(getNullableType(providesMethod))
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#PRODUCTION} binding for a {@code @Produces}-annotated
- * method.
- *
- * @param contributedBy the installed module that declares or inherits the method
- */
- public ProductionBinding producesMethodBinding(
- ExecutableElement producesMethod, TypeElement contributedBy) {
- // TODO(beder): Add nullability checking with Java 8.
- ProductionBinding.Builder builder =
- setMethodBindingProperties(
- ProductionBinding.builder(),
- producesMethod,
- contributedBy,
- keyFactory.forProducesMethod(producesMethod, contributedBy),
- this::producesMethodBinding)
- .kind(PRODUCTION)
- .productionKind(ProductionKind.fromProducesMethod(producesMethod))
- .thrownTypes(producesMethod.getThrownTypes())
- .executorRequest(dependencyRequestFactory.forProductionImplementationExecutor())
- .monitorRequest(dependencyRequestFactory.forProductionComponentMonitor());
- return builder.build();
- }
-
- private <C extends ContributionBinding, B extends ContributionBinding.Builder<C, B>>
- B setMethodBindingProperties(
- B builder,
- ExecutableElement method,
- TypeElement contributedBy,
- Key key,
- BiFunction<ExecutableElement, TypeElement, C> create) {
- checkArgument(method.getKind().equals(METHOD));
- ExecutableType methodType =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(contributedBy.asType()), method));
- if (!types.isSameType(methodType, method.asType())) {
- builder.unresolved(create.apply(method, MoreElements.asType(method.getEnclosingElement())));
- }
- boolean isKotlinObject =
- metadataUtil.isObjectClass(contributedBy)
- || metadataUtil.isCompanionObjectClass(contributedBy);
- return builder
- .contributionType(ContributionType.fromBindingElement(method))
- .bindingElement(method)
- .contributingModule(contributedBy)
- .isContributingModuleKotlinObject(isKotlinObject)
- .key(key)
- .dependencies(
- dependencyRequestFactory.forRequiredResolvedVariables(
- method.getParameters(), methodType.getParameterTypes()))
- .wrappedMapKeyAnnotation(wrapOptionalInEquivalence(getMapKey(method)));
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#MULTIBOUND_MAP} or {@link
- * dagger.model.BindingKind#MULTIBOUND_SET} binding given a set of multibinding contribution
- * bindings.
- *
- * @param key a key that may be satisfied by a multibinding
- */
- public ContributionBinding syntheticMultibinding(
- Key key, Iterable<ContributionBinding> multibindingContributions) {
- ContributionBinding.Builder<?, ?> builder =
- multibindingRequiresProduction(key, multibindingContributions)
- ? ProductionBinding.builder()
- : ProvisionBinding.builder();
- return builder
- .contributionType(ContributionType.UNIQUE)
- .key(key)
- .dependencies(
- dependencyRequestFactory.forMultibindingContributions(key, multibindingContributions))
- .kind(bindingKindForMultibindingKey(key))
- .build();
- }
-
- private boolean multibindingRequiresProduction(
- Key key, Iterable<ContributionBinding> multibindingContributions) {
- if (MapType.isMap(key)) {
- MapType mapType = MapType.from(key);
- if (mapType.valuesAreTypeOf(Producer.class) || mapType.valuesAreTypeOf(Produced.class)) {
- return true;
- }
- } else if (SetType.isSet(key) && SetType.from(key).elementsAreTypeOf(Produced.class)) {
- return true;
- }
- return Iterables.any(
- multibindingContributions, binding -> binding.bindingType().equals(BindingType.PRODUCTION));
- }
-
- /** Returns a {@link dagger.model.BindingKind#COMPONENT} binding for the component. */
- public ProvisionBinding componentBinding(TypeElement componentDefinitionType) {
- checkNotNull(componentDefinitionType);
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .bindingElement(componentDefinitionType)
- .key(keyFactory.forType(componentDefinitionType.asType()))
- .kind(COMPONENT)
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#COMPONENT_DEPENDENCY} binding for a component's
- * dependency.
- */
- public ProvisionBinding componentDependencyBinding(ComponentRequirement dependency) {
- checkNotNull(dependency);
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .bindingElement(dependency.typeElement())
- .key(keyFactory.forType(dependency.type()))
- .kind(COMPONENT_DEPENDENCY)
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#COMPONENT_PROVISION} or {@link
- * dagger.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
- */
- public ContributionBinding componentDependencyMethodBinding(
- ComponentDescriptor componentDescriptor, ExecutableElement dependencyMethod) {
- checkArgument(dependencyMethod.getKind().equals(METHOD));
- checkArgument(dependencyMethod.getParameters().isEmpty());
- ContributionBinding.Builder<?, ?> builder;
- if (componentDescriptor.isProduction()
- && isComponentProductionMethod(elements, dependencyMethod)) {
- builder =
- ProductionBinding.builder()
- .key(keyFactory.forProductionComponentMethod(dependencyMethod))
- .kind(COMPONENT_PRODUCTION)
- .thrownTypes(dependencyMethod.getThrownTypes());
- } else {
- builder =
- ProvisionBinding.builder()
- .key(keyFactory.forComponentMethod(dependencyMethod))
- .nullableType(getNullableType(dependencyMethod))
- .kind(COMPONENT_PROVISION)
- .scope(uniqueScopeOf(dependencyMethod));
- }
- return builder
- .contributionType(ContributionType.UNIQUE)
- .bindingElement(dependencyMethod)
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#BOUND_INSTANCE} binding for a
- * {@code @BindsInstance}-annotated builder setter method or factory method parameter.
- */
- ProvisionBinding boundInstanceBinding(ComponentRequirement requirement, Element element) {
- checkArgument(element instanceof VariableElement || element instanceof ExecutableElement);
- VariableElement parameterElement =
- element instanceof VariableElement
- ? MoreElements.asVariable(element)
- : getOnlyElement(MoreElements.asExecutable(element).getParameters());
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .bindingElement(element)
- .key(requirement.key().get())
- .nullableType(getNullableType(parameterElement))
- .kind(BOUND_INSTANCE)
- .build();
- }
-
- /**
- * Returns a {@link dagger.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()}.
- *
- * @param component the component that declares or inherits the method
- */
- ProvisionBinding subcomponentCreatorBinding(
- ExecutableElement subcomponentCreatorMethod, TypeElement component) {
- checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD));
- checkArgument(subcomponentCreatorMethod.getParameters().isEmpty());
- Key key =
- keyFactory.forSubcomponentCreatorMethod(
- subcomponentCreatorMethod, asDeclared(component.asType()));
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .bindingElement(subcomponentCreatorMethod)
- .key(key)
- .kind(SUBCOMPONENT_CREATOR)
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#SUBCOMPONENT_CREATOR} binding declared using {@link
- * Module#subcomponents()}.
- */
- ProvisionBinding subcomponentCreatorBinding(
- ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
- SubcomponentDeclaration subcomponentDeclaration = subcomponentDeclarations.iterator().next();
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .key(subcomponentDeclaration.key())
- .kind(SUBCOMPONENT_CREATOR)
- .build();
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#DELEGATE} binding.
- *
- * @param delegateDeclaration the {@code @Binds}-annotated declaration
- * @param actualBinding the binding that satisfies the {@code @Binds} declaration
- */
- ContributionBinding delegateBinding(
- DelegateDeclaration delegateDeclaration, ContributionBinding actualBinding) {
- switch (actualBinding.bindingType()) {
- case PRODUCTION:
- return buildDelegateBinding(
- ProductionBinding.builder().nullableType(actualBinding.nullableType()),
- delegateDeclaration,
- Producer.class);
-
- case PROVISION:
- return buildDelegateBinding(
- ProvisionBinding.builder()
- .scope(uniqueScopeOf(delegateDeclaration.bindingElement().get()))
- .nullableType(actualBinding.nullableType()),
- delegateDeclaration,
- Provider.class);
-
- case MEMBERS_INJECTION: // fall-through to throw
- }
- throw new AssertionError("bindingType: " + actualBinding);
- }
-
- /**
- * Returns a {@link dagger.model.BindingKind#DELEGATE} binding used when there is no binding that
- * satisfies the {@code @Binds} declaration.
- */
- public ContributionBinding unresolvedDelegateBinding(DelegateDeclaration delegateDeclaration) {
- return buildDelegateBinding(
- ProvisionBinding.builder().scope(uniqueScopeOf(delegateDeclaration.bindingElement().get())),
- delegateDeclaration,
- Provider.class);
- }
-
- private ContributionBinding buildDelegateBinding(
- ContributionBinding.Builder<?, ?> builder,
- DelegateDeclaration delegateDeclaration,
- Class<?> frameworkType) {
- boolean isKotlinObject =
- metadataUtil.isObjectClass(delegateDeclaration.contributingModule().get())
- || metadataUtil.isCompanionObjectClass(delegateDeclaration.contributingModule().get());
- return builder
- .contributionType(delegateDeclaration.contributionType())
- .bindingElement(delegateDeclaration.bindingElement().get())
- .contributingModule(delegateDeclaration.contributingModule().get())
- .isContributingModuleKotlinObject(isKotlinObject)
- .key(keyFactory.forDelegateBinding(delegateDeclaration, frameworkType))
- .dependencies(delegateDeclaration.delegateRequest())
- .wrappedMapKeyAnnotation(delegateDeclaration.wrappedMapKey())
- .kind(DELEGATE)
- .build();
- }
-
- /**
- * Returns an {@link dagger.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
- * the underlying (non-optional) key
- */
- ContributionBinding syntheticOptionalBinding(
- Key key,
- RequestKind requestKind,
- ImmutableCollection<? extends Binding> underlyingKeyBindings) {
- if (underlyingKeyBindings.isEmpty()) {
- return ProvisionBinding.builder()
- .contributionType(ContributionType.UNIQUE)
- .key(key)
- .kind(OPTIONAL)
- .build();
- }
-
- boolean requiresProduction =
- underlyingKeyBindings.stream()
- .anyMatch(binding -> binding.bindingType() == BindingType.PRODUCTION)
- || requestKind.equals(RequestKind.PRODUCER) // handles producerFromProvider cases
- || requestKind.equals(RequestKind.PRODUCED); // handles producerFromProvider cases
-
- return (requiresProduction ? ProductionBinding.builder() : ProvisionBinding.builder())
- .contributionType(ContributionType.UNIQUE)
- .key(key)
- .kind(OPTIONAL)
- .dependencies(dependencyRequestFactory.forSyntheticPresentOptionalBinding(key, requestKind))
- .build();
- }
-
- /** Returns a {@link dagger.model.BindingKind#MEMBERS_INJECTOR} binding. */
- public ProvisionBinding membersInjectorBinding(
- Key key, MembersInjectionBinding membersInjectionBinding) {
- return ProvisionBinding.builder()
- .key(key)
- .contributionType(ContributionType.UNIQUE)
- .kind(MEMBERS_INJECTOR)
- .bindingElement(MoreTypes.asTypeElement(membersInjectionBinding.key().type()))
- .provisionDependencies(membersInjectionBinding.dependencies())
- .injectionSites(membersInjectionBinding.injectionSites())
- .build();
- }
-
- /**
- * Returns a {@link dagger.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
- */
- // TODO(dpb): See if we can just pass one nongeneric/parameterized type.
- public MembersInjectionBinding membersInjectionBinding(
- DeclaredType declaredType, Optional<TypeMirror> resolvedType) {
- // If the class this is injecting has some type arguments, resolve everything.
- if (!declaredType.getTypeArguments().isEmpty() && resolvedType.isPresent()) {
- DeclaredType resolved = asDeclared(resolvedType.get());
- // Validate that we're resolving from the correct type.
- checkState(
- types.isSameType(types.erasure(resolved), types.erasure(declaredType)),
- "erased expected type: %s, erased actual type: %s",
- types.erasure(resolved),
- types.erasure(declaredType));
- declaredType = resolved;
- }
- ImmutableSortedSet<InjectionSite> injectionSites =
- injectionSiteFactory.getInjectionSites(declaredType);
- ImmutableSet<DependencyRequest> dependencies =
- injectionSites.stream()
- .flatMap(injectionSite -> injectionSite.dependencies().stream())
- .collect(toImmutableSet());
-
- Key key = keyFactory.forMembersInjectedType(declaredType);
- TypeElement typeElement = MoreElements.asType(declaredType.asElement());
- return new AutoValue_MembersInjectionBinding(
- key,
- dependencies,
- typeElement,
- hasNonDefaultTypeParameters(typeElement, key.type(), types)
- ? Optional.of(
- membersInjectionBinding(asDeclared(typeElement.asType()), Optional.empty()))
- : Optional.empty(),
- injectionSites);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingGraph.java b/java/dagger/internal/codegen/binding/BindingGraph.java
deleted file mode 100644
index 4936a05..0000000
--- a/java/dagger/internal/codegen/binding/BindingGraph.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
-import static dagger.internal.codegen.extension.DaggerStreams.stream;
-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.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Sets;
-import com.google.common.graph.Graphs;
-import com.google.common.graph.ImmutableNetwork;
-import com.google.common.graph.Traverser;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.Node;
-import dagger.model.ComponentPath;
-import dagger.model.Key;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-
-/**
- * A graph that represents a single component or subcomponent within a fully validated top-level
- * binding graph.
- */
-@AutoValue
-public abstract class BindingGraph {
-
- @AutoValue
- abstract static class TopLevelBindingGraph extends dagger.model.BindingGraph {
- static TopLevelBindingGraph create(
- ImmutableNetwork<Node, Edge> network, boolean isFullBindingGraph) {
- TopLevelBindingGraph topLevelBindingGraph =
- new AutoValue_BindingGraph_TopLevelBindingGraph(network, isFullBindingGraph);
-
- ImmutableMap<ComponentPath, ComponentNode> componentNodes =
- topLevelBindingGraph.componentNodes().stream()
- .collect(
- toImmutableMap(ComponentNode::componentPath, componentNode -> componentNode));
-
- ImmutableSetMultimap.Builder<ComponentNode, ComponentNode> subcomponentNodesBuilder =
- ImmutableSetMultimap.builder();
- topLevelBindingGraph.componentNodes().stream()
- .filter(componentNode -> !componentNode.componentPath().atRoot())
- .forEach(
- componentNode ->
- subcomponentNodesBuilder.put(
- componentNodes.get(componentNode.componentPath().parent()), componentNode));
-
- // Set these fields directly on the instance rather than passing these in as input to the
- // AutoValue to prevent exposing this data outside of the class.
- topLevelBindingGraph.componentNodes = componentNodes;
- topLevelBindingGraph.subcomponentNodes = subcomponentNodesBuilder.build();
- return topLevelBindingGraph;
- }
-
- private ImmutableMap<ComponentPath, ComponentNode> componentNodes;
- private ImmutableSetMultimap<ComponentNode, ComponentNode> subcomponentNodes;
-
- TopLevelBindingGraph() {}
-
- // This overrides dagger.model.BindingGraph with a more efficient implementation.
- @Override
- public Optional<ComponentNode> componentNode(ComponentPath componentPath) {
- return componentNodes.containsKey(componentPath)
- ? Optional.of(componentNodes.get(componentPath))
- : Optional.empty();
- }
-
- /** Returns the set of subcomponent nodes of the given component node. */
- ImmutableSet<ComponentNode> subcomponentNodes(ComponentNode componentNode) {
- return subcomponentNodes.get(componentNode);
- }
-
- @Override
- @Memoized
- public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
- return super.nodesByClass();
- }
- }
-
- static BindingGraph create(
- ComponentNode componentNode, TopLevelBindingGraph topLevelBindingGraph) {
- return create(Optional.empty(), componentNode, topLevelBindingGraph);
- }
-
- private static BindingGraph create(
- Optional<BindingGraph> parent,
- ComponentNode componentNode,
- TopLevelBindingGraph topLevelBindingGraph) {
- ImmutableSet<BindingNode> reachableBindingNodes =
- Graphs.reachableNodes(topLevelBindingGraph.network().asGraph(), componentNode).stream()
- .filter(node -> isSubpath(componentNode.componentPath(), node.componentPath()))
- .filter(node -> node instanceof BindingNode)
- .map(node -> (BindingNode) node)
- .collect(toImmutableSet());
-
- // Construct the maps of the ContributionBindings and MembersInjectionBindings.
- Map<Key, BindingNode> contributionBindings = new HashMap<>();
- Map<Key, BindingNode> membersInjectionBindings = new HashMap<>();
- for (BindingNode bindingNode : reachableBindingNodes) {
- Map<Key, BindingNode> bindingsMap;
- if (bindingNode.delegate() instanceof ContributionBinding) {
- bindingsMap = contributionBindings;
- } else if (bindingNode.delegate() instanceof MembersInjectionBinding) {
- bindingsMap = membersInjectionBindings;
- } else {
- throw new AssertionError("Unexpected binding node type: " + bindingNode.delegate());
- }
-
- // TODO(bcorso): Mapping binding nodes by key is flawed since bindings that depend on local
- // multibindings can have multiple nodes (one in each component). In this case, we choose the
- // node in the child-most component since this is likely the node that users of this
- // BindingGraph will want (and to remain consisted with LegacyBindingGraph). However, ideally
- // we would avoid this ambiguity by getting dependencies directly from the top-level network.
- // In particular, rather than using a Binding's list of DependencyRequests (which only
- // contains the key) we would use the top-level network to find the DependencyEdges for a
- // particular BindingNode.
- Key key = bindingNode.key();
- if (!bindingsMap.containsKey(key)
- // Always choose the child-most binding node.
- || bindingNode.componentPath().components().size()
- > bindingsMap.get(key).componentPath().components().size()) {
- bindingsMap.put(key, bindingNode);
- }
- }
-
- BindingGraph bindingGraph = new AutoValue_BindingGraph(componentNode, topLevelBindingGraph);
-
- ImmutableSet<ModuleDescriptor> modules =
- ((ComponentNodeImpl) componentNode).componentDescriptor().modules();
-
- ImmutableSet<ModuleDescriptor> inheritedModules =
- parent.isPresent()
- ? Sets.union(parent.get().ownedModules, parent.get().inheritedModules).immutableCopy()
- : ImmutableSet.of();
-
- // Set these fields directly on the instance rather than passing these in as input to the
- // AutoValue to prevent exposing this data outside of the class.
- bindingGraph.inheritedModules = inheritedModules;
- bindingGraph.ownedModules = Sets.difference(modules, inheritedModules).immutableCopy();
- bindingGraph.contributionBindings = ImmutableMap.copyOf(contributionBindings);
- bindingGraph.membersInjectionBindings = ImmutableMap.copyOf(membersInjectionBindings);
- bindingGraph.bindingModules =
- contributionBindings.values().stream()
- .map(BindingNode::contributingModule)
- .flatMap(presentValues())
- .collect(toImmutableSet());
-
- return bindingGraph;
- }
-
- private ImmutableMap<Key, BindingNode> contributionBindings;
- private ImmutableMap<Key, BindingNode> membersInjectionBindings;
- private ImmutableSet<ModuleDescriptor> inheritedModules;
- private ImmutableSet<ModuleDescriptor> ownedModules;
- private ImmutableSet<TypeElement> bindingModules;
-
- BindingGraph() {}
-
- /** Returns the {@link ComponentNode} for this graph. */
- public abstract ComponentNode componentNode();
-
- /** Returns the {@link ComponentPath} for this graph. */
- public final ComponentPath componentPath() {
- return componentNode().componentPath();
- }
-
- /** Returns the {@link TopLevelBindingGraph} from which this graph is contained. */
- public abstract TopLevelBindingGraph topLevelBindingGraph();
-
- /** Returns the {@link ComponentDescriptor} for this graph */
- public final ComponentDescriptor componentDescriptor() {
- return ((ComponentNodeImpl) componentNode()).componentDescriptor();
- }
-
- /** Returns the {@link ContributionBinding} for the given {@link Key}. */
- public final ContributionBinding contributionBinding(Key key) {
- return (ContributionBinding) contributionBindings.get(key).delegate();
- }
-
- /**
- * Returns the {@link MembersInjectionBinding} for the given {@link Key} or {@link
- * Optional#empty()} if one does not exist.
- */
- public final Optional<MembersInjectionBinding> membersInjectionBinding(Key key) {
- return membersInjectionBindings.containsKey(key)
- ? Optional.of((MembersInjectionBinding) membersInjectionBindings.get(key).delegate())
- : Optional.empty();
- }
-
- /** Returns the {@link TypeElement} for the component this graph represents. */
- public final TypeElement componentTypeElement() {
- return componentPath().currentComponent();
- }
-
- /**
- * Returns the set of modules that are owned by this graph regardless of whether or not any of
- * their bindings are used in this graph. For graphs representing top-level {@link
- * dagger.Component components}, this set will be the same as {@linkplain
- * ComponentDescriptor#modules() the component's transitive modules}. For {@linkplain Subcomponent
- * subcomponents}, this set will be the transitive modules that are not owned by any of their
- * ancestors.
- */
- public final ImmutableSet<TypeElement> ownedModuleTypes() {
- return ownedModules.stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
- }
-
- /**
- * Returns the factory method for this subcomponent, if it exists.
- *
- * <p>This factory method is the one defined in the parent component's interface.
- *
- * <p>In the example below, the {@link BindingGraph#factoryMethod} for {@code ChildComponent}
- * would return the {@link ExecutableElement}: {@code childComponent(ChildModule1)} .
- *
- * <pre><code>
- * {@literal @Component}
- * interface ParentComponent {
- * ChildComponent childComponent(ChildModule1 childModule);
- * }
- * </code></pre>
- */
- // TODO(b/73294201): Consider returning the resolved ExecutableType for the factory method.
- public final Optional<ExecutableElement> factoryMethod() {
- return topLevelBindingGraph().network().inEdges(componentNode()).stream()
- .filter(edge -> edge instanceof ChildFactoryMethodEdge)
- .map(edge -> ((ChildFactoryMethodEdge) edge).factoryMethod())
- .collect(toOptional());
- }
-
- /**
- * Returns a map between the {@linkplain ComponentRequirement component requirement} and the
- * corresponding {@link VariableElement} for each module parameter in the {@linkplain
- * BindingGraph#factoryMethod factory method}.
- */
- // TODO(dpb): Consider disallowing modules if none of their bindings are used.
- public final ImmutableMap<ComponentRequirement, VariableElement> factoryMethodParameters() {
- return factoryMethod().get().getParameters().stream()
- .collect(
- toImmutableMap(
- parameter -> ComponentRequirement.forModule(parameter.asType()),
- parameter -> parameter));
- }
-
- /**
- * The types for which the component needs instances.
- *
- * <ul>
- * <li>component dependencies
- * <li>owned modules with concrete instance bindings that are used in the graph
- * <li>bound instances
- * </ul>
- */
- @Memoized
- public ImmutableSet<ComponentRequirement> componentRequirements() {
- ImmutableSet<TypeElement> requiredModules =
- stream(Traverser.forTree(BindingGraph::subgraphs).depthFirstPostOrder(this))
- .flatMap(graph -> graph.bindingModules.stream())
- .filter(ownedModuleTypes()::contains)
- .collect(toImmutableSet());
- ImmutableSet.Builder<ComponentRequirement> requirements = ImmutableSet.builder();
- componentDescriptor().requirements().stream()
- .filter(
- requirement ->
- !requirement.kind().isModule()
- || requiredModules.contains(requirement.typeElement()))
- .forEach(requirements::add);
- if (factoryMethod().isPresent()) {
- requirements.addAll(factoryMethodParameters().keySet());
- }
- return requirements.build();
- }
-
- /** Returns all {@link ComponentDescriptor}s in the {@link TopLevelBindingGraph}. */
- public final ImmutableSet<ComponentDescriptor> componentDescriptors() {
- return topLevelBindingGraph().componentNodes().stream()
- .map(componentNode -> ((ComponentNodeImpl) componentNode).componentDescriptor())
- .collect(toImmutableSet());
- }
-
- @Memoized
- public ImmutableList<BindingGraph> subgraphs() {
- return topLevelBindingGraph().subcomponentNodes(componentNode()).stream()
- .map(subcomponent -> create(Optional.of(this), subcomponent, topLevelBindingGraph()))
- .collect(toImmutableList());
- }
-
- public final ImmutableSet<BindingNode> bindingNodes(Key key) {
- ImmutableSet.Builder<BindingNode> builder = ImmutableSet.builder();
- if (contributionBindings.containsKey(key)) {
- builder.add(contributionBindings.get(key));
- }
- if (membersInjectionBindings.containsKey(key)) {
- builder.add(membersInjectionBindings.get(key));
- }
- return builder.build();
- }
-
- @Memoized
- public ImmutableSet<BindingNode> bindingNodes() {
- return ImmutableSet.<BindingNode>builder()
- .addAll(contributionBindings.values())
- .addAll(membersInjectionBindings.values())
- .build();
- }
-
- // TODO(bcorso): Move this to ComponentPath
- private static boolean isSubpath(ComponentPath path, ComponentPath subpath) {
- if (path.components().size() < subpath.components().size()) {
- return false;
- }
- for (int i = 0; i < subpath.components().size(); i++) {
- if (!path.components().get(i).equals(subpath.components().get(i))) {
- return false;
- }
- }
- return true;
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingGraphConverter.java b/java/dagger/internal/codegen/binding/BindingGraphConverter.java
deleted file mode 100644
index b882b37..0000000
--- a/java/dagger/internal/codegen/binding/BindingGraphConverter.java
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Verify.verify;
-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.model.BindingKind.SUBCOMPONENT_CREATOR;
-
-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.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
-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.binding.BindingGraph.TopLevelBindingGraph;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** Converts {@link BindingGraph}s to {@link dagger.model.BindingGraph}s. */
-final class BindingGraphConverter {
- private final BindingDeclarationFormatter bindingDeclarationFormatter;
-
- @Inject
- BindingGraphConverter(BindingDeclarationFormatter bindingDeclarationFormatter) {
- this.bindingDeclarationFormatter = bindingDeclarationFormatter;
- }
-
- /**
- * Creates the external {@link dagger.model.BindingGraph} representing the given internal {@link
- * BindingGraph}.
- */
- BindingGraph convert(LegacyBindingGraph legacyBindingGraph, boolean isFullBindingGraph) {
- MutableNetwork<Node, Edge> network = asNetwork(legacyBindingGraph);
- ComponentNode rootNode = rootComponentNode(network);
-
- // When bindings are copied down into child graphs because they transitively depend on local
- // multibindings or optional bindings, the parent-owned binding is still there. If that
- // parent-owned binding is not reachable from its component, it doesn't need to be in the graph
- // because it will never be used. So remove all nodes that are not reachable from the root
- // component—unless we're converting a full binding graph.
- if (!isFullBindingGraph) {
- unreachableNodes(network.asGraph(), rootNode).forEach(network::removeNode);
- }
-
- TopLevelBindingGraph topLevelBindingGraph =
- TopLevelBindingGraph.create(ImmutableNetwork.copyOf(network), isFullBindingGraph);
- return BindingGraph.create(rootNode, topLevelBindingGraph);
- }
-
- private MutableNetwork<Node, Edge> asNetwork(LegacyBindingGraph graph) {
- Converter converter = new Converter(bindingDeclarationFormatter);
- converter.visitRootComponent(graph);
- return converter.network;
- }
-
- // TODO(dpb): Example of BindingGraph logic applied to derived networks.
- private ComponentNode rootComponentNode(Network<Node, Edge> network) {
- return (ComponentNode)
- Iterables.find(
- network.nodes(),
- node -> node instanceof ComponentNode && node.componentPath().atRoot());
- }
-
- /**
- * Used as a cache key to make sure resolved bindings are cached per component path.
- * This is required so that binding nodes are not reused across different branches of the
- * graph since the ResolvedBindings class only contains the component and not the path.
- */
- @AutoValue
- abstract static class ResolvedBindingsWithPath {
- abstract ResolvedBindings resolvedBindings();
- abstract ComponentPath componentPath();
-
- static ResolvedBindingsWithPath create(
- ResolvedBindings resolvedBindings, ComponentPath componentPath) {
- return new AutoValue_BindingGraphConverter_ResolvedBindingsWithPath(
- resolvedBindings, componentPath);
- }
- }
-
- private static final class Converter {
- /** The path from the root graph to the currently visited graph. */
- private final Deque<LegacyBindingGraph> bindingGraphPath = new ArrayDeque<>();
-
- /** The {@link ComponentPath} for each component in {@link #bindingGraphPath}. */
- private final Deque<ComponentPath> componentPaths = new ArrayDeque<>();
-
- private final BindingDeclarationFormatter bindingDeclarationFormatter;
- private final MutableNetwork<Node, Edge> network =
- NetworkBuilder.directed().allowsParallelEdges(true).allowsSelfLoops(true).build();
- private final Set<BindingNode> bindings = new HashSet<>();
-
- private final Map<ResolvedBindingsWithPath, ImmutableSet<BindingNode>> resolvedBindingsMap =
- new HashMap<>();
-
- /** Constructs a converter for a root (component, not subcomponent) binding graph. */
- private Converter(BindingDeclarationFormatter bindingDeclarationFormatter) {
- this.bindingDeclarationFormatter = bindingDeclarationFormatter;
- }
-
- private void visitRootComponent(LegacyBindingGraph graph) {
- visitComponent(graph, null);
- }
-
- /**
- * Called once for each component in a component hierarchy.
- *
- * <p>This implementation does the following:
- *
- * <ol>
- * <li>If this component is installed in its parent by a subcomponent factory method, calls
- * {@link #visitSubcomponentFactoryMethod(ComponentNode, ComponentNode,
- * ExecutableElement)}.
- * <li>For each entry point in the component, calls {@link #visitEntryPoint(ComponentNode,
- * DependencyRequest)}.
- * <li>For each child component, calls {@link #visitComponent(LegacyBindingGraph,
- * ComponentNode)}, updating the traversal state.
- * </ol>
- *
- * @param graph the currently visited graph
- */
- private void visitComponent(LegacyBindingGraph graph, ComponentNode parentComponent) {
- bindingGraphPath.addLast(graph);
- ComponentPath graphPath =
- ComponentPath.create(
- bindingGraphPath.stream()
- .map(LegacyBindingGraph::componentDescriptor)
- .map(ComponentDescriptor::typeElement)
- .collect(toImmutableList()));
- componentPaths.addLast(graphPath);
- ComponentNode currentComponent =
- ComponentNodeImpl.create(componentPath(), graph.componentDescriptor());
-
- network.addNode(currentComponent);
-
- for (ComponentMethodDescriptor entryPointMethod :
- graph.componentDescriptor().entryPointMethods()) {
- visitEntryPoint(currentComponent, entryPointMethod.dependencyRequest().get());
- }
-
- for (ResolvedBindings resolvedBindings : graph.resolvedBindings()) {
- for (BindingNode binding : bindingNodes(resolvedBindings)) {
- if (bindings.add(binding)) {
- network.addNode(binding);
- for (DependencyRequest dependencyRequest : binding.dependencies()) {
- addDependencyEdges(binding, dependencyRequest);
- }
- }
- if (binding.kind().equals(SUBCOMPONENT_CREATOR)
- && binding.componentPath().equals(currentComponent.componentPath())) {
- network.addEdge(
- binding,
- subcomponentNode(binding.key().type(), graph),
- new SubcomponentCreatorBindingEdgeImpl(
- resolvedBindings.subcomponentDeclarations()));
- }
- }
- }
-
- if (bindingGraphPath.size() > 1) {
- LegacyBindingGraph parent = Iterators.get(bindingGraphPath.descendingIterator(), 1);
- parent
- .componentDescriptor()
- .getFactoryMethodForChildComponent(graph.componentDescriptor())
- .ifPresent(
- childFactoryMethod ->
- visitSubcomponentFactoryMethod(
- parentComponent, currentComponent, childFactoryMethod.methodElement()));
- }
-
- for (LegacyBindingGraph child : graph.subgraphs()) {
- visitComponent(child, currentComponent);
- }
-
- verify(bindingGraphPath.removeLast().equals(graph));
- verify(componentPaths.removeLast().equals(graphPath));
- }
-
- /**
- * Called once for each entry point in a component.
- *
- * @param componentNode the component that contains the entry point
- * @param entryPoint the entry point to visit
- */
- private void visitEntryPoint(ComponentNode componentNode, DependencyRequest entryPoint) {
- addDependencyEdges(componentNode, entryPoint);
- }
-
- /**
- * Called if this component was installed in its parent by a subcomponent factory method.
- *
- * @param parentComponent the parent graph
- * @param currentComponent the currently visited graph
- * @param factoryMethod the factory method in the parent component that declares that the
- * current component is a child
- */
- private void visitSubcomponentFactoryMethod(
- ComponentNode parentComponent,
- ComponentNode currentComponent,
- ExecutableElement factoryMethod) {
- network.addEdge(
- parentComponent,
- currentComponent,
- new ChildFactoryMethodEdgeImpl(factoryMethod));
- }
-
- /**
- * Returns an immutable snapshot of the path from the root component to the currently visited
- * component.
- */
- private ComponentPath componentPath() {
- return componentPaths.getLast();
- }
-
- /**
- * Returns the subpath from the root component to the matching {@code ancestor} of the current
- * component.
- */
- private ComponentPath pathFromRootToAncestor(TypeElement ancestor) {
- for (ComponentPath componentPath : componentPaths) {
- if (componentPath.currentComponent().equals(ancestor)) {
- return componentPath;
- }
- }
- throw new IllegalArgumentException(
- String.format(
- "%s is not in the current path: %s", ancestor.getQualifiedName(), componentPath()));
- }
-
- /**
- * Returns the LegacyBindingGraph for {@code ancestor}, where {@code ancestor} is in the
- * component path of the current traversal.
- */
- private LegacyBindingGraph graphForAncestor(TypeElement ancestor) {
- for (LegacyBindingGraph graph : bindingGraphPath) {
- if (graph.componentDescriptor().typeElement().equals(ancestor)) {
- return graph;
- }
- }
- throw new IllegalArgumentException(
- String.format(
- "%s is not in the current path: %s", ancestor.getQualifiedName(), componentPath()));
- }
-
- /**
- * Adds a {@link dagger.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);
- if (dependencies.isEmpty()) {
- addDependencyEdge(source, dependencyRequest, missingBindingNode(dependencies));
- } else {
- for (BindingNode dependency : bindingNodes(dependencies)) {
- addDependencyEdge(source, dependencyRequest, dependency);
- }
- }
- }
-
- private void addDependencyEdge(
- Node source, DependencyRequest dependencyRequest, Node dependency) {
- network.addNode(dependency);
- if (!hasDependencyEdge(source, dependency, dependencyRequest)) {
- network.addEdge(
- source,
- dependency,
- new DependencyEdgeImpl(dependencyRequest, source instanceof ComponentNode));
- }
- }
-
- private boolean hasDependencyEdge(
- Node source, Node dependency, DependencyRequest dependencyRequest) {
- // An iterative approach is used instead of a Stream because this method is called in a hot
- // loop, and the Stream calculates the size of network.edgesConnecting(), which is slow. This
- // seems to be because caculating the edges connecting two nodes in a Network that supports
- // parallel edges is must check the equality of many nodes, and BindingNode's equality
- // semantics drag in the equality of many other expensive objects
- for (Edge edge : network.edgesConnecting(source, dependency)) {
- if (edge instanceof DependencyEdge) {
- if (((DependencyEdge) edge).dependencyRequest().equals(dependencyRequest)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private ResolvedBindings resolvedDependencies(
- Node source, DependencyRequest dependencyRequest) {
- return graphForAncestor(source.componentPath().currentComponent())
- .resolvedBindings(bindingRequest(dependencyRequest));
- }
-
- private ImmutableSet<BindingNode> bindingNodes(ResolvedBindings resolvedBindings) {
- ResolvedBindingsWithPath resolvedBindingsWithPath =
- ResolvedBindingsWithPath.create(resolvedBindings, componentPath());
- return resolvedBindingsMap.computeIfAbsent(
- resolvedBindingsWithPath, this::uncachedBindingNodes);
- }
-
- private ImmutableSet<BindingNode> uncachedBindingNodes(
- ResolvedBindingsWithPath resolvedBindingsWithPath) {
- ImmutableSet.Builder<BindingNode> bindingNodes = ImmutableSet.builder();
- resolvedBindingsWithPath.resolvedBindings()
- .allBindings()
- .asMap()
- .forEach(
- (component, bindings) -> {
- for (Binding binding : bindings) {
- bindingNodes.add(
- bindingNode(resolvedBindingsWithPath.resolvedBindings(), binding, component));
- }
- });
- return bindingNodes.build();
- }
-
- private BindingNode bindingNode(
- ResolvedBindings resolvedBindings, Binding binding, TypeElement owningComponent) {
- return BindingNode.create(
- pathFromRootToAncestor(owningComponent),
- binding,
- resolvedBindings.multibindingDeclarations(),
- resolvedBindings.optionalBindingDeclarations(),
- resolvedBindings.subcomponentDeclarations(),
- bindingDeclarationFormatter);
- }
-
- private MissingBinding missingBindingNode(ResolvedBindings dependencies) {
- // Put all missing binding nodes in the root component. This simplifies the binding graph
- // and produces better error messages for users since all dependents point to the same node.
- return MissingBindingImpl.create(
- ComponentPath.create(ImmutableList.of(componentPath().rootComponent())),
- dependencies.key());
- }
-
- private ComponentNode subcomponentNode(
- TypeMirror subcomponentBuilderType, LegacyBindingGraph graph) {
- TypeElement subcomponentBuilderElement = asTypeElement(subcomponentBuilderType);
- ComponentDescriptor subcomponent =
- graph.componentDescriptor().getChildComponentWithBuilderType(subcomponentBuilderElement);
- return ComponentNodeImpl.create(
- componentPath().childPath(subcomponent.typeElement()), subcomponent);
- }
- }
-
- @AutoValue
- abstract static class MissingBindingImpl extends MissingBinding {
- static MissingBinding create(ComponentPath component, Key key) {
- return new AutoValue_BindingGraphConverter_MissingBindingImpl(component, key);
- }
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object o);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingGraphFactory.java b/java/dagger/internal/codegen/binding/BindingGraphFactory.java
deleted file mode 100644
index 2c15e26..0000000
--- a/java/dagger/internal/codegen/binding/BindingGraphFactory.java
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.auto.common.MoreTypes.isType;
-import static com.google.auto.common.MoreTypes.isTypeOf;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
-import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentContributionMethod;
-import static dagger.internal.codegen.binding.SourceFiles.generatedMonitoringModuleName;
-import static dagger.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.model.BindingKind.DELEGATE;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.OPTIONAL;
-import static dagger.model.BindingKind.SUBCOMPONENT_CREATOR;
-import static dagger.model.RequestKind.MEMBERS_INJECTION;
-import static java.util.function.Predicate.isEqual;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimaps;
-import dagger.MembersInjector;
-import dagger.Reusable;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.OptionalType;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Scope;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.internal.ProductionExecutorModule;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Queue;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-
-/** A factory for {@link BindingGraph} objects. */
-@Singleton
-public final class BindingGraphFactory implements ClearableCache {
-
- private final DaggerElements elements;
- private final InjectBindingRegistry injectBindingRegistry;
- private final KeyFactory keyFactory;
- private final BindingFactory bindingFactory;
- private final ModuleDescriptor.Factory moduleDescriptorFactory;
- private final BindingGraphConverter bindingGraphConverter;
- private final Map<Key, ImmutableSet<Key>> keysMatchingRequestCache = new HashMap<>();
- private final CompilerOptions compilerOptions;
-
- @Inject
- BindingGraphFactory(
- DaggerElements elements,
- InjectBindingRegistry injectBindingRegistry,
- KeyFactory keyFactory,
- BindingFactory bindingFactory,
- ModuleDescriptor.Factory moduleDescriptorFactory,
- BindingGraphConverter bindingGraphConverter,
- CompilerOptions compilerOptions) {
- this.elements = elements;
- this.injectBindingRegistry = injectBindingRegistry;
- this.keyFactory = keyFactory;
- this.bindingFactory = bindingFactory;
- this.moduleDescriptorFactory = moduleDescriptorFactory;
- this.bindingGraphConverter = bindingGraphConverter;
- this.compilerOptions = compilerOptions;
- }
-
- /**
- * Creates a binding graph for a component.
- *
- * @param createFullBindingGraph if {@code true}, the binding graph will include all bindings;
- * otherwise it will include only bindings reachable from at least one entry point
- */
- public BindingGraph create(
- ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) {
- return bindingGraphConverter.convert(
- createLegacyBindingGraph(Optional.empty(), componentDescriptor, createFullBindingGraph),
- createFullBindingGraph);
- }
-
- private LegacyBindingGraph createLegacyBindingGraph(
- Optional<Resolver> parentResolver,
- ComponentDescriptor componentDescriptor,
- boolean createFullBindingGraph) {
- ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder();
- ImmutableSet.Builder<DelegateDeclaration> delegatesBuilder = ImmutableSet.builder();
- ImmutableSet.Builder<OptionalBindingDeclaration> optionalsBuilder = ImmutableSet.builder();
-
- if (componentDescriptor.isRealComponent()) {
- // binding for the component itself
- explicitBindingsBuilder.add(
- bindingFactory.componentBinding(componentDescriptor.typeElement()));
- }
-
- // Collect Component dependencies.
- for (ComponentRequirement dependency : componentDescriptor.dependencies()) {
- explicitBindingsBuilder.add(bindingFactory.componentDependencyBinding(dependency));
- List<ExecutableElement> dependencyMethods =
- methodsIn(elements.getAllMembers(dependency.typeElement()));
-
- // Within a component dependency, we want to allow the same method to appear multiple
- // times assuming it is the exact same method. We do this by tracking a set of bindings
- // we've already added with the binding element removed since that is the only thing
- // allowed to differ.
- HashMultimap<String, ContributionBinding> dedupeBindings = HashMultimap.create();
- for (ExecutableElement method : dependencyMethods) {
- // MembersInjection methods aren't "provided" explicitly, so ignore them.
- if (isComponentContributionMethod(elements, method)) {
- ContributionBinding binding = bindingFactory.componentDependencyMethodBinding(
- componentDescriptor, method);
- if (dedupeBindings.put(
- method.getSimpleName().toString(),
- // Remove the binding element since we know that will be different, but everything
- // else we want to be the same to consider it a duplicate.
- binding.toBuilder().clearBindingElement().build())) {
- explicitBindingsBuilder.add(binding);
- }
- }
- }
- }
-
- // Collect bindings on the creator.
- componentDescriptor
- .creatorDescriptor()
- .ifPresent(
- creatorDescriptor ->
- creatorDescriptor.boundInstanceRequirements().stream()
- .map(
- requirement ->
- bindingFactory.boundInstanceBinding(
- requirement, creatorDescriptor.elementForRequirement(requirement)))
- .forEach(explicitBindingsBuilder::add));
-
- componentDescriptor
- .childComponentsDeclaredByBuilderEntryPoints()
- .forEach(
- (builderEntryPoint, childComponent) -> {
- if (!componentDescriptor
- .childComponentsDeclaredByModules()
- .contains(childComponent)) {
- explicitBindingsBuilder.add(
- bindingFactory.subcomponentCreatorBinding(
- builderEntryPoint.methodElement(), componentDescriptor.typeElement()));
- }
- });
-
- ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations = ImmutableSet.builder();
- ImmutableSet.Builder<SubcomponentDeclaration> subcomponentDeclarations = ImmutableSet.builder();
-
- // Collect transitive module bindings and multibinding declarations.
- for (ModuleDescriptor moduleDescriptor : modules(componentDescriptor, parentResolver)) {
- explicitBindingsBuilder.addAll(moduleDescriptor.bindings());
- multibindingDeclarations.addAll(moduleDescriptor.multibindingDeclarations());
- subcomponentDeclarations.addAll(moduleDescriptor.subcomponentDeclarations());
- delegatesBuilder.addAll(moduleDescriptor.delegateDeclarations());
- optionalsBuilder.addAll(moduleDescriptor.optionalDeclarations());
- }
-
- final Resolver requestResolver =
- new Resolver(
- parentResolver,
- componentDescriptor,
- indexBindingDeclarationsByKey(explicitBindingsBuilder.build()),
- indexBindingDeclarationsByKey(multibindingDeclarations.build()),
- indexBindingDeclarationsByKey(subcomponentDeclarations.build()),
- indexBindingDeclarationsByKey(delegatesBuilder.build()),
- indexBindingDeclarationsByKey(optionalsBuilder.build()));
-
- componentDescriptor.entryPointMethods().stream()
- .map(method -> method.dependencyRequest().get())
- .forEach(
- entryPoint -> {
- if (entryPoint.kind().equals(MEMBERS_INJECTION)) {
- requestResolver.resolveMembersInjection(entryPoint.key());
- } else {
- requestResolver.resolve(entryPoint.key());
- }
- });
-
- if (createFullBindingGraph) {
- // Resolve the keys for all bindings in all modules, stripping any multibinding contribution
- // identifier so that the multibinding itself is resolved.
- modules(componentDescriptor, parentResolver).stream()
- .flatMap(module -> module.allBindingKeys().stream())
- .map(key -> key.toBuilder().multibindingContributionIdentifier(Optional.empty()).build())
- .forEach(requestResolver::resolve);
- }
-
- // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have
- // been detected during binding resolution. If a binding for a subcomponent is never resolved,
- // no BindingGraph will be created for it and no implementation will be generated. This is
- // done in a queue since resolving one subcomponent might resolve a key for a subcomponent
- // from a parent graph. This is done until no more new subcomponents are resolved.
- Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>();
- ImmutableList.Builder<LegacyBindingGraph> subgraphs = ImmutableList.builder();
- for (ComponentDescriptor subcomponent :
- Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) {
- if (resolvedSubcomponents.add(subcomponent)) {
- subgraphs.add(
- createLegacyBindingGraph(
- Optional.of(requestResolver), subcomponent, createFullBindingGraph));
- }
- }
-
- return new LegacyBindingGraph(
- componentDescriptor,
- ImmutableMap.copyOf(requestResolver.getResolvedContributionBindings()),
- ImmutableMap.copyOf(requestResolver.getResolvedMembersInjectionBindings()),
- ImmutableList.copyOf(subgraphs.build()));
- }
-
- /**
- * Returns all the modules that should be installed in the component. For production components
- * and production subcomponents that have a parent that is not a production component or
- * subcomponent, also includes the production monitoring module for the component and the
- * production executor module.
- */
- private ImmutableSet<ModuleDescriptor> modules(
- ComponentDescriptor componentDescriptor, Optional<Resolver> parentResolver) {
- return shouldIncludeImplicitProductionModules(componentDescriptor, parentResolver)
- ? new ImmutableSet.Builder<ModuleDescriptor>()
- .addAll(componentDescriptor.modules())
- .add(descriptorForMonitoringModule(componentDescriptor.typeElement()))
- .add(descriptorForProductionExecutorModule())
- .build()
- : componentDescriptor.modules();
- }
-
- private boolean shouldIncludeImplicitProductionModules(
- ComponentDescriptor component, Optional<Resolver> parentResolver) {
- return component.isProduction()
- && ((!component.isSubcomponent() && component.isRealComponent())
- || (parentResolver.isPresent()
- && !parentResolver.get().componentDescriptor.isProduction()));
- }
-
- /**
- * Returns a descriptor for a generated module that handles monitoring for production components.
- * This module is generated in the {@link
- * dagger.internal.codegen.validation.MonitoringModuleProcessingStep}.
- *
- * @throws TypeNotPresentException if the module has not been generated yet. This will cause the
- * processor to retry in a later processing round.
- */
- private ModuleDescriptor descriptorForMonitoringModule(TypeElement componentDefinitionType) {
- return moduleDescriptorFactory.create(
- elements.checkTypePresent(
- generatedMonitoringModuleName(componentDefinitionType).toString()));
- }
-
- /** Returns a descriptor {@link ProductionExecutorModule}. */
- private ModuleDescriptor descriptorForProductionExecutorModule() {
- return moduleDescriptorFactory.create(elements.getTypeElement(ProductionExecutorModule.class));
- }
-
- /** Indexes {@code bindingDeclarations} by {@link BindingDeclaration#key()}. */
- private static <T extends BindingDeclaration>
- ImmutableSetMultimap<Key, T> indexBindingDeclarationsByKey(Iterable<T> declarations) {
- return ImmutableSetMultimap.copyOf(Multimaps.index(declarations, BindingDeclaration::key));
- }
-
- @Override
- public void clearCache() {
- keysMatchingRequestCache.clear();
- }
-
- private final class Resolver {
- final Optional<Resolver> parentResolver;
- final ComponentDescriptor componentDescriptor;
- final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings;
- final ImmutableSet<ContributionBinding> explicitBindingsSet;
- final ImmutableSetMultimap<Key, ContributionBinding> explicitMultibindings;
- final ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations;
- final ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations;
- final ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations;
- final ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations;
- final ImmutableSetMultimap<Key, DelegateDeclaration> delegateMultibindingDeclarations;
- final Map<Key, ResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>();
- final Map<Key, ResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>();
- final Deque<Key> cycleStack = new ArrayDeque<>();
- final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>();
- final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>();
- final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>();
-
- Resolver(
- Optional<Resolver> parentResolver,
- ComponentDescriptor componentDescriptor,
- ImmutableSetMultimap<Key, ContributionBinding> explicitBindings,
- ImmutableSetMultimap<Key, MultibindingDeclaration> multibindingDeclarations,
- ImmutableSetMultimap<Key, SubcomponentDeclaration> subcomponentDeclarations,
- ImmutableSetMultimap<Key, DelegateDeclaration> delegateDeclarations,
- ImmutableSetMultimap<Key, OptionalBindingDeclaration> optionalBindingDeclarations) {
- this.parentResolver = parentResolver;
- this.componentDescriptor = checkNotNull(componentDescriptor);
- this.explicitBindings = checkNotNull(explicitBindings);
- this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values());
- this.multibindingDeclarations = checkNotNull(multibindingDeclarations);
- this.subcomponentDeclarations = checkNotNull(subcomponentDeclarations);
- this.delegateDeclarations = checkNotNull(delegateDeclarations);
- this.optionalBindingDeclarations = checkNotNull(optionalBindingDeclarations);
- this.explicitMultibindings = multibindingContributionsByMultibindingKey(explicitBindingsSet);
- this.delegateMultibindingDeclarations =
- multibindingContributionsByMultibindingKey(delegateDeclarations.values());
- subcomponentsToResolve.addAll(
- componentDescriptor.childComponentsDeclaredByFactoryMethods().values());
- subcomponentsToResolve.addAll(
- componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values());
- }
-
- /**
- * Returns the resolved contribution bindings for the given {@link Key}:
- *
- * <ul>
- * <li>All explicit bindings for:
- * <ul>
- * <li>the requested key
- * <li>{@code Set<T>} if the requested key's type is {@code Set<Produced<T>>}
- * <li>{@code Map<K, Provider<V>>} if the requested key's type is {@code Map<K,
- * Producer<V>>}.
- * </ul>
- * <li>An implicit {@link Inject @Inject}-annotated constructor binding if there is one and
- * there are no explicit bindings or synthetic bindings.
- * </ul>
- */
- ResolvedBindings lookUpBindings(Key requestKey) {
- Set<ContributionBinding> bindings = new LinkedHashSet<>();
- Set<ContributionBinding> multibindingContributions = new LinkedHashSet<>();
- Set<MultibindingDeclaration> multibindingDeclarations = new LinkedHashSet<>();
- Set<OptionalBindingDeclaration> optionalBindingDeclarations = new LinkedHashSet<>();
- Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>();
-
- // Gather all bindings, multibindings, optional, and subcomponent declarations/contributions.
- ImmutableSet<Key> keysMatchingRequest = keysMatchingRequest(requestKey);
- for (Resolver resolver : getResolverLineage()) {
- bindings.addAll(resolver.getLocalExplicitBindings(requestKey));
-
- for (Key key : keysMatchingRequest) {
- multibindingContributions.addAll(resolver.getLocalExplicitMultibindings(key));
- multibindingDeclarations.addAll(resolver.multibindingDeclarations.get(key));
- subcomponentDeclarations.addAll(resolver.subcomponentDeclarations.get(key));
- // The optional binding declarations are keyed by the unwrapped type.
- keyFactory.unwrapOptional(key)
- .map(resolver.optionalBindingDeclarations::get)
- .ifPresent(optionalBindingDeclarations::addAll);
- }
- }
-
- // Add synthetic multibinding
- if (!multibindingContributions.isEmpty() || !multibindingDeclarations.isEmpty()) {
- bindings.add(bindingFactory.syntheticMultibinding(requestKey, multibindingContributions));
- }
-
- // Add synthetic optional binding
- if (!optionalBindingDeclarations.isEmpty()) {
- bindings.add(
- bindingFactory.syntheticOptionalBinding(
- requestKey,
- getRequestKind(OptionalType.from(requestKey).valueType()),
- lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings()));
- }
-
- // Add subcomponent creator binding
- if (!subcomponentDeclarations.isEmpty()) {
- ProvisionBinding binding =
- bindingFactory.subcomponentCreatorBinding(
- ImmutableSet.copyOf(subcomponentDeclarations));
- bindings.add(binding);
- addSubcomponentToOwningResolver(binding);
- }
-
- // Add members injector binding
- if (isType(requestKey.type()) && isTypeOf(MembersInjector.class, requestKey.type())) {
- injectBindingRegistry
- .getOrFindMembersInjectorProvisionBinding(requestKey)
- .ifPresent(bindings::add);
- }
-
- // Add Assisted Factory binding
- if (isType(requestKey.type())
- && requestKey.type().getKind() == TypeKind.DECLARED
- && isAssistedFactoryType(asTypeElement(requestKey.type()))) {
- bindings.add(
- bindingFactory.assistedFactoryBinding(
- asTypeElement(requestKey.type()), Optional.of(requestKey.type())));
- }
-
- // If there are no bindings, add the implicit @Inject-constructed binding if there is one.
- if (bindings.isEmpty()) {
- injectBindingRegistry
- .getOrFindProvisionBinding(requestKey)
- .filter(this::isCorrectlyScopedInSubcomponent)
- .ifPresent(bindings::add);
- }
-
- return ResolvedBindings.forContributionBindings(
- requestKey,
- Multimaps.index(bindings, binding -> getOwningComponent(requestKey, binding)),
- multibindingDeclarations,
- subcomponentDeclarations,
- optionalBindingDeclarations);
- }
-
- /**
- * Returns true if this binding graph resolution is for a subcomponent and the {@code @Inject}
- * binding's scope correctly matches one of the components in the current component ancestry.
- * If not, it means the binding is not owned by any of the currently known components, and will
- * be owned by a future ancestor (or, if never owned, will result in an incompatibly scoped
- * binding error at the root component).
- */
- private boolean isCorrectlyScopedInSubcomponent(ProvisionBinding binding) {
- checkArgument(binding.kind() == INJECTION || binding.kind() == ASSISTED_INJECTION);
- if (!rootComponent().isSubcomponent()
- || !binding.scope().isPresent()
- || binding.scope().get().isReusable()) {
- return true;
- }
-
- Resolver owningResolver = getOwningResolver(binding).orElse(this);
- ComponentDescriptor owningComponent = owningResolver.componentDescriptor;
- return owningComponent.scopes().contains(binding.scope().get());
- }
-
- private ComponentDescriptor rootComponent() {
- return parentResolver.map(Resolver::rootComponent).orElse(componentDescriptor);
- }
-
- /** Returns the resolved members injection bindings for the given {@link Key}. */
- ResolvedBindings lookUpMembersInjectionBinding(Key requestKey) {
- // no explicit deps for members injection, so just look it up
- Optional<MembersInjectionBinding> binding =
- injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey);
- return binding.isPresent()
- ? ResolvedBindings.forMembersInjectionBinding(
- requestKey, componentDescriptor, binding.get())
- : ResolvedBindings.noBindings(requestKey);
- }
-
- /**
- * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link
- * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue
- * will be used to detect which subcomponents need to be resolved.
- */
- private void addSubcomponentToOwningResolver(ProvisionBinding subcomponentCreatorBinding) {
- checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR));
- Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get();
-
- TypeElement builderType = MoreTypes.asTypeElement(subcomponentCreatorBinding.key().type());
- owningResolver.subcomponentsToResolve.add(
- owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType));
- }
-
- /**
- * Profiling has determined that computing the keys matching {@code requestKey} has measurable
- * performance impact. It is called repeatedly (at least 3 times per key resolved per {@link
- * BindingGraph}. {@code javac}'s name-checking performance seems suboptimal (converting byte
- * strings to Strings repeatedly), and the matching keys creations relies on that. This also
- * ensures that the resulting keys have their hash codes cached on successive calls to this
- * method.
- *
- * <p>This caching may become obsolete if:
- *
- * <ul>
- * <li>We decide to intern all {@link Key} instances
- * <li>We fix javac's name-checking peformance (though we may want to keep this for older
- * javac users)
- * </ul>
- */
- private ImmutableSet<Key> keysMatchingRequest(Key requestKey) {
- return keysMatchingRequestCache.computeIfAbsent(
- requestKey, this::keysMatchingRequestUncached);
- }
-
- private ImmutableSet<Key> keysMatchingRequestUncached(Key requestKey) {
- ImmutableSet.Builder<Key> keys = ImmutableSet.builder();
- keys.add(requestKey);
- keyFactory.unwrapSetKey(requestKey, Produced.class).ifPresent(keys::add);
- keyFactory.rewrapMapKey(requestKey, Producer.class, Provider.class).ifPresent(keys::add);
- keyFactory.rewrapMapKey(requestKey, Provider.class, Producer.class).ifPresent(keys::add);
- keys.addAll(keyFactory.implicitFrameworkMapKeys(requestKey));
- return keys.build();
- }
-
- private ImmutableSet<ContributionBinding> createDelegateBindings(
- ImmutableSet<DelegateDeclaration> delegateDeclarations) {
- ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
- for (DelegateDeclaration delegateDeclaration : delegateDeclarations) {
- builder.add(createDelegateBinding(delegateDeclaration));
- }
- return builder.build();
- }
-
- /**
- * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved
- * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate
- * bindings for the dependency key, there should still be only one binding for the delegate key.
- */
- private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) {
- Key delegateKey = delegateDeclaration.delegateRequest().key();
- if (cycleStack.contains(delegateKey)) {
- return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
- }
-
- ResolvedBindings resolvedDelegate;
- try {
- cycleStack.push(delegateKey);
- resolvedDelegate = lookUpBindings(delegateKey);
- } finally {
- cycleStack.pop();
- }
- if (resolvedDelegate.contributionBindings().isEmpty()) {
- // This is guaranteed to result in a missing binding error, so it doesn't matter if the
- // binding is a Provision or Production, except if it is a @IntoMap method, in which
- // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a
- // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a
- // strange error, that the RHS needs to be provided with an @Inject or @Provides
- // annotated method, but a user should be able to figure out if a @Produces annotation
- // is needed.
- // TODO(gak): revisit how we model missing delegates if/when we clean up how we model
- // binding declarations
- return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
- }
- // It doesn't matter which of these is selected, since they will later on produce a
- // duplicate binding error.
- ContributionBinding explicitDelegate =
- resolvedDelegate.contributionBindings().iterator().next();
- return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate);
- }
-
- /**
- * Returns the component that should contain the framework field for {@code binding}.
- *
- * <p>If {@code binding} is either not bound in an ancestor component or depends transitively on
- * bindings in this component, returns this component.
- *
- * <p>Otherwise, resolves {@code request} in this component's parent in order to resolve any
- * multibinding contributions in the parent, and returns the parent-resolved {@link
- * ResolvedBindings#owningComponent(ContributionBinding)}.
- */
- private TypeElement getOwningComponent(Key requestKey, ContributionBinding binding) {
- if (isResolvedInParent(requestKey, binding)
- && !new LocalDependencyChecker().dependsOnLocalBindings(binding)) {
- ResolvedBindings parentResolvedBindings =
- parentResolver.get().resolvedContributionBindings.get(requestKey);
- return parentResolvedBindings.owningComponent(binding);
- } else {
- return componentDescriptor.typeElement();
- }
- }
-
- /**
- * Returns {@code true} if {@code binding} is owned by an ancestor. If so, {@linkplain #resolve
- * resolves} the {@link Key} in this component's parent. Don't resolve directly in the owning
- * component in case it depends on multibindings in any of its descendants.
- */
- private boolean isResolvedInParent(Key requestKey, ContributionBinding binding) {
- Optional<Resolver> owningResolver = getOwningResolver(binding);
- if (owningResolver.isPresent() && !owningResolver.get().equals(this)) {
- parentResolver.get().resolve(requestKey);
- return true;
- } else {
- return false;
- }
- }
-
- private Optional<Resolver> getOwningResolver(ContributionBinding binding) {
- // TODO(ronshapiro): extract the different pieces of this method into their own methods
- if ((binding.scope().isPresent() && binding.scope().get().isProductionScope())
- || binding.bindingType().equals(BindingType.PRODUCTION)) {
- for (Resolver requestResolver : getResolverLineage()) {
- // Resolve @Inject @ProductionScope bindings at the highest production component.
- if (binding.kind().equals(INJECTION)
- && requestResolver.componentDescriptor.isProduction()) {
- return Optional.of(requestResolver);
- }
-
- // Resolve explicit @Produces and @ProductionScope bindings at the highest component that
- // installs the binding.
- if (requestResolver.containsExplicitBinding(binding)) {
- return Optional.of(requestResolver);
- }
- }
- }
-
- if (binding.scope().isPresent() && binding.scope().get().isReusable()) {
- for (Resolver requestResolver : getResolverLineage().reverse()) {
- // If a @Reusable binding was resolved in an ancestor, use that component.
- ResolvedBindings resolvedBindings =
- requestResolver.resolvedContributionBindings.get(binding.key());
- if (resolvedBindings != null
- && resolvedBindings.contributionBindings().contains(binding)) {
- return Optional.of(requestResolver);
- }
- }
- // If a @Reusable binding was not resolved in any ancestor, resolve it here.
- return Optional.empty();
- }
-
- for (Resolver requestResolver : getResolverLineage().reverse()) {
- if (requestResolver.containsExplicitBinding(binding)) {
- return Optional.of(requestResolver);
- }
- }
-
- // look for scope separately. we do this for the case where @Singleton can appear twice
- // in the † compatibility mode
- Optional<Scope> bindingScope = binding.scope();
- if (bindingScope.isPresent()) {
- for (Resolver requestResolver : getResolverLineage().reverse()) {
- if (requestResolver.componentDescriptor.scopes().contains(bindingScope.get())) {
- return Optional.of(requestResolver);
- }
- }
- }
- return Optional.empty();
- }
-
- private boolean containsExplicitBinding(ContributionBinding binding) {
- return explicitBindingsSet.contains(binding)
- || resolverContainsDelegateDeclarationForBinding(binding)
- || subcomponentDeclarations.containsKey(binding.key());
- }
-
- /** Returns true if {@code binding} was installed in a module in this resolver's component. */
- private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) {
- if (!binding.kind().equals(DELEGATE)) {
- return false;
- }
-
- // Map multibinding key values are wrapped with a framework type. This needs to be undone
- // to look it up in the delegate declarations map.
- // TODO(erichang): See if we can standardize the way map keys are used in these data
- // structures, either always wrapped or unwrapped to be consistent and less errorprone.
- Key bindingKey = binding.key();
- if (compilerOptions.strictMultibindingValidation()
- && binding.contributionType().equals(ContributionType.MAP)) {
- bindingKey = keyFactory.unwrapMapValueType(bindingKey);
- }
-
- return delegateDeclarations.get(bindingKey).stream()
- .anyMatch(
- declaration ->
- declaration.contributingModule().equals(binding.contributingModule())
- && declaration.bindingElement().equals(binding.bindingElement()));
- }
-
- /** Returns the resolver lineage from parent to child. */
- private ImmutableList<Resolver> getResolverLineage() {
- ImmutableList.Builder<Resolver> resolverList = ImmutableList.builder();
- for (Optional<Resolver> currentResolver = Optional.of(this);
- currentResolver.isPresent();
- currentResolver = currentResolver.get().parentResolver) {
- resolverList.add(currentResolver.get());
- }
- return resolverList.build().reverse();
- }
-
- /**
- * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this
- * resolver.
- */
- private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) {
- return new ImmutableSet.Builder<ContributionBinding>()
- .addAll(explicitBindings.get(key))
- // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces
- // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's
- // value type if it's a Map<K, Provider/Producer<V>> before looking in
- // delegateDeclarations. createDelegateBindings() will create bindings with the properly
- // wrapped key type.
- .addAll(
- createDelegateBindings(delegateDeclarations.get(keyFactory.unwrapMapValueType(key))))
- .build();
- }
-
- /**
- * Returns the explicit multibinding contributions that contribute to the map or set requested
- * by {@code key} from this resolver.
- */
- private ImmutableSet<ContributionBinding> getLocalExplicitMultibindings(Key key) {
- ImmutableSet.Builder<ContributionBinding> multibindings = ImmutableSet.builder();
- multibindings.addAll(explicitMultibindings.get(key));
- if (!MapType.isMap(key)
- || MapType.from(key).isRawType()
- || MapType.from(key).valuesAreFrameworkType()) {
- // @Binds @IntoMap declarations have key Map<K, V>, unlike @Provides @IntoMap or @Produces
- // @IntoMap, which have Map<K, Provider/Producer<V>> keys. So unwrap the key's type's
- // value type if it's a Map<K, Provider/Producer<V>> before looking in
- // delegateMultibindingDeclarations. createDelegateBindings() will create bindings with the
- // properly wrapped key type.
- multibindings.addAll(
- createDelegateBindings(
- delegateMultibindingDeclarations.get(keyFactory.unwrapMapValueType(key))));
- }
- return multibindings.build();
- }
-
- /**
- * Returns the {@link OptionalBindingDeclaration}s that match the {@code key} from this and all
- * ancestor resolvers.
- */
- private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) {
- Optional<Key> unwrapped = keyFactory.unwrapOptional(key);
- if (!unwrapped.isPresent()) {
- return ImmutableSet.of();
- }
- ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder();
- for (Resolver resolver : getResolverLineage()) {
- declarations.addAll(resolver.optionalBindingDeclarations.get(unwrapped.get()));
- }
- return declarations.build();
- }
-
- /**
- * Returns the {@link ResolvedBindings} for {@code key} that was resolved in this resolver or an
- * ancestor resolver. Only checks for {@link ContributionBinding}s as {@link
- * MembersInjectionBinding}s are not inherited.
- */
- private Optional<ResolvedBindings> getPreviouslyResolvedBindings(Key key) {
- Optional<ResolvedBindings> result =
- Optional.ofNullable(resolvedContributionBindings.get(key));
- if (result.isPresent()) {
- return result;
- } else if (parentResolver.isPresent()) {
- return parentResolver.get().getPreviouslyResolvedBindings(key);
- } else {
- return Optional.empty();
- }
- }
-
- private void resolveMembersInjection(Key key) {
- ResolvedBindings bindings = lookUpMembersInjectionBinding(key);
- resolveDependencies(bindings);
- resolvedMembersInjectionBindings.put(key, bindings);
- }
-
- void resolve(Key key) {
- // If we find a cycle, stop resolving. The original request will add it with all of the
- // other resolved deps.
- if (cycleStack.contains(key)) {
- return;
- }
-
- // If the binding was previously resolved in this (sub)component, don't resolve it again.
- if (resolvedContributionBindings.containsKey(key)) {
- return;
- }
-
- /*
- * If the binding was previously resolved in an ancestor component, then we may be able to
- * avoid resolving it here and just depend on the ancestor component resolution.
- *
- * 1. If it depends transitively on multibinding contributions or optional bindings with
- * bindings from this subcomponent, then we have to resolve it in this subcomponent so
- * that it sees the local bindings.
- *
- * 2. If there are any explicit bindings in this component, they may conflict with those in
- * the ancestor component, so resolve them here so that conflicts can be caught.
- */
- if (getPreviouslyResolvedBindings(key).isPresent()) {
- /* Resolve in the parent in case there are multibinding contributions or conflicts in some
- * component between this one and the previously-resolved one. */
- parentResolver.get().resolve(key);
- if (!new LocalDependencyChecker().dependsOnLocalBindings(key)
- && getLocalExplicitBindings(key).isEmpty()) {
- /* Cache the inherited parent component's bindings in case resolving at the parent found
- * bindings in some component between this one and the previously-resolved one. */
- resolvedContributionBindings.put(key, getPreviouslyResolvedBindings(key).get());
- return;
- }
- }
-
- cycleStack.push(key);
- try {
- ResolvedBindings bindings = lookUpBindings(key);
- resolvedContributionBindings.put(key, bindings);
- resolveDependencies(bindings);
- } finally {
- cycleStack.pop();
- }
- }
-
- /**
- * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this
- * component.
- */
- private void resolveDependencies(ResolvedBindings resolvedBindings) {
- for (Binding binding : resolvedBindings.bindingsOwnedBy(componentDescriptor)) {
- for (DependencyRequest dependency : binding.dependencies()) {
- resolve(dependency.key());
- }
- }
- }
-
- /**
- * Returns all of the {@link ResolvedBindings} for {@link ContributionBinding}s from this and
- * all ancestor resolvers, indexed by {@link ResolvedBindings#key()}.
- */
- Map<Key, ResolvedBindings> getResolvedContributionBindings() {
- Map<Key, ResolvedBindings> bindings = new LinkedHashMap<>();
- parentResolver.ifPresent(parent -> bindings.putAll(parent.getResolvedContributionBindings()));
- bindings.putAll(resolvedContributionBindings);
- return bindings;
- }
-
- /**
- * Returns all of the {@link ResolvedBindings} for {@link MembersInjectionBinding} from this
- * resolvers, indexed by {@link ResolvedBindings#key()}.
- */
- ImmutableMap<Key, ResolvedBindings> getResolvedMembersInjectionBindings() {
- return ImmutableMap.copyOf(resolvedMembersInjectionBindings);
- }
-
- private final class LocalDependencyChecker {
- private final Set<Object> cycleChecker = new HashSet<>();
-
- /**
- * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with
- * contributions declared within this component's modules or optional bindings with present
- * values declared within this component's modules, or if any of its unscoped dependencies
- * depend on such bindings.
- *
- * <p>We don't care about scoped dependencies because they will never depend on bindings from
- * subcomponents.
- *
- * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty
- */
- private boolean dependsOnLocalBindings(Key key) {
- // Don't recur infinitely if there are valid cycles in the dependency graph.
- // http://b/23032377
- if (!cycleChecker.add(key)) {
- return false;
- }
- return reentrantComputeIfAbsent(
- keyDependsOnLocalBindingsCache, key, this::dependsOnLocalBindingsUncached);
- }
-
- /**
- * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable}
- * scope) and depends on multibindings with contributions declared within this component's
- * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend
- * on such local multibindings.
- *
- * <p>We don't care about non-reusable scoped dependencies because they will never depend on
- * multibindings with contributions from subcomponents.
- */
- private boolean dependsOnLocalBindings(Binding binding) {
- if (!cycleChecker.add(binding)) {
- return false;
- }
- return reentrantComputeIfAbsent(
- bindingDependsOnLocalBindingsCache, binding, this::dependsOnLocalBindingsUncached);
- }
-
- private boolean dependsOnLocalBindingsUncached(Key key) {
- checkArgument(
- getPreviouslyResolvedBindings(key).isPresent(),
- "no previously resolved bindings in %s for %s",
- Resolver.this,
- key);
- ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings(key).get();
- if (hasLocalMultibindingContributions(key)
- || hasLocalOptionalBindingContribution(previouslyResolvedBindings)) {
- return true;
- }
-
- for (Binding binding : previouslyResolvedBindings.bindings()) {
- if (dependsOnLocalBindings(binding)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean dependsOnLocalBindingsUncached(Binding binding) {
- if ((!binding.scope().isPresent() || binding.scope().get().isReusable())
- // TODO(beder): Figure out what happens with production subcomponents.
- && !binding.bindingType().equals(BindingType.PRODUCTION)) {
- for (DependencyRequest dependency : binding.dependencies()) {
- if (dependsOnLocalBindings(dependency.key())) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Returns {@code true} if there is at least one multibinding contribution declared within
- * this component's modules that matches the key.
- */
- private boolean hasLocalMultibindingContributions(Key requestKey) {
- return keysMatchingRequest(requestKey)
- .stream()
- .anyMatch(key -> !getLocalExplicitMultibindings(key).isEmpty());
- }
-
- /**
- * Returns {@code true} if there is a contribution in this component for an {@code
- * Optional<Foo>} key that has not been contributed in a parent.
- */
- private boolean hasLocalOptionalBindingContribution(ResolvedBindings resolvedBindings) {
- if (resolvedBindings
- .contributionBindings()
- .stream()
- .map(ContributionBinding::kind)
- .anyMatch(isEqual(OPTIONAL))) {
- return !getLocalExplicitBindings(keyFactory.unwrapOptional(resolvedBindings.key()).get())
- .isEmpty();
- } else {
- // If a parent contributes a @Provides Optional<Foo> binding and a child has a
- // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for
- // Foo on its own
- return !getOptionalBindingDeclarations(resolvedBindings.key()).isEmpty();
- }
- }
- }
- }
-
- /**
- * A multimap of those {@code declarations} that are multibinding contribution declarations,
- * indexed by the key of the set or map to which they contribute.
- */
- static <T extends BindingDeclaration>
- ImmutableSetMultimap<Key, T> multibindingContributionsByMultibindingKey(
- Iterable<T> declarations) {
- ImmutableSetMultimap.Builder<Key, T> builder = ImmutableSetMultimap.builder();
- for (T declaration : declarations) {
- if (declaration.key().multibindingContributionIdentifier().isPresent()) {
- builder.put(
- declaration
- .key()
- .toBuilder()
- .multibindingContributionIdentifier(Optional.empty())
- .build(),
- declaration);
- }
- }
- return builder.build();
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingNode.java b/java/dagger/internal/codegen/binding/BindingNode.java
deleted file mode 100644
index 78d440d..0000000
--- a/java/dagger/internal/codegen/binding/BindingNode.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingType.PRODUCTION;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import dagger.BindsOptionalOf;
-import dagger.Module;
-import dagger.model.BindingKind;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Scope;
-import dagger.multibindings.Multibinds;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/**
- * An implementation of {@link dagger.model.Binding} that also exposes {@link BindingDeclaration}s
- * associated with the binding.
- */
-// TODO(dpb): Consider a supertype of dagger.model.Binding that
-// dagger.internal.codegen.binding.Binding
-// could also implement.
-@AutoValue
-public abstract class BindingNode implements dagger.model.Binding {
- public static BindingNode create(
- ComponentPath component,
- Binding delegate,
- ImmutableSet<MultibindingDeclaration> multibindingDeclarations,
- ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations,
- ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations,
- BindingDeclarationFormatter bindingDeclarationFormatter) {
- BindingNode node =
- new AutoValue_BindingNode(
- component,
- delegate,
- multibindingDeclarations,
- optionalBindingDeclarations,
- subcomponentDeclarations);
- node.bindingDeclarationFormatter = checkNotNull(bindingDeclarationFormatter);
- return node;
- }
-
- private BindingDeclarationFormatter bindingDeclarationFormatter;
-
- public abstract Binding delegate();
-
- public abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
-
- public abstract ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations();
-
- public abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
-
- /**
- * The {@link Element}s (other than the binding's {@link #bindingElement()}) that are associated
- * with the binding.
- *
- * <ul>
- * <li>{@linkplain BindsOptionalOf optional binding} declarations
- * <li>{@linkplain Module#subcomponents() module subcomponent} declarations
- * <li>{@linkplain Multibinds multibinding} declarations
- * </ul>
- */
- public final Iterable<BindingDeclaration> associatedDeclarations() {
- return Iterables.concat(
- multibindingDeclarations(), optionalBindingDeclarations(), subcomponentDeclarations());
- }
-
- @Override
- public Key key() {
- return delegate().key();
- }
-
- @Override
- public ImmutableSet<DependencyRequest> dependencies() {
- return delegate().dependencies();
- }
-
- @Override
- public Optional<Element> bindingElement() {
- return delegate().bindingElement();
- }
-
- @Override
- public Optional<TypeElement> contributingModule() {
- return delegate().contributingModule();
- }
-
- @Override
- public boolean requiresModuleInstance() {
- return delegate().requiresModuleInstance();
- }
-
- @Override
- public Optional<Scope> scope() {
- return delegate().scope();
- }
-
- @Override
- public boolean isNullable() {
- return delegate().isNullable();
- }
-
- @Override
- public boolean isProduction() {
- return delegate().bindingType().equals(PRODUCTION);
- }
-
- @Override
- public BindingKind kind() {
- return delegate().kind();
- }
-
- @Override
- public final String toString() {
- return bindingDeclarationFormatter.format(delegate());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingRequest.java b/java/dagger/internal/codegen/binding/BindingRequest.java
deleted file mode 100644
index d61d9cf..0000000
--- a/java/dagger/internal/codegen/binding/BindingRequest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2018 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 dagger.internal.codegen.base.RequestKinds.requestType;
-
-import com.google.auto.value.AutoValue;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import java.util.Optional;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A request for a binding, which may be in the form of a request for a dependency to pass to a
- * constructor or module method ({@link RequestKind}) or an internal request for a framework
- * instance ({@link FrameworkType}).
- */
-@AutoValue
-public abstract class BindingRequest {
- /** Creates a {@link BindingRequest} for the given {@link DependencyRequest}. */
- public static BindingRequest bindingRequest(DependencyRequest dependencyRequest) {
- return bindingRequest(dependencyRequest.key(), dependencyRequest.kind());
- }
-
- /**
- * Creates a {@link BindingRequest} for a normal dependency request for the given {@link Key} and
- * {@link RequestKind}.
- */
- public static BindingRequest bindingRequest(Key key, RequestKind requestKind) {
- // When there's a request that has a 1:1 mapping to a FrameworkType, the request should be
- // associated with that FrameworkType as well, because we want to ensure that if a request
- // comes in for that as a dependency first and as a framework instance later, they resolve to
- // the same binding expression.
- // TODO(cgdecker): Instead of doing this, make ComponentBindingExpressions create a
- // BindingExpression for the RequestKind that simply delegates to the BindingExpression for the
- // FrameworkType. Then there are separate BindingExpressions, but we don't end up doing weird
- // things like creating two fields when there should only be one.
- return new AutoValue_BindingRequest(
- key, Optional.of(requestKind), FrameworkType.forRequestKind(requestKind));
- }
-
- /**
- * Creates a {@link BindingRequest} for a request for a framework instance for the given {@link
- * Key} with the given {@link FrameworkType}.
- */
- public static BindingRequest bindingRequest(Key key, FrameworkType frameworkType) {
- return new AutoValue_BindingRequest(
- key, frameworkType.requestKind(), Optional.of(frameworkType));
- }
-
- /** Returns the {@link Key} for the requested binding. */
- public abstract Key key();
-
- /** Returns the request kind associated with this request, if any. */
- public abstract Optional<RequestKind> requestKind();
-
- /** Returns the framework type associated with this request, if any. */
- public abstract Optional<FrameworkType> frameworkType();
-
- /** Returns whether this request is of the given kind. */
- public final boolean isRequestKind(RequestKind requestKind) {
- return requestKind.equals(requestKind().orElse(null));
- }
-
- public final TypeMirror requestedType(TypeMirror contributedType, DaggerTypes types) {
- if (requestKind().isPresent()) {
- return requestType(requestKind().get(), contributedType, types);
- }
- return types.wrapType(contributedType, frameworkType().get().frameworkClass());
- }
-
- /** Returns a name that can be used for the kind of request this is. */
- public final String kindName() {
- Object requestKindObject =
- requestKind().isPresent()
- ? requestKind().get()
- : frameworkType().get().frameworkClass().getSimpleName();
- return requestKindObject.toString();
- }
-}
diff --git a/java/dagger/internal/codegen/binding/BindingType.java b/java/dagger/internal/codegen/binding/BindingType.java
deleted file mode 100644
index 7f5ea54..0000000
--- a/java/dagger/internal/codegen/binding/BindingType.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import dagger.MembersInjector;
-
-/** Whether a binding or declaration is for provision, production, or a {@link MembersInjector}. */
-public enum BindingType {
- /** A binding with this type is a {@link ProvisionBinding}. */
- PROVISION,
-
- /** A binding with this type is a {@link MembersInjectionBinding}. */
- MEMBERS_INJECTION,
-
- /** A binding with this type is a {@link ProductionBinding}. */
- PRODUCTION,
-}
diff --git a/java/dagger/internal/codegen/binding/BindsTypeChecker.java b/java/dagger/internal/codegen/binding/BindsTypeChecker.java
deleted file mode 100644
index f3e0a1b..0000000
--- a/java/dagger/internal/codegen/binding/BindsTypeChecker.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.google.common.collect.Iterables.getOnlyElement;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Checks the assignability of one type to another, given a {@link ContributionType} context. This
- * is used by {@link dagger.internal.codegen.validation.BindsMethodValidator} to validate that the
- * right-hand- side of a {@link dagger.Binds} method is valid, as well as in {@link
- * dagger.internal.codegen.writing.DelegateBindingExpression} when the right-hand-side in generated
- * code might be an erased type due to accessibility.
- */
-public final class BindsTypeChecker {
- private final DaggerTypes types;
- private final DaggerElements elements;
-
- // TODO(bcorso): Make this pkg-private. Used by DelegateBindingExpression.
- @Inject
- public BindsTypeChecker(DaggerTypes types, DaggerElements elements) {
- this.types = types;
- this.elements = elements;
- }
-
- /**
- * Checks the assignability of {@code rightHandSide} to {@code leftHandSide} given a {@link
- * ContributionType} context.
- */
- public boolean isAssignable(
- TypeMirror rightHandSide, TypeMirror leftHandSide, ContributionType contributionType) {
- return types.isAssignable(rightHandSide, desiredAssignableType(leftHandSide, contributionType));
- }
-
- private TypeMirror desiredAssignableType(
- TypeMirror leftHandSide, ContributionType contributionType) {
- switch (contributionType) {
- case UNIQUE:
- return leftHandSide;
- case SET:
- DeclaredType parameterizedSetType = types.getDeclaredType(setElement(), leftHandSide);
- return methodParameterType(parameterizedSetType, "add");
- case SET_VALUES:
- return methodParameterType(MoreTypes.asDeclared(leftHandSide), "addAll");
- case MAP:
- DeclaredType parameterizedMapType =
- types.getDeclaredType(mapElement(), unboundedWildcard(), leftHandSide);
- return methodParameterTypes(parameterizedMapType, "put").get(1);
- }
- throw new AssertionError("Unknown contribution type: " + contributionType);
- }
-
- private ImmutableList<TypeMirror> methodParameterTypes(DeclaredType type, String methodName) {
- ImmutableList.Builder<ExecutableElement> methodsForName = ImmutableList.builder();
- for (ExecutableElement method :
- // type.asElement().getEnclosedElements() is not used because some non-standard JDKs (e.g.
- // J2CL) don't redefine Set.add() (whose only purpose of being redefined in the standard JDK
- // is documentation, and J2CL's implementation doesn't declare docs for JDK types).
- // MoreElements.getLocalAndInheritedMethods ensures that the method will always be present.
- MoreElements.getLocalAndInheritedMethods(MoreTypes.asTypeElement(type), types, elements)) {
- if (method.getSimpleName().contentEquals(methodName)) {
- methodsForName.add(method);
- }
- }
- ExecutableElement method = getOnlyElement(methodsForName.build());
- return ImmutableList.copyOf(
- MoreTypes.asExecutable(types.asMemberOf(type, method)).getParameterTypes());
- }
-
- private TypeMirror methodParameterType(DeclaredType type, String methodName) {
- return getOnlyElement(methodParameterTypes(type, methodName));
- }
-
- private TypeElement setElement() {
- return elements.getTypeElement(Set.class);
- }
-
- private TypeElement mapElement() {
- return elements.getTypeElement(Map.class);
- }
-
- private TypeMirror unboundedWildcard() {
- return types.getWildcardType(null, null);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java b/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
deleted file mode 100644
index c056588..0000000
--- a/java/dagger/internal/codegen/binding/ChildFactoryMethodEdgeImpl.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 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 dagger.internal.codegen.base.ElementFormatter.elementToString;
-
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import javax.lang.model.element.ExecutableElement;
-
-/** An implementation of {@link ChildFactoryMethodEdge}. */
-public final class ChildFactoryMethodEdgeImpl implements ChildFactoryMethodEdge {
-
- private final ExecutableElement factoryMethod;
-
- ChildFactoryMethodEdgeImpl(ExecutableElement factoryMethod) {
- this.factoryMethod = factoryMethod;
- }
-
- @Override
- public ExecutableElement factoryMethod() {
- return factoryMethod;
- }
-
- @Override
- public String toString() {
- return elementToString(factoryMethod);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorAnnotation.java b/java/dagger/internal/codegen/binding/ComponentCreatorAnnotation.java
deleted file mode 100644
index 6297188..0000000
--- a/java/dagger/internal/codegen/binding/ComponentCreatorAnnotation.java
+++ /dev/null
@@ -1,152 +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.internal.codegen.binding;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.Ascii.toUpperCase;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.DaggerStreams.valuesOf;
-import static java.util.stream.Collectors.mapping;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Component;
-import dagger.Subcomponent;
-import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.stream.Collector;
-import java.util.stream.Stream;
-import javax.lang.model.element.TypeElement;
-
-/** Simple representation of a component creator annotation type. */
-public enum ComponentCreatorAnnotation {
- COMPONENT_BUILDER(Component.Builder.class),
- COMPONENT_FACTORY(Component.Factory.class),
- SUBCOMPONENT_BUILDER(Subcomponent.Builder.class),
- SUBCOMPONENT_FACTORY(Subcomponent.Factory.class),
- PRODUCTION_COMPONENT_BUILDER(ProductionComponent.Builder.class),
- PRODUCTION_COMPONENT_FACTORY(ProductionComponent.Factory.class),
- PRODUCTION_SUBCOMPONENT_BUILDER(ProductionSubcomponent.Builder.class),
- PRODUCTION_SUBCOMPONENT_FACTORY(ProductionSubcomponent.Factory.class),
- ;
-
- private final Class<? extends Annotation> annotation;
- private final ComponentCreatorKind creatorKind;
- private final Class<? extends Annotation> componentAnnotation;
-
- @SuppressWarnings("unchecked") // Builder/factory annotations live within their parent annotation.
- ComponentCreatorAnnotation(Class<? extends Annotation> annotation) {
- this.annotation = annotation;
- this.creatorKind = ComponentCreatorKind.valueOf(toUpperCase(annotation.getSimpleName()));
- this.componentAnnotation = (Class<? extends Annotation>) annotation.getEnclosingClass();
- }
-
- /** The actual annotation type. */
- public Class<? extends Annotation> annotation() {
- return annotation;
- }
-
- /** The component annotation type that encloses this creator annotation type. */
- public final Class<? extends Annotation> componentAnnotation() {
- return componentAnnotation;
- }
-
- /** Returns {@code true} if the creator annotation is for a subcomponent. */
- public final boolean isSubcomponentCreatorAnnotation() {
- return componentAnnotation().getSimpleName().endsWith("Subcomponent");
- }
-
- /**
- * Returns {@code true} if the creator annotation is for a production component or subcomponent.
- */
- public final boolean isProductionCreatorAnnotation() {
- return componentAnnotation().getSimpleName().startsWith("Production");
- }
-
- /** The creator kind the annotation is associated with. */
- // TODO(dpb): Remove ComponentCreatorKind.
- public ComponentCreatorKind creatorKind() {
- return creatorKind;
- }
-
- @Override
- public final String toString() {
- return annotation().getName();
- }
-
- /** Returns all component creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> allCreatorAnnotations() {
- return stream().collect(toAnnotationClasses());
- }
-
- /** Returns all root component creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> rootComponentCreatorAnnotations() {
- return stream()
- .filter(
- componentCreatorAnnotation ->
- !componentCreatorAnnotation.isSubcomponentCreatorAnnotation())
- .collect(toAnnotationClasses());
- }
-
- /** Returns all subcomponent creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> subcomponentCreatorAnnotations() {
- return stream()
- .filter(
- componentCreatorAnnotation ->
- componentCreatorAnnotation.isSubcomponentCreatorAnnotation())
- .collect(toAnnotationClasses());
- }
-
- /** Returns all production component creator annotations. */
- public static ImmutableSet<Class<? extends Annotation>> productionCreatorAnnotations() {
- return stream()
- .filter(
- componentCreatorAnnotation ->
- componentCreatorAnnotation.isProductionCreatorAnnotation())
- .collect(toAnnotationClasses());
- }
-
- /** Returns the legal creator annotations for the given {@code componentAnnotation}. */
- public static ImmutableSet<Class<? extends Annotation>> creatorAnnotationsFor(
- ComponentAnnotation componentAnnotation) {
- return stream()
- .filter(
- creatorAnnotation ->
- creatorAnnotation
- .componentAnnotation()
- .getSimpleName()
- .equals(componentAnnotation.simpleName()))
- .collect(toAnnotationClasses());
- }
-
- /** Returns all creator annotations present on the given {@code type}. */
- public static ImmutableSet<ComponentCreatorAnnotation> getCreatorAnnotations(TypeElement type) {
- return stream()
- .filter(cca -> isAnnotationPresent(type, cca.annotation()))
- .collect(toImmutableSet());
- }
-
- private static Stream<ComponentCreatorAnnotation> stream() {
- return valuesOf(ComponentCreatorAnnotation.class);
- }
-
- private static Collector<ComponentCreatorAnnotation, ?, ImmutableSet<Class<? extends Annotation>>>
- toAnnotationClasses() {
- return mapping(ComponentCreatorAnnotation::annotation, toImmutableSet());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java b/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
deleted file mode 100644
index 5ea30ed..0000000
--- a/java/dagger/internal/codegen/binding/ComponentCreatorDescriptor.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.MoreTypes;
-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.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import dagger.BindsInstance;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import java.util.List;
-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.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A descriptor for a component <i>creator</i> type: that is, a type annotated with
- * {@code @Component.Builder} (or one of the corresponding production or subcomponent versions).
- */
-@AutoValue
-public abstract class ComponentCreatorDescriptor {
-
- /** Returns the annotation marking this creator. */
- public abstract ComponentCreatorAnnotation annotation();
-
- /** The kind of this creator. */
- public final ComponentCreatorKind kind() {
- return annotation().creatorKind();
- }
-
- /** The annotated creator type. */
- public abstract TypeElement typeElement();
-
- /** The method that creates and returns a component instance. */
- public abstract ExecutableElement factoryMethod();
-
- /**
- * Multimap of component requirements to setter methods that set that requirement.
- *
- * <p>In a valid creator, there will be exactly one element per component requirement, so this
- * method should only be called when validating the descriptor.
- */
- abstract ImmutableSetMultimap<ComponentRequirement, ExecutableElement> unvalidatedSetterMethods();
-
- /**
- * Multimap of component requirements to factory method parameters that set that requirement.
- *
- * <p>In a valid creator, there will be exactly one element per component requirement, so this
- * method should only be called when validating the descriptor.
- */
- abstract ImmutableSetMultimap<ComponentRequirement, VariableElement>
- unvalidatedFactoryParameters();
-
- /**
- * Multimap of component requirements to elements (methods or parameters) that set that
- * requirement.
- *
- * <p>In a valid creator, there will be exactly one element per component requirement, so this
- * method should only be called when validating the descriptor.
- */
- public final ImmutableSetMultimap<ComponentRequirement, Element>
- unvalidatedRequirementElements() {
- // ComponentCreatorValidator ensures that there are either setter methods or factory method
- // parameters, but not both, so we can cheat a little here since we know that only one of
- // the two multimaps will be non-empty.
- return ImmutableSetMultimap.copyOf( // no actual copy
- unvalidatedSetterMethods().isEmpty()
- ? unvalidatedFactoryParameters()
- : unvalidatedSetterMethods());
- }
-
- /**
- * Map of component requirements to elements (setter methods or factory method parameters) that
- * set them.
- */
- @Memoized
- ImmutableMap<ComponentRequirement, Element> requirementElements() {
- return flatten(unvalidatedRequirementElements());
- }
-
- /** Map of component requirements to setter methods for those requirements. */
- @Memoized
- public ImmutableMap<ComponentRequirement, ExecutableElement> setterMethods() {
- return flatten(unvalidatedSetterMethods());
- }
-
- /** Map of component requirements to factory method parameters for those requirements. */
- @Memoized
- public ImmutableMap<ComponentRequirement, VariableElement> factoryParameters() {
- return flatten(unvalidatedFactoryParameters());
- }
-
- private static <K, V> ImmutableMap<K, V> flatten(Multimap<K, V> multimap) {
- return ImmutableMap.copyOf(
- Maps.transformValues(multimap.asMap(), values -> getOnlyElement(values)));
- }
-
- /** Returns the set of component requirements this creator allows the user to set. */
- public final ImmutableSet<ComponentRequirement> userSettableRequirements() {
- // Note: they should have been validated at the point this is used, so this set is valid.
- return unvalidatedRequirementElements().keySet();
- }
-
- /** Returns the set of requirements for modules and component dependencies for this creator. */
- public final ImmutableSet<ComponentRequirement> moduleAndDependencyRequirements() {
- return userSettableRequirements().stream()
- .filter(requirement -> !requirement.isBoundInstance())
- .collect(toImmutableSet());
- }
-
- /** Returns the set of bound instance requirements for this creator. */
- final ImmutableSet<ComponentRequirement> boundInstanceRequirements() {
- return userSettableRequirements().stream()
- .filter(ComponentRequirement::isBoundInstance)
- .collect(toImmutableSet());
- }
-
- /** Returns the element in this creator that sets the given {@code requirement}. */
- final Element elementForRequirement(ComponentRequirement requirement) {
- return requirementElements().get(requirement);
- }
-
- /** Creates a new {@link ComponentCreatorDescriptor} for the given creator {@code type}. */
- public static ComponentCreatorDescriptor create(
- DeclaredType type,
- DaggerElements elements,
- DaggerTypes types,
- DependencyRequestFactory dependencyRequestFactory) {
- TypeElement typeElement = asTypeElement(type);
- TypeMirror componentType = typeElement.getEnclosingElement().asType();
-
- ImmutableSetMultimap.Builder<ComponentRequirement, ExecutableElement> setterMethods =
- ImmutableSetMultimap.builder();
-
- ExecutableElement factoryMethod = null;
- for (ExecutableElement method : elements.getUnimplementedMethods(typeElement)) {
- ExecutableType resolvedMethodType = MoreTypes.asExecutable(types.asMemberOf(type, method));
-
- if (types.isSubtype(componentType, resolvedMethodType.getReturnType())) {
- factoryMethod = method;
- } else {
- VariableElement parameter = getOnlyElement(method.getParameters());
- TypeMirror parameterType = getOnlyElement(resolvedMethodType.getParameterTypes());
- setterMethods.put(
- requirement(method, parameter, parameterType, dependencyRequestFactory, method),
- method);
- }
- }
- verify(factoryMethod != null); // validation should have ensured this.
-
- ImmutableSetMultimap.Builder<ComponentRequirement, VariableElement> factoryParameters =
- ImmutableSetMultimap.builder();
-
- ExecutableType resolvedFactoryMethodType =
- MoreTypes.asExecutable(types.asMemberOf(type, factoryMethod));
- List<? extends VariableElement> parameters = factoryMethod.getParameters();
- List<? extends TypeMirror> parameterTypes = resolvedFactoryMethodType.getParameterTypes();
- for (int i = 0; i < parameters.size(); i++) {
- VariableElement parameter = parameters.get(i);
- TypeMirror parameterType = parameterTypes.get(i);
- factoryParameters.put(
- requirement(factoryMethod, parameter, parameterType, dependencyRequestFactory, parameter),
- parameter);
- }
-
- // Validation should have ensured exactly one creator annotation is present on the type.
- ComponentCreatorAnnotation annotation = getOnlyElement(getCreatorAnnotations(typeElement));
- return new AutoValue_ComponentCreatorDescriptor(
- annotation, typeElement, factoryMethod, setterMethods.build(), factoryParameters.build());
- }
-
- private static ComponentRequirement requirement(
- ExecutableElement method,
- VariableElement parameter,
- TypeMirror type,
- DependencyRequestFactory dependencyRequestFactory,
- Element elementForVariableName) {
- if (isAnnotationPresent(method, BindsInstance.class)
- || isAnnotationPresent(parameter, BindsInstance.class)) {
- DependencyRequest request =
- dependencyRequestFactory.forRequiredResolvedVariable(parameter, type);
- String variableName = elementForVariableName.getSimpleName().toString();
- return ComponentRequirement.forBoundInstance(
- request.key(), request.isNullable(), variableName);
- }
-
- return moduleAnnotation(asTypeElement(type)).isPresent()
- ? ComponentRequirement.forModule(type)
- : ComponentRequirement.forDependency(type);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentCreatorKind.java b/java/dagger/internal/codegen/binding/ComponentCreatorKind.java
deleted file mode 100644
index b2581d6..0000000
--- a/java/dagger/internal/codegen/binding/ComponentCreatorKind.java
+++ /dev/null
@@ -1,42 +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.internal.codegen.binding;
-
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-
-import com.google.common.base.Ascii;
-
-/** Enumeration of the different kinds of component creators. */
-public enum ComponentCreatorKind {
- /** {@code @Component.Builder} or one of its subcomponent/production variants. */
- BUILDER,
-
- /** {@code @Component.Factory} or one of its subcomponent/production variants. */
- FACTORY,
- ;
-
- /** Name to use as (or as part of) a type name for a creator of this kind. */
- public String typeName() {
- return UPPER_UNDERSCORE.to(UPPER_CAMEL, name());
- }
-
- /** Name to use for a component's static method returning a creator of this kind. */
- public String methodName() {
- return Ascii.toLowerCase(name());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptor.java b/java/dagger/internal/codegen/binding/ComponentDescriptor.java
deleted file mode 100644
index a7e4cc4..0000000
--- a/java/dagger/internal/codegen/binding/ComponentDescriptor.java
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.type.TypeKind.VOID;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.Component;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Scope;
-import dagger.producers.CancellationPolicy;
-import dagger.producers.ProductionComponent;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Stream;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A component declaration.
- *
- * <p>Represents one type annotated with {@code @Component}, {@code Subcomponent},
- * {@code @ProductionComponent}, or {@code @ProductionSubcomponent}.
- *
- * <p>When validating bindings installed in modules, a {@link ComponentDescriptor} can also
- * represent a synthetic component for the module, where there is an entry point for each binding in
- * the module.
- */
-@AutoValue
-public abstract class ComponentDescriptor {
- /** The annotation that specifies that {@link #typeElement()} is a component. */
- public abstract ComponentAnnotation annotation();
-
- /** Returns {@code true} if this is a subcomponent. */
- public final boolean isSubcomponent() {
- return annotation().isSubcomponent();
- }
-
- /**
- * Returns {@code true} if this is a production component or subcomponent, or a
- * {@code @ProducerModule} when doing module binding validation.
- */
- public final boolean isProduction() {
- return annotation().isProduction();
- }
-
- /**
- * Returns {@code true} if this is a real component, and not a fictional one used to validate
- * module bindings.
- */
- public final boolean isRealComponent() {
- return annotation().isRealComponent();
- }
-
- /**
- * The element that defines the component. This is the element to which the {@link #annotation()}
- * was applied.
- */
- public abstract TypeElement typeElement();
-
- /**
- * The set of component dependencies listed in {@link Component#dependencies} or {@link
- * ProductionComponent#dependencies()}.
- */
- public abstract ImmutableSet<ComponentRequirement> dependencies();
-
- /** The non-abstract {@link #modules()} and the {@link #dependencies()}. */
- public final ImmutableSet<ComponentRequirement> dependenciesAndConcreteModules() {
- return Stream.concat(
- moduleTypes().stream()
- .filter(dep -> !dep.getModifiers().contains(ABSTRACT))
- .map(module -> ComponentRequirement.forModule(module.asType())),
- dependencies().stream())
- .collect(toImmutableSet());
- }
-
- /**
- * The {@link ModuleDescriptor modules} declared in {@link Component#modules()} and reachable by
- * traversing {@link Module#includes()}.
- */
- public abstract ImmutableSet<ModuleDescriptor> modules();
-
- /** The types of the {@link #modules()}. */
- public final ImmutableSet<TypeElement> moduleTypes() {
- return modules().stream().map(ModuleDescriptor::moduleElement).collect(toImmutableSet());
- }
-
- /**
- * The types for which the component will need instances if all of its bindings are used. For the
- * types the component will need in a given binding graph, use {@link
- * BindingGraph#componentRequirements()}.
- *
- * <ul>
- * <li>{@linkplain #modules()} modules} with concrete instance bindings
- * <li>Bound instances
- * <li>{@linkplain #dependencies() dependencies}
- * </ul>
- */
- @Memoized
- ImmutableSet<ComponentRequirement> requirements() {
- ImmutableSet.Builder<ComponentRequirement> requirements = ImmutableSet.builder();
- modules().stream()
- .filter(
- module ->
- module.bindings().stream().anyMatch(ContributionBinding::requiresModuleInstance))
- .map(module -> ComponentRequirement.forModule(module.moduleElement().asType()))
- .forEach(requirements::add);
- requirements.addAll(dependencies());
- requirements.addAll(
- creatorDescriptor()
- .map(ComponentCreatorDescriptor::boundInstanceRequirements)
- .orElse(ImmutableSet.of()));
- return requirements.build();
- }
-
- /**
- * This component's {@linkplain #dependencies() dependencies} keyed by each provision or
- * production method defined by that dependency. Note that the dependencies' types are not simply
- * the enclosing type of the method; a method may be declared by a supertype of the actual
- * dependency.
- */
- public abstract ImmutableMap<ExecutableElement, ComponentRequirement>
- dependenciesByDependencyMethod();
-
- /** The {@linkplain #dependencies() component dependency} that defines a method. */
- public final ComponentRequirement getDependencyThatDefinesMethod(Element method) {
- checkArgument(
- method instanceof ExecutableElement, "method must be an executable element: %s", method);
- return checkNotNull(
- dependenciesByDependencyMethod().get(method), "no dependency implements %s", method);
- }
-
- /** The scopes of the component. */
- public abstract ImmutableSet<Scope> scopes();
-
- /**
- * All {@link Subcomponent}s which are direct children of this component. This includes
- * subcomponents installed from {@link Module#subcomponents()} as well as subcomponent {@linkplain
- * #childComponentsDeclaredByFactoryMethods() factory methods} and {@linkplain
- * #childComponentsDeclaredByBuilderEntryPoints() builder methods}.
- */
- public final ImmutableSet<ComponentDescriptor> childComponents() {
- return ImmutableSet.<ComponentDescriptor>builder()
- .addAll(childComponentsDeclaredByFactoryMethods().values())
- .addAll(childComponentsDeclaredByBuilderEntryPoints().values())
- .addAll(childComponentsDeclaredByModules())
- .build();
- }
-
- /**
- * All {@linkplain Subcomponent direct child} components that are declared by a {@linkplain
- * Module#subcomponents() module's subcomponents}.
- */
- abstract ImmutableSet<ComponentDescriptor> childComponentsDeclaredByModules();
-
- /**
- * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
- * factory method.
- */
- public abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
- childComponentsDeclaredByFactoryMethods();
-
- /** Returns a map of {@link #childComponents()} indexed by {@link #typeElement()}. */
- @Memoized
- public ImmutableMap<TypeElement, ComponentDescriptor> childComponentsByElement() {
- return Maps.uniqueIndex(childComponents(), ComponentDescriptor::typeElement);
- }
-
- /** Returns the factory method that declares a child component. */
- final Optional<ComponentMethodDescriptor> getFactoryMethodForChildComponent(
- ComponentDescriptor childComponent) {
- return Optional.ofNullable(
- childComponentsDeclaredByFactoryMethods().inverse().get(childComponent));
- }
-
- /**
- * All {@linkplain Subcomponent direct child} components that are declared by a subcomponent
- * builder method.
- */
- abstract ImmutableBiMap<ComponentMethodDescriptor, ComponentDescriptor>
- childComponentsDeclaredByBuilderEntryPoints();
-
- private final Supplier<ImmutableMap<TypeElement, ComponentDescriptor>>
- childComponentsByBuilderType =
- Suppliers.memoize(
- () ->
- childComponents().stream()
- .filter(child -> child.creatorDescriptor().isPresent())
- .collect(
- toImmutableMap(
- child -> child.creatorDescriptor().get().typeElement(),
- child -> child)));
-
- /** Returns the child component with the given builder type. */
- final ComponentDescriptor getChildComponentWithBuilderType(TypeElement builderType) {
- return checkNotNull(
- childComponentsByBuilderType.get().get(builderType),
- "no child component found for builder type %s",
- builderType.getQualifiedName());
- }
-
- public abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
-
- /** Returns the first component method associated with this binding request, if one exists. */
- public Optional<ComponentMethodDescriptor> firstMatchingComponentMethod(BindingRequest request) {
- return componentMethods().stream()
- .filter(method -> doesComponentMethodMatch(method, request))
- .findFirst();
- }
-
- /** Returns true if the component method matches the binding request. */
- private static boolean doesComponentMethodMatch(
- ComponentMethodDescriptor componentMethod, BindingRequest request) {
- return componentMethod
- .dependencyRequest()
- .map(BindingRequest::bindingRequest)
- .filter(request::equals)
- .isPresent();
- }
-
- /** The entry point methods on the component type. Each has a {@link DependencyRequest}. */
- public final ImmutableSet<ComponentMethodDescriptor> entryPointMethods() {
- return componentMethods()
- .stream()
- .filter(method -> method.dependencyRequest().isPresent())
- .collect(toImmutableSet());
- }
-
- // TODO(gak): Consider making this non-optional and revising the
- // interaction between the spec & generation
- /** Returns a descriptor for the creator type for this component type, if the user defined one. */
- public abstract Optional<ComponentCreatorDescriptor> creatorDescriptor();
-
- /**
- * Returns {@code true} for components that have a creator, either because the user {@linkplain
- * #creatorDescriptor() specified one} or because it's a top-level component with an implicit
- * builder.
- */
- public final boolean hasCreator() {
- return !isSubcomponent() || creatorDescriptor().isPresent();
- }
-
- /**
- * Returns the {@link CancellationPolicy} for this component, or an empty optional if either the
- * component is not a production component or no {@code CancellationPolicy} annotation is present.
- */
- public final Optional<CancellationPolicy> cancellationPolicy() {
- return isProduction()
- ? Optional.ofNullable(typeElement().getAnnotation(CancellationPolicy.class))
- : Optional.empty();
- }
-
- @Memoized
- @Override
- public int hashCode() {
- // TODO(b/122962745): Only use typeElement().hashCode()
- return Objects.hash(typeElement(), annotation());
- }
-
- // TODO(ronshapiro): simplify the equality semantics
- @Override
- public abstract boolean equals(Object obj);
-
- /** A component method. */
- @AutoValue
- public abstract static class ComponentMethodDescriptor {
- /** The method itself. Note that this may be declared on a supertype of the component. */
- public abstract ExecutableElement methodElement();
-
- /**
- * The dependency request for production, provision, and subcomponent creator methods. Absent
- * for subcomponent factory methods.
- */
- public abstract Optional<DependencyRequest> dependencyRequest();
-
- /** The subcomponent for subcomponent factory methods and subcomponent creator methods. */
- public abstract Optional<ComponentDescriptor> subcomponent();
-
- /**
- * Returns the return type of {@link #methodElement()} as resolved in the {@link
- * ComponentDescriptor#typeElement() component type}. If there are no type variables in the
- * return type, this is the equivalent of {@code methodElement().getReturnType()}.
- */
- public TypeMirror resolvedReturnType(DaggerTypes types) {
- checkState(dependencyRequest().isPresent());
-
- TypeMirror returnType = methodElement().getReturnType();
- if (returnType.getKind().isPrimitive() || returnType.getKind().equals(VOID)) {
- return returnType;
- }
- return BindingRequest.bindingRequest(dependencyRequest().get())
- .requestedType(dependencyRequest().get().key().type(), types);
- }
-
- /** A {@link ComponentMethodDescriptor}builder for a method. */
- public static Builder builder(ExecutableElement method) {
- return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor.Builder()
- .methodElement(method);
- }
-
- /** A builder of {@link ComponentMethodDescriptor}s. */
- @AutoValue.Builder
- @CanIgnoreReturnValue
- public interface Builder {
- /** @see ComponentMethodDescriptor#methodElement() */
- Builder methodElement(ExecutableElement methodElement);
-
- /** @see ComponentMethodDescriptor#dependencyRequest() */
- Builder dependencyRequest(DependencyRequest dependencyRequest);
-
- /** @see ComponentMethodDescriptor#subcomponent() */
- Builder subcomponent(ComponentDescriptor subcomponent);
-
- /** Builds the descriptor. */
- @CheckReturnValue
- ComponentMethodDescriptor build();
- }
- }
-
- /** No-argument methods defined on {@link Object} that are ignored for contribution. */
- private static final ImmutableSet<String> NON_CONTRIBUTING_OBJECT_METHOD_NAMES =
- ImmutableSet.of("toString", "hashCode", "clone", "getClass");
-
- /**
- * Returns {@code true} if a method could be a component entry point but not a members-injection
- * method.
- */
- static boolean isComponentContributionMethod(DaggerElements elements, ExecutableElement method) {
- return method.getParameters().isEmpty()
- && !method.getReturnType().getKind().equals(VOID)
- && !elements.getTypeElement(Object.class).equals(method.getEnclosingElement())
- && !NON_CONTRIBUTING_OBJECT_METHOD_NAMES.contains(method.getSimpleName().toString());
- }
-
- /** Returns {@code true} if a method could be a component production entry point. */
- static boolean isComponentProductionMethod(DaggerElements elements, ExecutableElement method) {
- return isComponentContributionMethod(elements, method) && isFutureType(method.getReturnType());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java b/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
deleted file mode 100644
index f13aa50..0000000
--- a/java/dagger/internal/codegen/binding/ComponentDescriptorFactory.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
-import static dagger.internal.codegen.base.Scopes.productionScope;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.creatorAnnotationsFor;
-import static dagger.internal.codegen.binding.ComponentDescriptor.isComponentContributionMethod;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.isSubcomponentCreator;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.VOID;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.internal.codegen.base.ModuleAnnotation;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Scope;
-import java.util.Optional;
-import java.util.function.Function;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/** A factory for {@link ComponentDescriptor}s. */
-public final class ComponentDescriptorFactory {
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final DependencyRequestFactory dependencyRequestFactory;
- private final ModuleDescriptor.Factory moduleDescriptorFactory;
- private final InjectionAnnotations injectionAnnotations;
-
- @Inject
- ComponentDescriptorFactory(
- DaggerElements elements,
- DaggerTypes types,
- DependencyRequestFactory dependencyRequestFactory,
- ModuleDescriptor.Factory moduleDescriptorFactory,
- InjectionAnnotations injectionAnnotations) {
- this.elements = elements;
- this.types = types;
- this.dependencyRequestFactory = dependencyRequestFactory;
- this.moduleDescriptorFactory = moduleDescriptorFactory;
- this.injectionAnnotations = injectionAnnotations;
- }
-
- /** Returns a descriptor for a root component type. */
- public ComponentDescriptor rootComponentDescriptor(TypeElement typeElement) {
- return create(
- typeElement,
- checkAnnotation(
- typeElement,
- ComponentAnnotation::rootComponentAnnotation,
- "must have a component annotation"));
- }
-
- /** Returns a descriptor for a subcomponent type. */
- public ComponentDescriptor subcomponentDescriptor(TypeElement typeElement) {
- return create(
- typeElement,
- checkAnnotation(
- typeElement,
- ComponentAnnotation::subcomponentAnnotation,
- "must have a subcomponent annotation"));
- }
-
- /**
- * Returns a descriptor for a fictional component based on a module type in order to validate its
- * bindings.
- */
- public ComponentDescriptor moduleComponentDescriptor(TypeElement typeElement) {
- return create(
- typeElement,
- ComponentAnnotation.fromModuleAnnotation(
- checkAnnotation(
- typeElement, ModuleAnnotation::moduleAnnotation, "must have a module annotation")));
- }
-
- private static <A> A checkAnnotation(
- TypeElement typeElement,
- Function<TypeElement, Optional<A>> annotationFunction,
- String message) {
- return annotationFunction
- .apply(typeElement)
- .orElseThrow(() -> new IllegalArgumentException(typeElement + " " + message));
- }
-
- private ComponentDescriptor create(
- TypeElement typeElement, ComponentAnnotation componentAnnotation) {
- ImmutableSet<ComponentRequirement> componentDependencies =
- componentAnnotation.dependencyTypes().stream()
- .map(ComponentRequirement::forDependency)
- .collect(toImmutableSet());
-
- ImmutableMap.Builder<ExecutableElement, ComponentRequirement> dependenciesByDependencyMethod =
- ImmutableMap.builder();
-
- for (ComponentRequirement componentDependency : componentDependencies) {
- for (ExecutableElement dependencyMethod :
- methodsIn(elements.getAllMembers(componentDependency.typeElement()))) {
- if (isComponentContributionMethod(elements, dependencyMethod)) {
- dependenciesByDependencyMethod.put(dependencyMethod, componentDependency);
- }
- }
- }
-
- // Start with the component's modules. For fictional components built from a module, start with
- // that module.
- ImmutableSet<TypeElement> modules =
- componentAnnotation.isRealComponent()
- ? componentAnnotation.modules()
- : ImmutableSet.of(typeElement);
-
- ImmutableSet<ModuleDescriptor> transitiveModules =
- moduleDescriptorFactory.transitiveModules(modules);
-
- ImmutableSet.Builder<ComponentDescriptor> subcomponentsFromModules = ImmutableSet.builder();
- for (ModuleDescriptor module : transitiveModules) {
- for (SubcomponentDeclaration subcomponentDeclaration : module.subcomponentDeclarations()) {
- TypeElement subcomponent = subcomponentDeclaration.subcomponentType();
- subcomponentsFromModules.add(subcomponentDescriptor(subcomponent));
- }
- }
-
- ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
- ImmutableSet.builder();
- ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor>
- subcomponentsByFactoryMethod = ImmutableBiMap.builder();
- ImmutableBiMap.Builder<ComponentMethodDescriptor, ComponentDescriptor>
- subcomponentsByBuilderMethod = ImmutableBiMap.builder();
- if (componentAnnotation.isRealComponent()) {
- ImmutableSet<ExecutableElement> unimplementedMethods =
- elements.getUnimplementedMethods(typeElement);
- for (ExecutableElement componentMethod : unimplementedMethods) {
- ComponentMethodDescriptor componentMethodDescriptor =
- getDescriptorForComponentMethod(typeElement, componentAnnotation, componentMethod);
- componentMethodsBuilder.add(componentMethodDescriptor);
- componentMethodDescriptor
- .subcomponent()
- .ifPresent(
- subcomponent -> {
- // If the dependency request is present, that means the method returns the
- // subcomponent factory.
- if (componentMethodDescriptor.dependencyRequest().isPresent()) {
- subcomponentsByBuilderMethod.put(componentMethodDescriptor, subcomponent);
- } else {
- subcomponentsByFactoryMethod.put(componentMethodDescriptor, subcomponent);
- }
- });
- }
- }
-
- // Validation should have ensured that this set will have at most one element.
- ImmutableSet<DeclaredType> enclosedCreators =
- creatorAnnotationsFor(componentAnnotation).stream()
- .flatMap(
- creatorAnnotation ->
- enclosedAnnotatedTypes(typeElement, creatorAnnotation).stream())
- .collect(toImmutableSet());
- Optional<ComponentCreatorDescriptor> creatorDescriptor =
- enclosedCreators.isEmpty()
- ? Optional.empty()
- : Optional.of(
- ComponentCreatorDescriptor.create(
- getOnlyElement(enclosedCreators), elements, types, dependencyRequestFactory));
-
- ImmutableSet<Scope> scopes = scopesOf(typeElement);
- if (componentAnnotation.isProduction()) {
- scopes = ImmutableSet.<Scope>builder().addAll(scopes).add(productionScope(elements)).build();
- }
-
- return new AutoValue_ComponentDescriptor(
- componentAnnotation,
- typeElement,
- componentDependencies,
- transitiveModules,
- dependenciesByDependencyMethod.build(),
- scopes,
- subcomponentsFromModules.build(),
- subcomponentsByFactoryMethod.build(),
- subcomponentsByBuilderMethod.build(),
- componentMethodsBuilder.build(),
- creatorDescriptor);
- }
-
- private ComponentMethodDescriptor getDescriptorForComponentMethod(
- TypeElement componentElement,
- ComponentAnnotation componentAnnotation,
- ExecutableElement componentMethod) {
- ComponentMethodDescriptor.Builder descriptor =
- ComponentMethodDescriptor.builder(componentMethod);
-
- ExecutableType resolvedComponentMethod =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(componentElement.asType()), componentMethod));
- TypeMirror returnType = resolvedComponentMethod.getReturnType();
- if (returnType.getKind().equals(DECLARED)
- && !injectionAnnotations.getQualifier(componentMethod).isPresent()) {
- TypeElement returnTypeElement = asTypeElement(returnType);
- if (subcomponentAnnotation(returnTypeElement).isPresent()) {
- // It's a subcomponent factory method. There is no dependency request, and there could be
- // any number of parameters. Just return the descriptor.
- return descriptor.subcomponent(subcomponentDescriptor(returnTypeElement)).build();
- }
- if (isSubcomponentCreator(returnTypeElement)) {
- descriptor.subcomponent(
- subcomponentDescriptor(asType(returnTypeElement.getEnclosingElement())));
- }
- }
-
- switch (componentMethod.getParameters().size()) {
- case 0:
- checkArgument(
- !returnType.getKind().equals(VOID),
- "component method cannot be void: %s",
- componentMethod);
- descriptor.dependencyRequest(
- componentAnnotation.isProduction()
- ? dependencyRequestFactory.forComponentProductionMethod(
- componentMethod, resolvedComponentMethod)
- : dependencyRequestFactory.forComponentProvisionMethod(
- componentMethod, resolvedComponentMethod));
- break;
-
- case 1:
- checkArgument(
- returnType.getKind().equals(VOID)
- || MoreTypes.equivalence()
- .equivalent(returnType, resolvedComponentMethod.getParameterTypes().get(0)),
- "members injection method must return void or parameter type: %s",
- componentMethod);
- descriptor.dependencyRequest(
- dependencyRequestFactory.forComponentMembersInjectionMethod(
- componentMethod, resolvedComponentMethod));
- break;
-
- default:
- throw new IllegalArgumentException(
- "component method has too many parameters: " + componentMethod);
- }
-
- return descriptor.build();
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentKind.java b/java/dagger/internal/codegen/binding/ComponentKind.java
deleted file mode 100644
index 1cb3d7c..0000000
--- a/java/dagger/internal/codegen/binding/ComponentKind.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.collect.Sets.immutableEnumSet;
-import static dagger.internal.codegen.extension.DaggerStreams.stream;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.DaggerStreams.valuesOf;
-import static java.util.EnumSet.allOf;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Component;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.Optional;
-import javax.lang.model.element.TypeElement;
-
-/** Enumeration of the different kinds of components. */
-public enum ComponentKind {
- /** {@code @Component} */
- COMPONENT(Component.class, true, false),
-
- /** {@code @Subcomponent} */
- SUBCOMPONENT(Subcomponent.class, false, false),
-
- /** {@code @ProductionComponent} */
- PRODUCTION_COMPONENT(ProductionComponent.class, true, true),
-
- /** {@code @ProductionSubcomponent} */
- PRODUCTION_SUBCOMPONENT(ProductionSubcomponent.class, false, true),
-
- /**
- * Kind for a descriptor that was generated from a {@link Module} instead of a component type in
- * order to validate the module's bindings.
- */
- MODULE(Module.class, true, false),
-
- /**
- * Kind for a descriptor was generated from a {@link ProducerModule} instead of a component type
- * in order to validate the module's bindings.
- */
- PRODUCER_MODULE(ProducerModule.class, true, true),
- ;
-
- private static final ImmutableSet<ComponentKind> ROOT_COMPONENT_KINDS =
- valuesOf(ComponentKind.class)
- .filter(kind -> !kind.isForModuleValidation())
- .filter(kind -> kind.isRoot())
- .collect(toImmutableSet());
-
- private static final ImmutableSet<ComponentKind> SUBCOMPONENT_KINDS =
- valuesOf(ComponentKind.class)
- .filter(kind -> !kind.isForModuleValidation())
- .filter(kind -> !kind.isRoot())
- .collect(toImmutableSet());
-
- /** Returns the set of kinds for root components. */
- public static ImmutableSet<ComponentKind> rootComponentKinds() {
- return ROOT_COMPONENT_KINDS;
- }
-
- /** Returns the set of kinds for subcomponents. */
- public static ImmutableSet<ComponentKind> subcomponentKinds() {
- return SUBCOMPONENT_KINDS;
- }
-
- /** Returns the annotations for components of the given kinds. */
- public static ImmutableSet<Class<? extends Annotation>> annotationsFor(
- Iterable<ComponentKind> kinds) {
- return stream(kinds).map(ComponentKind::annotation).collect(toImmutableSet());
- }
-
- /** Returns the set of component kinds the given {@code element} has annotations for. */
- public static ImmutableSet<ComponentKind> getComponentKinds(TypeElement element) {
- return valuesOf(ComponentKind.class)
- .filter(kind -> isAnnotationPresent(element, kind.annotation()))
- .collect(toImmutableSet());
- }
-
- /**
- * Returns the kind of an annotated element if it is annotated with one of the {@linkplain
- * #annotation() annotations}.
- *
- * @throws IllegalArgumentException if the element is annotated with more than one of the
- * annotations
- */
- public static Optional<ComponentKind> forAnnotatedElement(TypeElement element) {
- ImmutableSet<ComponentKind> kinds = getComponentKinds(element);
- if (kinds.size() > 1) {
- throw new IllegalArgumentException(
- element + " cannot be annotated with more than one of " + annotationsFor(kinds));
- }
- return kinds.stream().findAny();
- }
-
- private final Class<? extends Annotation> annotation;
- private final boolean isRoot;
- private final boolean production;
-
- ComponentKind(
- Class<? extends Annotation> annotation,
- boolean isRoot,
- boolean production) {
- this.annotation = annotation;
- this.isRoot = isRoot;
- this.production = production;
- }
-
- /** Returns the annotation that marks a component of this kind. */
- public Class<? extends Annotation> annotation() {
- return annotation;
- }
-
- /** Returns the kinds of modules that can be used with a component of this kind. */
- public ImmutableSet<ModuleKind> legalModuleKinds() {
- return isProducer()
- ? immutableEnumSet(allOf(ModuleKind.class))
- : immutableEnumSet(ModuleKind.MODULE);
- }
-
- /** Returns the kinds of subcomponents a component of this kind can have. */
- public ImmutableSet<ComponentKind> legalSubcomponentKinds() {
- return isProducer()
- ? immutableEnumSet(PRODUCTION_SUBCOMPONENT)
- : immutableEnumSet(SUBCOMPONENT, PRODUCTION_SUBCOMPONENT);
- }
-
- /**
- * Returns {@code true} if the descriptor is for a root component (not a subcomponent) or is for
- * {@linkplain #isForModuleValidation() module-validation}.
- */
- public boolean isRoot() {
- return isRoot;
- }
-
- /** Returns true if this is a production component. */
- public boolean isProducer() {
- return production;
- }
-
- /** Returns {@code true} if the descriptor is for a module in order to validate its bindings. */
- public boolean isForModuleValidation() {
- switch (this) {
- case MODULE:
- case PRODUCER_MODULE:
- return true;
- default:
- // fall through
- }
- return false;
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentNodeImpl.java b/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
deleted file mode 100644
index 0947c25..0000000
--- a/java/dagger/internal/codegen/binding/ComponentNodeImpl.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 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 dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.ComponentPath;
-import dagger.model.DependencyRequest;
-import dagger.model.Scope;
-
-/** An implementation of {@link ComponentNode} that also exposes the {@link ComponentDescriptor}. */
-@AutoValue
-public abstract class ComponentNodeImpl implements ComponentNode {
- public static ComponentNode create(
- ComponentPath componentPath, ComponentDescriptor componentDescriptor) {
- return new AutoValue_ComponentNodeImpl(componentPath, componentDescriptor);
- }
-
- @Override
- public final boolean isSubcomponent() {
- return componentDescriptor().isSubcomponent();
- }
-
- @Override
- public boolean isRealComponent() {
- return componentDescriptor().isRealComponent();
- }
-
- @Override
- public final ImmutableSet<DependencyRequest> entryPoints() {
- return componentDescriptor().entryPointMethods().stream()
- .map(method -> method.dependencyRequest().get())
- .collect(toImmutableSet());
- }
-
- @Override
- public ImmutableSet<Scope> scopes() {
- return componentDescriptor().scopes();
- }
-
- public abstract ComponentDescriptor componentDescriptor();
-
- @Override
- public final String toString() {
- return componentPath().toString();
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ComponentRequirement.java b/java/dagger/internal/codegen/binding/ComponentRequirement.java
deleted file mode 100644
index fa24b56..0000000
--- a/java/dagger/internal/codegen/binding/ComponentRequirement.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static javax.lang.model.element.ElementKind.CONSTRUCTOR;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.Binds;
-import dagger.BindsOptionalOf;
-import dagger.Provides;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.Key;
-import dagger.multibindings.Multibinds;
-import dagger.producers.Produces;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A type that a component needs an instance of. */
-@AutoValue
-public abstract class ComponentRequirement {
- /** The kind of the {@link ComponentRequirement}. */
- public enum Kind {
- /** A type listed in the component's {@code dependencies} attribute. */
- DEPENDENCY,
-
- /** A type listed in the component or subcomponent's {@code modules} attribute. */
- MODULE,
-
- /**
- * An object that is passed to a builder's {@link dagger.BindsInstance @BindsInstance} method.
- */
- BOUND_INSTANCE,
- ;
-
- public boolean isBoundInstance() {
- return equals(BOUND_INSTANCE);
- }
-
- public boolean isModule() {
- return equals(MODULE);
- }
- }
-
- /** The kind of requirement. */
- public abstract Kind kind();
-
- /** Returns true if this is a {@link Kind#BOUND_INSTANCE} requirement. */
- // TODO(ronshapiro): consider removing this and inlining the usages
- final boolean isBoundInstance() {
- return kind().isBoundInstance();
- }
-
- /**
- * The type of the instance the component must have, wrapped so that requirements can be used as
- * value types.
- */
- public abstract Equivalence.Wrapper<TypeMirror> wrappedType();
-
- /** The type of the instance the component must have. */
- public TypeMirror type() {
- return wrappedType().get();
- }
-
- /** The element associated with the type of this requirement. */
- public TypeElement typeElement() {
- return MoreTypes.asTypeElement(type());
- }
-
- /** The action a component builder should take if it {@code null} is passed. */
- public enum NullPolicy {
- /** Make a new instance. */
- NEW,
- /** Throw an exception. */
- THROW,
- /** Allow use of null values. */
- ALLOW,
- }
-
- /**
- * An override for the requirement's null policy. If set, this is used as the null policy instead
- * of the default behavior in {@link #nullPolicy}.
- *
- * <p>Some implementations' null policy can be determined upon construction (e.g., for binding
- * instances), but others' require Elements and Types, which must wait until {@link #nullPolicy}
- * is called.
- */
- abstract Optional<NullPolicy> overrideNullPolicy();
-
- /** The requirement's null policy. */
- public NullPolicy nullPolicy(
- DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) {
- if (overrideNullPolicy().isPresent()) {
- return overrideNullPolicy().get();
- }
- switch (kind()) {
- case MODULE:
- return componentCanMakeNewInstances(typeElement(), metadataUtil)
- ? NullPolicy.NEW
- : requiresAPassedInstance(elements, types, metadataUtil)
- ? NullPolicy.THROW
- : NullPolicy.ALLOW;
- case DEPENDENCY:
- case BOUND_INSTANCE:
- return NullPolicy.THROW;
- }
- throw new AssertionError();
- }
-
- /**
- * Returns true if the passed {@link ComponentRequirement} requires a passed instance in order to
- * be used within a component.
- */
- public boolean requiresAPassedInstance(
- DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) {
- if (!kind().isModule()) {
- // Bound instances and dependencies always require the user to provide an instance.
- return true;
- }
- return requiresModuleInstance(elements, types, metadataUtil)
- && !componentCanMakeNewInstances(typeElement(), metadataUtil);
- }
-
- /**
- * Returns {@code true} if an instance is needed for this (module) requirement.
- *
- * <p>An instance is only needed if there is a binding method on the module that is neither {@code
- * abstract} nor {@code static}; if all bindings are one of those, then there should be no
- * possible dependency on instance state in the module's bindings.
- *
- * <p>Alternatively, if the module is a Kotlin Object then the binding methods are considered
- * {@code static}, requiring no module instance.
- */
- private boolean requiresModuleInstance(
- DaggerElements elements, DaggerTypes types, KotlinMetadataUtil metadataUtil) {
- boolean isKotlinObject =
- metadataUtil.isObjectClass(typeElement())
- || metadataUtil.isCompanionObjectClass(typeElement());
- if (isKotlinObject) {
- return false;
- }
-
- ImmutableSet<ExecutableElement> methods =
- getLocalAndInheritedMethods(typeElement(), types, elements);
- return methods.stream()
- .filter(this::isBindingMethod)
- .map(ExecutableElement::getModifiers)
- .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC));
- }
-
- private boolean isBindingMethod(ExecutableElement method) {
- // TODO(cgdecker): At the very least, we should have utility methods to consolidate this stuff
- // in one place; listing individual annotations all over the place is brittle.
- return isAnyAnnotationPresent(
- method,
- Provides.class,
- Produces.class,
- // TODO(ronshapiro): it would be cool to have internal meta-annotations that could describe
- // these, like @AbstractBindingMethod
- Binds.class,
- Multibinds.class,
- BindsOptionalOf.class);
- }
-
- /** The key for this requirement, if one is available. */
- public abstract Optional<Key> key();
-
- /** Returns the name for this requirement that could be used as a variable. */
- public abstract String variableName();
-
- /** Returns a parameter spec for this requirement. */
- public ParameterSpec toParameterSpec() {
- return ParameterSpec.builder(TypeName.get(type()), variableName()).build();
- }
-
- public static ComponentRequirement forDependency(TypeMirror type) {
- return new AutoValue_ComponentRequirement(
- Kind.DEPENDENCY,
- MoreTypes.equivalence().wrap(checkNotNull(type)),
- Optional.empty(),
- Optional.empty(),
- simpleVariableName(MoreTypes.asTypeElement(type)));
- }
-
- public static ComponentRequirement forModule(TypeMirror type) {
- return new AutoValue_ComponentRequirement(
- Kind.MODULE,
- MoreTypes.equivalence().wrap(checkNotNull(type)),
- Optional.empty(),
- Optional.empty(),
- simpleVariableName(MoreTypes.asTypeElement(type)));
- }
-
- static ComponentRequirement forBoundInstance(Key key, boolean nullable, String variableName) {
- return new AutoValue_ComponentRequirement(
- Kind.BOUND_INSTANCE,
- MoreTypes.equivalence().wrap(key.type()),
- nullable ? Optional.of(NullPolicy.ALLOW) : Optional.empty(),
- Optional.of(key),
- variableName);
- }
-
- public static ComponentRequirement forBoundInstance(ContributionBinding binding) {
- checkArgument(binding.kind().equals(BindingKind.BOUND_INSTANCE));
- return forBoundInstance(
- binding.key(),
- binding.nullableType().isPresent(),
- binding.bindingElement().get().getSimpleName().toString());
- }
-
- /**
- * Returns true if and only if a component can instantiate new instances (typically of a module)
- * rather than requiring that they be passed.
- */
- // TODO(bcorso): Should this method throw if its called knowing that an instance is not needed?
- public static boolean componentCanMakeNewInstances(
- TypeElement typeElement, KotlinMetadataUtil metadataUtil) {
- switch (typeElement.getKind()) {
- case CLASS:
- break;
- case ENUM:
- case ANNOTATION_TYPE:
- case INTERFACE:
- return false;
- default:
- throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind());
- }
-
- if (typeElement.getModifiers().contains(ABSTRACT)) {
- return false;
- }
-
- if (requiresEnclosingInstance(typeElement)) {
- return false;
- }
-
- if (metadataUtil.isObjectClass(typeElement)
- || metadataUtil.isCompanionObjectClass(typeElement)) {
- return false;
- }
-
- for (Element enclosed : typeElement.getEnclosedElements()) {
- if (enclosed.getKind().equals(CONSTRUCTOR)
- && MoreElements.asExecutable(enclosed).getParameters().isEmpty()
- && !enclosed.getModifiers().contains(PRIVATE)) {
- return true;
- }
- }
-
- // TODO(gak): still need checks for visibility
-
- return false;
- }
-
- private static boolean requiresEnclosingInstance(TypeElement typeElement) {
- switch (typeElement.getNestingKind()) {
- case TOP_LEVEL:
- return false;
- case MEMBER:
- return !typeElement.getModifiers().contains(STATIC);
- case ANONYMOUS:
- case LOCAL:
- return true;
- }
- throw new AssertionError(
- "TypeElement cannot have nesting kind: " + typeElement.getNestingKind());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java b/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
deleted file mode 100644
index 539a66a..0000000
--- a/java/dagger/internal/codegen/binding/ConfigurationAnnotations.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.consumingIterable;
-import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.base.MoreAnnotationMirrors.getTypeListValue;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static javax.lang.model.util.ElementFilter.typesIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-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 dagger.Component;
-import dagger.Module;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.lang.annotation.Annotation;
-import java.util.ArrayDeque;
-import java.util.List;
-import java.util.Optional;
-import java.util.Queue;
-import java.util.Set;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Utility methods related to dagger configuration annotations (e.g.: {@link Component} and {@link
- * Module}).
- */
-public final class ConfigurationAnnotations {
-
- public static Optional<TypeElement> getSubcomponentCreator(TypeElement subcomponent) {
- checkArgument(subcomponentAnnotation(subcomponent).isPresent());
- for (TypeElement nestedType : typesIn(subcomponent.getEnclosedElements())) {
- if (isSubcomponentCreator(nestedType)) {
- return Optional.of(nestedType);
- }
- }
- return Optional.empty();
- }
-
- static boolean isSubcomponentCreator(Element element) {
- return isAnyAnnotationPresent(element, subcomponentCreatorAnnotations());
- }
-
- // Dagger 1 support.
- public static ImmutableList<TypeMirror> getModuleInjects(AnnotationMirror moduleAnnotation) {
- checkNotNull(moduleAnnotation);
- return getTypeListValue(moduleAnnotation, "injects");
- }
-
- /** Returns the first type that specifies this' nullability, or empty if none. */
- public static Optional<DeclaredType> getNullableType(Element element) {
- List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
- for (AnnotationMirror mirror : mirrors) {
- if (mirror.getAnnotationType().asElement().getSimpleName().contentEquals("Nullable")) {
- return Optional.of(mirror.getAnnotationType());
- }
- }
- return Optional.empty();
- }
-
- /**
- * Returns the full set of modules transitively {@linkplain Module#includes included} from the
- * given seed modules. If a module is malformed and a type listed in {@link Module#includes} is
- * not annotated with {@link Module}, it is ignored.
- *
- * @deprecated Use {@link ComponentDescriptor#modules()}.
- */
- @Deprecated
- public static ImmutableSet<TypeElement> getTransitiveModules(
- DaggerTypes types, DaggerElements elements, Iterable<TypeElement> seedModules) {
- TypeMirror objectType = elements.getTypeElement(Object.class).asType();
- Queue<TypeElement> moduleQueue = new ArrayDeque<>();
- Iterables.addAll(moduleQueue, seedModules);
- Set<TypeElement> moduleElements = Sets.newLinkedHashSet();
- for (TypeElement moduleElement : consumingIterable(moduleQueue)) {
- moduleAnnotation(moduleElement)
- .ifPresent(
- moduleAnnotation -> {
- ImmutableSet.Builder<TypeElement> moduleDependenciesBuilder =
- ImmutableSet.builder();
- moduleDependenciesBuilder.addAll(moduleAnnotation.includes());
- // We don't recur on the parent class because we don't want the parent class as a
- // root that the component depends on, and also because we want the dependencies
- // rooted against this element, not the parent.
- addIncludesFromSuperclasses(
- types, moduleElement, moduleDependenciesBuilder, objectType);
- ImmutableSet<TypeElement> moduleDependencies = moduleDependenciesBuilder.build();
- moduleElements.add(moduleElement);
- for (TypeElement dependencyType : moduleDependencies) {
- if (!moduleElements.contains(dependencyType)) {
- moduleQueue.add(dependencyType);
- }
- }
- });
- }
- return ImmutableSet.copyOf(moduleElements);
- }
-
- /** Returns the enclosed types annotated with the given annotation. */
- public static ImmutableList<DeclaredType> enclosedAnnotatedTypes(
- TypeElement typeElement, Class<? extends Annotation> annotation) {
- final ImmutableList.Builder<DeclaredType> builders = ImmutableList.builder();
- for (TypeElement element : typesIn(typeElement.getEnclosedElements())) {
- if (MoreElements.isAnnotationPresent(element, annotation)) {
- builders.add(MoreTypes.asDeclared(element.asType()));
- }
- }
- return builders.build();
- }
-
- /** Traverses includes from superclasses and adds them into the builder. */
- private static void addIncludesFromSuperclasses(
- DaggerTypes types,
- TypeElement element,
- ImmutableSet.Builder<TypeElement> builder,
- TypeMirror objectType) {
- // Also add the superclass to the queue, in case any @Module definitions were on that.
- TypeMirror superclass = element.getSuperclass();
- while (!types.isSameType(objectType, superclass)
- && superclass.getKind().equals(TypeKind.DECLARED)) {
- element = MoreElements.asType(types.asElement(superclass));
- moduleAnnotation(element)
- .ifPresent(moduleAnnotation -> builder.addAll(moduleAnnotation.includes()));
- superclass = element.getSuperclass();
- }
- }
-
- private ConfigurationAnnotations() {}
-}
diff --git a/java/dagger/internal/codegen/binding/ContributionBinding.java b/java/dagger/internal/codegen/binding/ContributionBinding.java
deleted file mode 100644
index 1942e8c..0000000
--- a/java/dagger/internal/codegen/binding/ContributionBinding.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.base.MoreAnnotationMirrors.unwrapOptionalEquivalence;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.CLASS_CONSTRUCTOR;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.DELEGATE;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
-import static java.util.Arrays.asList;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Preconditions;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.ContributionType.HasContributionType;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.SetType;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import java.util.Optional;
-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.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * An abstract class for a value object representing the mechanism by which a {@link Key} can be
- * contributed to a dependency graph.
- */
-public abstract class ContributionBinding extends Binding implements HasContributionType {
-
- /** Returns the type that specifies this' nullability, absent if not nullable. */
- public abstract Optional<DeclaredType> nullableType();
-
- public abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation();
-
- public final Optional<AnnotationMirror> mapKeyAnnotation() {
- return unwrapOptionalEquivalence(wrappedMapKeyAnnotation());
- }
-
- /** If {@link #bindingElement()} is a method that returns a primitive type, returns that type. */
- public final Optional<TypeMirror> contributedPrimitiveType() {
- return bindingElement()
- .filter(bindingElement -> bindingElement instanceof ExecutableElement)
- .map(bindingElement -> MoreElements.asExecutable(bindingElement).getReturnType())
- .filter(type -> type.getKind().isPrimitive());
- }
-
- @Override
- public boolean requiresModuleInstance() {
- return !isContributingModuleKotlinObject().orElse(false) && super.requiresModuleInstance();
- }
-
- @Override
- public final boolean isNullable() {
- return nullableType().isPresent();
- }
-
- /**
- * Returns {@code true} if the contributing module is a Kotlin object. Note that a companion
- * object is also considered a Kotlin object.
- */
- abstract Optional<Boolean> isContributingModuleKotlinObject();
-
- /** The strategy for getting an instance of a factory for a {@link ContributionBinding}. */
- public enum FactoryCreationStrategy {
- /** The factory class is a single instance. */
- SINGLETON_INSTANCE,
- /** The factory must be created by calling the constructor. */
- CLASS_CONSTRUCTOR,
- /** The factory is simply delegated to another. */
- DELEGATE,
- }
-
- /**
- * Returns the {@link FactoryCreationStrategy} appropriate for a binding.
- *
- * <p>Delegate bindings use the {@link FactoryCreationStrategy#DELEGATE} strategy.
- *
- * <p>Bindings without dependencies that don't require a module instance use the {@link
- * FactoryCreationStrategy#SINGLETON_INSTANCE} strategy.
- *
- * <p>All other bindings use the {@link FactoryCreationStrategy#CLASS_CONSTRUCTOR} strategy.
- */
- public final FactoryCreationStrategy factoryCreationStrategy() {
- switch (kind()) {
- case DELEGATE:
- return DELEGATE;
- case PROVISION:
- return dependencies().isEmpty() && !requiresModuleInstance()
- ? SINGLETON_INSTANCE
- : CLASS_CONSTRUCTOR;
- case INJECTION:
- case MULTIBOUND_SET:
- case MULTIBOUND_MAP:
- return dependencies().isEmpty() ? SINGLETON_INSTANCE : CLASS_CONSTRUCTOR;
- default:
- return CLASS_CONSTRUCTOR;
- }
- }
-
- /**
- * The {@link TypeMirror type} for the {@code Factory<T>} or {@code Producer<T>} which is created
- * for this binding. Uses the binding's key, V in the case of {@code Map<K, FrameworkClass<V>>>},
- * and E {@code Set<E>} for {@link dagger.multibindings.IntoSet @IntoSet} methods.
- */
- public final TypeMirror contributedType() {
- switch (contributionType()) {
- case MAP:
- return MapType.from(key()).unwrappedFrameworkValueType();
- case SET:
- return SetType.from(key()).elementType();
- case SET_VALUES:
- case UNIQUE:
- return key().type();
- }
- throw new AssertionError();
- }
-
- /**
- * Returns {@link BindingKind#MULTIBOUND_SET} or {@link
- * BindingKind#MULTIBOUND_MAP} if the key is a set or map.
- *
- * @throws IllegalArgumentException if {@code key} is neither a set nor a map
- */
- static BindingKind bindingKindForMultibindingKey(Key key) {
- if (SetType.isSet(key)) {
- return BindingKind.MULTIBOUND_SET;
- } else if (MapType.isMap(key)) {
- return BindingKind.MULTIBOUND_MAP;
- } else {
- throw new IllegalArgumentException(String.format("key is not for a set or map: %s", key));
- }
- }
-
- public abstract Builder<?, ?> toBuilder();
-
- /**
- * Base builder for {@link com.google.auto.value.AutoValue @AutoValue} subclasses of {@link
- * ContributionBinding}.
- */
- @CanIgnoreReturnValue
- public abstract static class Builder<C extends ContributionBinding, B extends Builder<C, B>> {
- public abstract B dependencies(Iterable<DependencyRequest> dependencies);
-
- public B dependencies(DependencyRequest... dependencies) {
- return dependencies(asList(dependencies));
- }
-
- public abstract B unresolved(C unresolved);
-
- public abstract B contributionType(ContributionType contributionType);
-
- public abstract B bindingElement(Element bindingElement);
-
- abstract B bindingElement(Optional<Element> bindingElement);
-
- public final B clearBindingElement() {
- return bindingElement(Optional.empty());
- };
-
- abstract B contributingModule(TypeElement contributingModule);
-
- abstract B isContributingModuleKotlinObject(boolean isModuleKotlinObject);
-
- public abstract B key(Key key);
-
- public abstract B nullableType(Optional<DeclaredType> nullableType);
-
- abstract B wrappedMapKeyAnnotation(
- Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKeyAnnotation);
-
- public abstract B kind(BindingKind kind);
-
- @CheckReturnValue
- abstract C autoBuild();
-
- @CheckReturnValue
- public C build() {
- C binding = autoBuild();
- Preconditions.checkState(
- binding.contributingModule().isPresent()
- == binding.isContributingModuleKotlinObject().isPresent(),
- "The contributionModule and isModuleKotlinObject must both be set together.");
- return binding;
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/DelegateDeclaration.java b/java/dagger/internal/codegen/binding/DelegateDeclaration.java
deleted file mode 100644
index b6c3c38..0000000
--- a/java/dagger/internal/codegen/binding/DelegateDeclaration.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.base.MoreAnnotationMirrors.wrapOptionalInEquivalence;
-import static dagger.internal.codegen.binding.MapKeys.getMapKey;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.Iterables;
-import dagger.Binds;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.ContributionType.HasContributionType;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-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.type.ExecutableType;
-
-/** The declaration for a delegate binding established by a {@link Binds} method. */
-@AutoValue
-public abstract class DelegateDeclaration extends BindingDeclaration
- implements HasContributionType {
- abstract DependencyRequest delegateRequest();
-
- abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedMapKey();
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object obj);
-
- /** A {@link DelegateDeclaration} factory. */
- public static final class Factory {
- private final DaggerTypes types;
- private final KeyFactory keyFactory;
- private final DependencyRequestFactory dependencyRequestFactory;
-
- @Inject
- Factory(
- DaggerTypes types,
- KeyFactory keyFactory,
- DependencyRequestFactory dependencyRequestFactory) {
- this.types = types;
- this.keyFactory = keyFactory;
- this.dependencyRequestFactory = dependencyRequestFactory;
- }
-
- public DelegateDeclaration create(
- ExecutableElement bindsMethod, TypeElement contributingModule) {
- checkArgument(MoreElements.isAnnotationPresent(bindsMethod, Binds.class));
- ExecutableType resolvedMethod =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), bindsMethod));
- DependencyRequest delegateRequest =
- dependencyRequestFactory.forRequiredResolvedVariable(
- Iterables.getOnlyElement(bindsMethod.getParameters()),
- Iterables.getOnlyElement(resolvedMethod.getParameterTypes()));
- return new AutoValue_DelegateDeclaration(
- ContributionType.fromBindingElement(bindsMethod),
- keyFactory.forBindsMethod(bindsMethod, contributingModule),
- Optional.<Element>of(bindsMethod),
- Optional.of(contributingModule),
- delegateRequest,
- wrapOptionalInEquivalence(getMapKey(bindsMethod)));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java b/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
deleted file mode 100644
index f11517e..0000000
--- a/java/dagger/internal/codegen/binding/DependencyEdgeImpl.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 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 dagger.internal.codegen.base.ElementFormatter;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.DependencyRequest;
-
-/** An implementation of {@link DependencyEdge}. */
-final class DependencyEdgeImpl implements DependencyEdge {
-
- private final DependencyRequest dependencyRequest;
- private final boolean entryPoint;
-
- DependencyEdgeImpl(DependencyRequest dependencyRequest, boolean entryPoint) {
- this.dependencyRequest = dependencyRequest;
- this.entryPoint = entryPoint;
- }
-
- @Override
- public DependencyRequest dependencyRequest() {
- return dependencyRequest;
- }
-
- @Override
- public boolean isEntryPoint() {
- return entryPoint;
- }
-
- @Override
- public String toString() {
- String string =
- dependencyRequest
- .requestElement()
- .map(ElementFormatter::elementToString)
- .orElseGet(
- () ->
- "synthetic request for "
- + dependencyRequest.kind().format(dependencyRequest.key()));
- return entryPoint ? string + " (entry point)" : string;
- }
-}
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java b/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
deleted file mode 100644
index 707de4c..0000000
--- a/java/dagger/internal/codegen/binding/DependencyRequestFactory.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreTypes.isTypeOf;
-import static com.google.common.base.Preconditions.checkArgument;
-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.base.RequestKinds.extractKeyType;
-import static dagger.internal.codegen.base.RequestKinds.frameworkClass;
-import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
-import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
-import static dagger.model.RequestKind.FUTURE;
-import static dagger.model.RequestKind.INSTANCE;
-import static dagger.model.RequestKind.MEMBERS_INJECTION;
-import static dagger.model.RequestKind.PRODUCER;
-import static dagger.model.RequestKind.PROVIDER;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.Lazy;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.OptionalType;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import java.util.List;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Factory for {@link DependencyRequest}s.
- *
- * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available, which
- * may mean that the type will be generated in a later round of processing.
- */
-public final class DependencyRequestFactory {
- private final KeyFactory keyFactory;
- private final InjectionAnnotations injectionAnnotations;
-
- @Inject
- DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations) {
- this.keyFactory = keyFactory;
- this.injectionAnnotations = injectionAnnotations;
- }
-
- ImmutableSet<DependencyRequest> forRequiredResolvedVariables(
- List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
- checkState(resolvedTypes.size() == variables.size());
- ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder();
- for (int i = 0; i < variables.size(); i++) {
- builder.add(forRequiredResolvedVariable(variables.get(i), resolvedTypes.get(i)));
- }
- return builder.build();
- }
-
- /**
- * Creates synthetic dependency requests for each individual multibinding contribution in {@code
- * multibindingContributions}.
- */
- ImmutableSet<DependencyRequest> forMultibindingContributions(
- Key multibindingKey, Iterable<ContributionBinding> multibindingContributions) {
- ImmutableSet.Builder<DependencyRequest> requests = ImmutableSet.builder();
- for (ContributionBinding multibindingContribution : multibindingContributions) {
- requests.add(forMultibindingContribution(multibindingKey, multibindingContribution));
- }
- return requests.build();
- }
-
- /** Creates a synthetic dependency request for one individual {@code multibindingContribution}. */
- private DependencyRequest forMultibindingContribution(
- Key multibindingKey, ContributionBinding multibindingContribution) {
- checkArgument(
- multibindingContribution.key().multibindingContributionIdentifier().isPresent(),
- "multibindingContribution's key must have a multibinding contribution identifier: %s",
- multibindingContribution);
- return DependencyRequest.builder()
- .kind(multibindingContributionRequestKind(multibindingKey, multibindingContribution))
- .key(multibindingContribution.key())
- .build();
- }
-
- // TODO(b/28555349): support PROVIDER_OF_LAZY here too
- private static final ImmutableSet<RequestKind> WRAPPING_MAP_VALUE_FRAMEWORK_TYPES =
- ImmutableSet.of(PROVIDER, PRODUCER);
-
- private RequestKind multibindingContributionRequestKind(
- Key multibindingKey, ContributionBinding multibindingContribution) {
- switch (multibindingContribution.contributionType()) {
- case MAP:
- MapType mapType = MapType.from(multibindingKey);
- for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) {
- if (mapType.valuesAreTypeOf(frameworkClass(kind))) {
- return kind;
- }
- }
- // fall through
- case SET:
- case SET_VALUES:
- return INSTANCE;
- case UNIQUE:
- throw new IllegalArgumentException(
- "multibindingContribution must be a multibinding: " + multibindingContribution);
- }
- throw new AssertionError(multibindingContribution.toString());
- }
-
- DependencyRequest forRequiredResolvedVariable(
- VariableElement variableElement, TypeMirror resolvedType) {
- checkNotNull(variableElement);
- checkNotNull(resolvedType);
- // Ban @Assisted parameters, they are not considered dependency requests.
- checkArgument(!AssistedInjectionAnnotations.isAssistedParameter(variableElement));
- Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(variableElement);
- return newDependencyRequest(variableElement, resolvedType, qualifier);
- }
-
- public DependencyRequest forComponentProvisionMethod(
- ExecutableElement provisionMethod, ExecutableType provisionMethodType) {
- checkNotNull(provisionMethod);
- checkNotNull(provisionMethodType);
- checkArgument(
- provisionMethod.getParameters().isEmpty(),
- "Component provision methods must be empty: %s",
- provisionMethod);
- Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(provisionMethod);
- return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier);
- }
-
- public DependencyRequest forComponentProductionMethod(
- ExecutableElement productionMethod, ExecutableType productionMethodType) {
- checkNotNull(productionMethod);
- checkNotNull(productionMethodType);
- checkArgument(
- productionMethod.getParameters().isEmpty(),
- "Component production methods must be empty: %s",
- productionMethod);
- TypeMirror type = productionMethodType.getReturnType();
- Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(productionMethod);
- // Only a component production method can be a request for a ListenableFuture, so we
- // special-case it here.
- if (isTypeOf(ListenableFuture.class, type)) {
- return DependencyRequest.builder()
- .kind(FUTURE)
- .key(keyFactory.forQualifiedType(qualifier, unwrapType(type)))
- .requestElement(productionMethod)
- .build();
- } else {
- return newDependencyRequest(productionMethod, type, qualifier);
- }
- }
-
- DependencyRequest forComponentMembersInjectionMethod(
- ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType) {
- checkNotNull(membersInjectionMethod);
- checkNotNull(membersInjectionMethodType);
- Optional<AnnotationMirror> qualifier =
- injectionAnnotations.getQualifier(membersInjectionMethod);
- checkArgument(!qualifier.isPresent());
- TypeMirror membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes());
- return DependencyRequest.builder()
- .kind(MEMBERS_INJECTION)
- .key(keyFactory.forMembersInjectedType(membersInjectedType))
- .requestElement(membersInjectionMethod)
- .build();
- }
-
- DependencyRequest forProductionImplementationExecutor() {
- return DependencyRequest.builder()
- .kind(PROVIDER)
- .key(keyFactory.forProductionImplementationExecutor())
- .build();
- }
-
- DependencyRequest forProductionComponentMonitor() {
- return DependencyRequest.builder()
- .kind(PROVIDER)
- .key(keyFactory.forProductionComponentMonitor())
- .build();
- }
-
- /**
- * Returns a synthetic request for the present value of an optional binding generated from a
- * {@link dagger.BindsOptionalOf} declaration.
- */
- DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind) {
- Optional<Key> key = keyFactory.unwrapOptional(requestKey);
- checkArgument(key.isPresent(), "not a request for optional: %s", requestKey);
- return DependencyRequest.builder()
- .kind(kind)
- .key(key.get())
- .isNullable(
- allowsNull(getRequestKind(OptionalType.from(requestKey).valueType()), Optional.empty()))
- .build();
- }
-
- private DependencyRequest newDependencyRequest(
- Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier) {
- RequestKind requestKind = getRequestKind(type);
- return DependencyRequest.builder()
- .kind(requestKind)
- .key(keyFactory.forQualifiedType(qualifier, extractKeyType(type)))
- .requestElement(requestElement)
- .isNullable(allowsNull(requestKind, getNullableType(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.
- */
- private boolean allowsNull(RequestKind kind, Optional<DeclaredType> nullableType) {
- return nullableType.isPresent() || !kind.equals(INSTANCE);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java b/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
deleted file mode 100644
index 888dec2..0000000
--- a/java/dagger/internal/codegen/binding/DependencyRequestFormatter.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static dagger.internal.codegen.base.RequestKinds.requestType;
-
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.Provides;
-import dagger.internal.codegen.base.Formatter;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.producers.Produces;
-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.ElementVisitor;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementKindVisitor8;
-
-/**
- * Formats a {@link DependencyRequest} into a {@link String} suitable for an error message listing a
- * chain of dependencies.
- *
- * <dl>
- * <dt>For component provision methods
- * <dd>{@code @Qualifier SomeType is provided at\n ComponentType.method()}
- * <dt>For component injection methods
- * <dd>{@code SomeType is injected at\n ComponentType.method(foo)}
- * <dt>For parameters to {@link Provides @Provides}, {@link Produces @Produces}, or {@link
- * Inject @Inject} methods:
- * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType.method([…, ]param[, …])}
- * <dt>For parameters to {@link Inject @Inject} constructors:
- * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType([…, ]param[, …])}
- * <dt>For {@link Inject @Inject} fields:
- * <dd>{@code @Qualified ResolvedType is injected at\n EnclosingType.field}
- * </dl>
- */
-public final class DependencyRequestFormatter extends Formatter<DependencyRequest> {
-
- private final DaggerTypes types;
-
- @Inject
- DependencyRequestFormatter(DaggerTypes types) {
- this.types = types;
- }
-
- @Override
- public String format(DependencyRequest request) {
- return request
- .requestElement()
- .map(element -> element.accept(formatVisitor, request))
- .orElse("");
- }
-
- /**
- * Appends a newline and the formatted dependency request unless {@link
- * #format(DependencyRequest)} returns the empty string.
- */
- @CanIgnoreReturnValue
- public StringBuilder appendFormatLine(
- StringBuilder builder, DependencyRequest dependencyRequest) {
- String formatted = format(dependencyRequest);
- if (!formatted.isEmpty()) {
- builder.append('\n').append(formatted);
- }
- return builder;
- }
-
- private final ElementVisitor<String, DependencyRequest> formatVisitor =
- new ElementKindVisitor8<String, DependencyRequest>() {
-
- @Override
- public String visitExecutableAsMethod(ExecutableElement method, DependencyRequest request) {
- return INDENT
- + request.key()
- + " is "
- + componentMethodRequestVerb(request)
- + " at\n"
- + DOUBLE_INDENT
- + elementToString(method);
- }
-
- @Override
- public String visitVariable(VariableElement variable, DependencyRequest request) {
- TypeMirror requestedType = requestType(request.kind(), request.key().type(), types);
- return INDENT
- + formatQualifier(request.key().qualifier())
- + requestedType
- + " is injected at\n"
- + DOUBLE_INDENT
- + elementToString(variable);
- }
-
- @Override
- public String visitType(TypeElement e, DependencyRequest request) {
- return ""; // types by themselves provide no useful information.
- }
-
- @Override
- protected String defaultAction(Element element, DependencyRequest request) {
- throw new IllegalStateException(
- "Invalid request " + element.getKind() + " element " + element);
- }
- };
-
- private String formatQualifier(Optional<AnnotationMirror> maybeQualifier) {
- return maybeQualifier.map(qualifier -> qualifier + " ").orElse("");
- }
-
- /**
- * Returns the verb for a component method dependency request. Returns "produced", "provided", or
- * "injected", depending on the kind of request.
- */
- private String componentMethodRequestVerb(DependencyRequest request) {
- switch (request.kind()) {
- case FUTURE:
- case PRODUCER:
- case INSTANCE:
- case LAZY:
- case PROVIDER:
- case PROVIDER_OF_LAZY:
- return "requested";
-
- case MEMBERS_INJECTION:
- return "injected";
-
- case PRODUCED:
- break;
- }
- throw new AssertionError("illegal request kind for method: " + request);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/DependencyVariableNamer.java b/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
deleted file mode 100644
index e01d22e..0000000
--- a/java/dagger/internal/codegen/binding/DependencyVariableNamer.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Ascii;
-import com.google.common.base.CaseFormat;
-import dagger.Lazy;
-import dagger.model.DependencyRequest;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.inject.Provider;
-
-/**
- * Picks a reasonable name for what we think is being provided from the variable name associated
- * with the {@link DependencyRequest}. I.e. strips out words like "lazy" and "provider" if we
- * believe that those refer to {@link Lazy} and {@link Provider} rather than the type being
- * provided.
- */
-//TODO(gak): develop the heuristics to get better names
-final class DependencyVariableNamer {
- private static final Pattern LAZY_PROVIDER_PATTERN = Pattern.compile("lazy(\\w+)Provider");
-
- static String name(DependencyRequest dependency) {
- if (!dependency.requestElement().isPresent()) {
- return simpleVariableName(MoreTypes.asTypeElement(dependency.key().type()));
- }
-
- String variableName = dependency.requestElement().get().getSimpleName().toString();
- if (Ascii.isUpperCase(variableName.charAt(0))) {
- variableName = toLowerCamel(variableName);
- }
- switch (dependency.kind()) {
- case INSTANCE:
- return variableName;
- case LAZY:
- return variableName.startsWith("lazy") && !variableName.equals("lazy")
- ? toLowerCamel(variableName.substring(4))
- : variableName;
- case PROVIDER_OF_LAZY:
- Matcher matcher = LAZY_PROVIDER_PATTERN.matcher(variableName);
- if (matcher.matches()) {
- return toLowerCamel(matcher.group(1));
- }
- // fall through
- case PROVIDER:
- return variableName.endsWith("Provider") && !variableName.equals("Provider")
- ? variableName.substring(0, variableName.length() - 8)
- : variableName;
- case PRODUCED:
- return variableName.startsWith("produced") && !variableName.equals("produced")
- ? toLowerCamel(variableName.substring(8))
- : variableName;
- case PRODUCER:
- return variableName.endsWith("Producer") && !variableName.equals("Producer")
- ? variableName.substring(0, variableName.length() - 8)
- : variableName;
- default:
- throw new AssertionError();
- }
- }
-
- private static String toLowerCamel(String name) {
- return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ErrorMessages.java b/java/dagger/internal/codegen/binding/ErrorMessages.java
deleted file mode 100644
index 8962ade..0000000
--- a/java/dagger/internal/codegen/binding/ErrorMessages.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2014 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import dagger.internal.codegen.base.ComponentAnnotation;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.function.UnaryOperator;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** The collection of error messages to be reported back to users. */
-public final class ErrorMessages {
-
- private static final UnaryOperator<String> PRODUCTION =
- s ->
- s.replace("component", "production component")
- .replace("Component", "ProductionComponent");
-
- private static final UnaryOperator<String> SUBCOMPONENT =
- s -> s.replace("component", "subcomponent").replace("Component", "Subcomponent");
-
- private static final UnaryOperator<String> FACTORY = s -> s.replace("Builder", "Factory");
-
- private static final ImmutableMap<ComponentKind, Function<String, String>>
- COMPONENT_TRANSFORMATIONS =
- ImmutableMap.of(
- ComponentKind.COMPONENT, UnaryOperator.identity(),
- ComponentKind.SUBCOMPONENT, SUBCOMPONENT,
- ComponentKind.PRODUCTION_COMPONENT, PRODUCTION,
- ComponentKind.PRODUCTION_SUBCOMPONENT, PRODUCTION.andThen(SUBCOMPONENT));
-
- public static ComponentMessages componentMessagesFor(ComponentKind componentKind) {
- return new ComponentMessages(COMPONENT_TRANSFORMATIONS.get(componentKind));
- }
-
- public static ComponentMessages componentMessagesFor(ComponentAnnotation componentAnnotation) {
- return new ComponentMessages(
- transformation(componentAnnotation.isProduction(), componentAnnotation.isSubcomponent()));
- }
-
- public static ComponentCreatorMessages creatorMessagesFor(
- ComponentCreatorAnnotation creatorAnnotation) {
- Function<String, String> transformation =
- transformation(
- creatorAnnotation.isProductionCreatorAnnotation(),
- creatorAnnotation.isSubcomponentCreatorAnnotation());
- switch (creatorAnnotation.creatorKind()) {
- case BUILDER:
- return new BuilderMessages(transformation);
- case FACTORY:
- return new FactoryMessages(transformation);
- }
- throw new AssertionError(creatorAnnotation);
- }
-
- private static Function<String, String> transformation(
- boolean isProduction, boolean isSubcomponent) {
- Function<String, String> transformation = isProduction ? PRODUCTION : UnaryOperator.identity();
- return isSubcomponent ? transformation.andThen(SUBCOMPONENT) : transformation;
- }
-
- private abstract static class Messages {
- private final Function<String, String> transformation;
-
- Messages(Function<String, String> transformation) {
- this.transformation = transformation;
- }
-
- protected final String process(String s) {
- return transformation.apply(s);
- }
- }
-
- /** Errors for components. */
- public static final class ComponentMessages extends Messages {
- ComponentMessages(Function<String, String> transformation) {
- super(transformation);
- }
-
- public final String moreThanOne() {
- return process("@Component has more than one @Component.Builder or @Component.Factory: %s");
- }
- }
-
- /** Errors for component creators. */
- public abstract static class ComponentCreatorMessages extends Messages {
- ComponentCreatorMessages(Function<String, String> transformation) {
- super(transformation);
- }
-
- public static String builderMethodRequiresNoArgs() {
- return "Methods returning a @Component.Builder must have no arguments";
- }
-
- public static String moreThanOneRefToSubcomponent() {
- return "Only one method can create a given subcomponent. %s is created by: %s";
- }
-
- public final String invalidConstructor() {
- return process("@Component.Builder classes must have exactly one constructor,"
- + " and it must not be private or have any parameters");
- }
-
- public final String generics() {
- return process("@Component.Builder types must not have any generic types");
- }
-
- public final String mustBeInComponent() {
- return process("@Component.Builder types must be nested within a @Component");
- }
-
- public final String mustBeClassOrInterface() {
- return process("@Component.Builder types must be abstract classes or interfaces");
- }
-
- public final String isPrivate() {
- return process("@Component.Builder types must not be private");
- }
-
- public final String mustBeStatic() {
- return process("@Component.Builder types must be static");
- }
-
- public final String mustBeAbstract() {
- return process("@Component.Builder types must be abstract");
- }
-
- public abstract String missingFactoryMethod();
-
- public abstract String multipleSettersForModuleOrDependencyType();
-
- public abstract String extraSetters();
-
- public abstract String missingSetters();
-
- public abstract String twoFactoryMethods();
-
- public abstract String inheritedTwoFactoryMethods();
-
- public abstract String factoryMethodMustReturnComponentType();
-
- public final String inheritedFactoryMethodMustReturnComponentType() {
- return factoryMethodMustReturnComponentType() + ". Inherited method: %s";
- }
-
- public abstract String factoryMethodMayNotBeAnnotatedWithBindsInstance();
-
- public final String inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance() {
- return factoryMethodMayNotBeAnnotatedWithBindsInstance() + ". Inherited method: %s";
- }
-
- public final String setterMethodsMustTakeOneArg() {
- return process("@Component.Builder methods must not have more than one argument");
- }
-
- public final String inheritedSetterMethodsMustTakeOneArg() {
- return setterMethodsMustTakeOneArg() + ". Inherited method: %s";
- }
-
- public final String setterMethodsMustReturnVoidOrBuilder() {
- return process("@Component.Builder setter methods must return void, the builder,"
- + " or a supertype of the builder");
- }
-
- public final String inheritedSetterMethodsMustReturnVoidOrBuilder() {
- return setterMethodsMustReturnVoidOrBuilder() + ". Inherited method: %s";
- }
-
- public final String methodsMayNotHaveTypeParameters() {
- return process("@Component.Builder methods must not have type parameters");
- }
-
- public final String inheritedMethodsMayNotHaveTypeParameters() {
- return methodsMayNotHaveTypeParameters() + ". Inherited method: %s";
- }
-
- public abstract String nonBindsInstanceParametersMayNotBePrimitives();
-
- public final String inheritedNonBindsInstanceParametersMayNotBePrimitives() {
- return nonBindsInstanceParametersMayNotBePrimitives() + ". Inherited method: %s";
- }
-
- public final String factoryMethodReturnsSupertypeWithMissingMethods(
- TypeElement component,
- TypeElement componentBuilder,
- TypeMirror returnType,
- ExecutableElement buildMethod,
- Set<ExecutableElement> additionalMethods) {
- return String.format(
- "%1$s.%2$s() returns %3$s, but %4$s declares additional component method(s): %5$s. In "
- + "order to provide type-safe access to these methods, override %2$s() to return "
- + "%4$s",
- componentBuilder.getQualifiedName(),
- buildMethod.getSimpleName(),
- returnType,
- component.getQualifiedName(),
- Joiner.on(", ").join(additionalMethods));
- }
-
- public final String bindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
- return process("@Component.Builder setter methods may not have @BindsInstance on both the "
- + "method and its parameter; choose one or the other");
- }
-
- public final String inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter() {
- return bindsInstanceNotAllowedOnBothSetterMethodAndParameter() + ". Inherited method: %s";
- }
- }
-
- private static final class BuilderMessages extends ComponentCreatorMessages {
- BuilderMessages(Function<String, String> transformation) {
- super(transformation);
- }
-
- @Override
- public String missingFactoryMethod() {
- return process(
- "@Component.Builder types must have exactly one no-args method that "
- + " returns the @Component type");
- }
-
- @Override
- public String multipleSettersForModuleOrDependencyType() {
- return process(
- "@Component.Builder types must not have more than one setter method per module or "
- + "dependency, but %s is set by %s");
- }
-
- @Override
- public String extraSetters() {
- return process(
- "@Component.Builder has setters for modules or components that aren't required: %s");
- }
-
- @Override
- public String missingSetters() {
- return process(
- "@Component.Builder is missing setters for required modules or components: %s");
- }
-
- @Override
- public String twoFactoryMethods() {
- return process(
- "@Component.Builder types must have exactly one zero-arg method, and that"
- + " method must return the @Component type. Already found: %s");
- }
-
- @Override
- public String inheritedTwoFactoryMethods() {
- return process(
- "@Component.Builder types must have exactly one zero-arg method, and that"
- + " method must return the @Component type. Found %s and %s");
- }
-
- @Override
- public String factoryMethodMustReturnComponentType() {
- return process(
- "@Component.Builder methods that have no arguments must return the @Component type or a "
- + "supertype of the @Component");
- }
-
- @Override
- public String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
- return process(
- "@Component.Builder no-arg build methods may not be annotated with @BindsInstance");
- }
-
- @Override
- public String nonBindsInstanceParametersMayNotBePrimitives() {
- return process(
- "@Component.Builder methods that are not annotated with @BindsInstance "
- + "must take either a module or a component dependency, not a primitive");
- }
- }
-
- private static final class FactoryMessages extends ComponentCreatorMessages {
- FactoryMessages(Function<String, String> transformation) {
- super(transformation.andThen(FACTORY));
- }
-
- @Override
- public String missingFactoryMethod() {
- return process(
- "@Component.Factory types must have exactly one method that "
- + "returns the @Component type");
- }
-
- @Override
- public String multipleSettersForModuleOrDependencyType() {
- return process(
- "@Component.Factory methods must not have more than one parameter per module or "
- + "dependency, but %s is set by %s");
- }
-
- @Override
- public String extraSetters() {
- return process(
- "@Component.Factory method has parameters for modules or components that aren't "
- + "required: %s");
- }
-
- @Override
- public String missingSetters() {
- return process(
- "@Component.Factory method is missing parameters for required modules or components: %s");
- }
-
- @Override
- public String twoFactoryMethods() {
- return process(
- "@Component.Factory types must have exactly one abstract method. Already found: %s");
- }
-
- @Override
- public String inheritedTwoFactoryMethods() {
- return twoFactoryMethods();
- }
-
- @Override
- public String factoryMethodMustReturnComponentType() {
- return process(
- "@Component.Factory abstract methods must return the @Component type or a "
- + "supertype of the @Component");
- }
-
- @Override
- public String factoryMethodMayNotBeAnnotatedWithBindsInstance() {
- return process("@Component.Factory method may not be annotated with @BindsInstance");
- }
-
- @Override
- public String nonBindsInstanceParametersMayNotBePrimitives() {
- return process(
- "@Component.Factory method parameters that are not annotated with @BindsInstance "
- + "must be either a module or a component dependency, not a primitive");
- }
- }
-
- private ErrorMessages() {}
-}
diff --git a/java/dagger/internal/codegen/binding/FrameworkField.java b/java/dagger/internal/codegen/binding/FrameworkField.java
deleted file mode 100644
index 3b0b73f..0000000
--- a/java/dagger/internal/codegen/binding/FrameworkField.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.model.BindingKind.MEMBERS_INJECTOR;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.base.CaseFormat;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementVisitor;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementKindVisitor8;
-
-/**
- * A value object that represents a field in the generated Component class.
- *
- * <p>Examples:
- *
- * <ul>
- * <li>{@code Provider<String>}
- * <li>{@code Producer<Widget>}
- * <li>{@code Provider<Map<SomeMapKey, MapValue>>}.
- * </ul>
- */
-@AutoValue
-public abstract class FrameworkField {
-
- /**
- * Creates a framework field.
- *
- * @param frameworkClassName the name of the framework class (e.g., {@link javax.inject.Provider})
- * @param valueTypeName the name of the type parameter of the framework class (e.g., {@code Foo}
- * for {@code Provider<Foo>}
- * @param fieldName the name of the field
- */
- public static FrameworkField create(
- ClassName frameworkClassName, TypeName valueTypeName, String fieldName) {
- String suffix = frameworkClassName.simpleName();
- return new AutoValue_FrameworkField(
- ParameterizedTypeName.get(frameworkClassName, valueTypeName),
- fieldName.endsWith(suffix) ? fieldName : fieldName + suffix);
- }
-
- /**
- * A framework field for a {@link ContributionBinding}.
- *
- * @param frameworkClass if present, the field will use this framework class instead of the normal
- * one for the binding's type.
- */
- public static FrameworkField forBinding(
- ContributionBinding binding, Optional<ClassName> frameworkClass) {
- return create(
- frameworkClass.orElse(
- ClassName.get(
- FrameworkType.forBindingType(binding.bindingType()).frameworkClass())),
- TypeName.get(fieldValueType(binding)),
- frameworkFieldName(binding));
- }
-
- private static TypeMirror fieldValueType(ContributionBinding binding) {
- return binding.contributionType().isMultibinding()
- ? binding.contributedType()
- : binding.key().type();
- }
-
- private static String frameworkFieldName(ContributionBinding binding) {
- if (binding.bindingElement().isPresent()) {
- String name = BINDING_ELEMENT_NAME.visit(binding.bindingElement().get(), binding);
- return binding.kind().equals(MEMBERS_INJECTOR) ? name + "MembersInjector" : name;
- }
- return KeyVariableNamer.name(binding.key());
- }
-
- private static final ElementVisitor<String, Binding> BINDING_ELEMENT_NAME =
- new ElementKindVisitor8<String, Binding>() {
-
- @Override
- protected String defaultAction(Element e, Binding p) {
- throw new IllegalArgumentException("Unexpected binding " + p);
- }
-
- @Override
- public String visitExecutableAsConstructor(ExecutableElement e, Binding p) {
- return visit(e.getEnclosingElement(), p);
- }
-
- @Override
- public String visitExecutableAsMethod(ExecutableElement e, Binding p) {
- return e.getSimpleName().toString();
- }
-
- @Override
- public String visitType(TypeElement e, Binding p) {
- return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, e.getSimpleName().toString());
- }
-
- @Override
- public String visitVariableAsParameter(VariableElement e, Binding p) {
- return e.getSimpleName().toString();
- }
- };
-
- public abstract ParameterizedTypeName type();
-
- public abstract String name();
-}
diff --git a/java/dagger/internal/codegen/binding/FrameworkType.java b/java/dagger/internal/codegen/binding/FrameworkType.java
deleted file mode 100644
index 6b160b6..0000000
--- a/java/dagger/internal/codegen/binding/FrameworkType.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-import static dagger.model.RequestKind.INSTANCE;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import dagger.Lazy;
-import dagger.internal.DoubleCheck;
-import dagger.internal.ProviderOfLazy;
-import dagger.internal.codegen.base.RequestKinds;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.internal.Producers;
-import java.util.Optional;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/** One of the core types initialized as fields in a generated component. */
-public enum FrameworkType {
- /** A {@link Provider}. */
- PROVIDER {
- @Override
- public Class<?> frameworkClass() {
- return Provider.class;
- }
-
- @Override
- public Optional<RequestKind> requestKind() {
- return Optional.of(RequestKind.PROVIDER);
- }
-
- @Override
- public CodeBlock to(RequestKind requestKind, CodeBlock from) {
- switch (requestKind) {
- case INSTANCE:
- return CodeBlock.of("$L.get()", from);
-
- case LAZY:
- return CodeBlock.of("$T.lazy($L)", DoubleCheck.class, from);
-
- case PROVIDER:
- return from;
-
- case PROVIDER_OF_LAZY:
- return CodeBlock.of("$T.create($L)", ProviderOfLazy.class, from);
-
- case PRODUCER:
- return CodeBlock.of("$T.producerFromProvider($L)", Producers.class, from);
-
- case FUTURE:
- return CodeBlock.of("$T.immediateFuture($L)", Futures.class, to(INSTANCE, from));
-
- case PRODUCED:
- return CodeBlock.of("$T.successful($L)", Produced.class, to(INSTANCE, from));
-
- default:
- throw new IllegalArgumentException(
- String.format("Cannot request a %s from a %s", requestKind, this));
- }
- }
-
- @Override
- public Expression to(RequestKind requestKind, Expression from, DaggerTypes types) {
- CodeBlock codeBlock = to(requestKind, from.codeBlock());
- switch (requestKind) {
- case INSTANCE:
- return Expression.create(types.unwrapTypeOrObject(from.type()), codeBlock);
-
- case PROVIDER:
- return from;
-
- case PROVIDER_OF_LAZY:
- TypeMirror lazyType = types.rewrapType(from.type(), Lazy.class);
- return Expression.create(types.wrapType(lazyType, Provider.class), codeBlock);
-
- case FUTURE:
- return Expression.create(
- types.rewrapType(from.type(), ListenableFuture.class), codeBlock);
-
- default:
- return Expression.create(
- types.rewrapType(from.type(), RequestKinds.frameworkClass(requestKind)), codeBlock);
- }
- }
- },
-
- /** A {@link Producer}. */
- PRODUCER_NODE {
- @Override
- public Class<?> frameworkClass() {
- // TODO(cgdecker): Replace this with new class for representing internal producer nodes.
- // Currently the new class is CancellableProducer, but it may be changed to ProducerNode and
- // made to not implement Producer.
- return Producer.class;
- }
-
- @Override
- public Optional<RequestKind> requestKind() {
- return Optional.empty();
- }
-
- @Override
- public CodeBlock to(RequestKind requestKind, CodeBlock from) {
- switch (requestKind) {
- case FUTURE:
- return CodeBlock.of("$L.get()", from);
-
- case PRODUCER:
- return from;
-
- default:
- throw new IllegalArgumentException(
- String.format("Cannot request a %s from a %s", requestKind, this));
- }
- }
-
- @Override
- public Expression to(RequestKind requestKind, Expression from, DaggerTypes types) {
- switch (requestKind) {
- case FUTURE:
- return Expression.create(
- types.rewrapType(from.type(), ListenableFuture.class),
- to(requestKind, from.codeBlock()));
-
- case PRODUCER:
- return Expression.create(from.type(), to(requestKind, from.codeBlock()));
-
- default:
- throw new IllegalArgumentException(
- String.format("Cannot request a %s from a %s", requestKind, this));
- }
- }
- },
- ;
-
- /** Returns the framework type appropriate for fields for a given binding type. */
- public static FrameworkType forBindingType(BindingType bindingType) {
- switch (bindingType) {
- case PROVISION:
- return PROVIDER;
- case PRODUCTION:
- return PRODUCER_NODE;
- case MEMBERS_INJECTION:
- }
- throw new AssertionError(bindingType);
- }
-
- /** Returns the framework type that exactly matches the given request kind, if one exists. */
- public static Optional<FrameworkType> forRequestKind(RequestKind requestKind) {
- switch (requestKind) {
- case PROVIDER:
- return Optional.of(FrameworkType.PROVIDER);
- default:
- return Optional.empty();
- }
- }
-
- /** The class of fields of this type. */
- public abstract Class<?> frameworkClass();
-
- /** Returns the {@link #frameworkClass()} parameterized with a type. */
- public ParameterizedTypeName frameworkClassOf(TypeName valueType) {
- return ParameterizedTypeName.get(ClassName.get(frameworkClass()), valueType);
- }
-
- /** The request kind that an instance of this framework type can satisfy directly, if any. */
- public abstract Optional<RequestKind> requestKind();
-
- /**
- * Returns a {@link CodeBlock} that evaluates to a requested object given an expression that
- * evaluates to an instance of this framework type.
- *
- * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
- * satisfy
- * @param from a {@link CodeBlock} that evaluates to an instance of this framework type
- * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
- * requestKind}
- */
- public abstract CodeBlock to(RequestKind requestKind, CodeBlock from);
-
- /**
- * Returns an {@link Expression} that evaluates to a requested object given an expression that
- * evaluates to an instance of this framework type.
- *
- * @param requestKind the kind of {@link DependencyRequest} that the returned expression can
- * satisfy
- * @param from an expression that evaluates to an instance of this framework type
- * @throws IllegalArgumentException if a valid expression cannot be generated for {@code
- * requestKind}
- */
- public abstract Expression to(RequestKind requestKind, Expression from, DaggerTypes types);
-
- @Override
- public String toString() {
- return UPPER_UNDERSCORE.to(UPPER_CAMEL, super.toString());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java b/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
deleted file mode 100644
index 85463af..0000000
--- a/java/dagger/internal/codegen/binding/FrameworkTypeMapper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.binding.BindingType.PRODUCTION;
-
-import dagger.model.RequestKind;
-import dagger.producers.Producer;
-import javax.inject.Provider;
-
-/**
- * A mapper for associating a {@link RequestKind} to a {@link FrameworkType}, dependent on the type
- * of code to be generated (e.g., for {@link Provider} or {@link Producer}).
- */
-public enum FrameworkTypeMapper {
- FOR_PROVIDER() {
- @Override
- public FrameworkType getFrameworkType(RequestKind requestKind) {
- switch (requestKind) {
- case INSTANCE:
- case PROVIDER:
- case PROVIDER_OF_LAZY:
- case LAZY:
- return FrameworkType.PROVIDER;
- case PRODUCED:
- case PRODUCER:
- throw new IllegalArgumentException(requestKind.toString());
- default:
- throw new AssertionError(requestKind);
- }
- }
- },
- FOR_PRODUCER() {
- @Override
- public FrameworkType getFrameworkType(RequestKind requestKind) {
- switch (requestKind) {
- case INSTANCE:
- case PRODUCED:
- case PRODUCER:
- return FrameworkType.PRODUCER_NODE;
- case PROVIDER:
- case PROVIDER_OF_LAZY:
- case LAZY:
- return FrameworkType.PROVIDER;
- default:
- throw new AssertionError(requestKind);
- }
- }
- };
-
- public static FrameworkTypeMapper forBindingType(BindingType bindingType) {
- return bindingType.equals(PRODUCTION) ? FOR_PRODUCER : FOR_PROVIDER;
- }
-
- public abstract FrameworkType getFrameworkType(RequestKind requestKind);
-}
diff --git a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java b/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
deleted file mode 100644
index 5203130..0000000
--- a/java/dagger/internal/codegen/binding/InjectBindingRegistry.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.Component;
-import dagger.Provides;
-import dagger.internal.codegen.base.SourceFileGenerationException;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.model.Key;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-
-/**
- * Maintains the collection of provision bindings from {@link Inject} constructors and members
- * injection bindings from {@link Inject} fields and methods known to the annotation processor. Note
- * that this registry <b>does not</b> handle any explicit bindings (those from {@link Provides}
- * methods, {@link Component} dependencies, etc.).
- */
-public interface InjectBindingRegistry {
- /**
- * Returns a {@link ProvisionBinding} for {@code key}. If none has been registered yet, registers
- * one.
- */
- Optional<ProvisionBinding> getOrFindProvisionBinding(Key key);
-
- /**
- * Returns a {@link MembersInjectionBinding} for {@code key}. If none has been registered yet,
- * registers one, along with all necessary members injection bindings for superclasses.
- */
- Optional<MembersInjectionBinding> getOrFindMembersInjectionBinding(Key key);
-
- /**
- * Returns a {@link ProvisionBinding} for a {@link dagger.MembersInjector} of {@code key}. If none
- * has been registered yet, registers one.
- */
- Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key);
-
- @CanIgnoreReturnValue
- Optional<ProvisionBinding> tryRegisterConstructor(ExecutableElement constructorElement);
-
- @CanIgnoreReturnValue
- Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(TypeElement typeElement);
-
- /**
- * This method ensures that sources for all registered {@link Binding bindings} (either explicitly
- * or implicitly via {@link #getOrFindMembersInjectionBinding} or {@link
- * #getOrFindProvisionBinding}) are generated.
- */
- void generateSourcesForRequiredBindings(
- SourceFileGenerator<ProvisionBinding> factoryGenerator,
- SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator)
- throws SourceFileGenerationException;
-}
diff --git a/java/dagger/internal/codegen/binding/InjectionAnnotations.java b/java/dagger/internal/codegen/binding/InjectionAnnotations.java
deleted file mode 100644
index 748755e..0000000
--- a/java/dagger/internal/codegen/binding/InjectionAnnotations.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.asVariable;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getStringValue;
-import static dagger.internal.codegen.binding.SourceFiles.memberInjectedFieldSignatureForVariable;
-import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.constructorsIn;
-
-import com.google.auto.common.AnnotationMirrors;
-import com.google.auto.common.SuperficialValidation;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.InjectedFieldSignature;
-import dagger.internal.codegen.extension.DaggerCollectors;
-import dagger.internal.codegen.extension.DaggerStreams;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.Optional;
-import java.util.stream.Stream;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-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.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.util.ElementFilter;
-
-/** Utilities relating to annotations defined in the {@code javax.inject} package. */
-public final class InjectionAnnotations {
-
- private static final Equivalence<AnnotationMirror> EQUIVALENCE = AnnotationMirrors.equivalence();
-
- private final DaggerElements elements;
- private final KotlinMetadataUtil kotlinMetadataUtil;
-
- @Inject
- InjectionAnnotations(DaggerElements elements, KotlinMetadataUtil kotlinMetadataUtil) {
- this.elements = elements;
- this.kotlinMetadataUtil = kotlinMetadataUtil;
- }
-
- public Optional<AnnotationMirror> getQualifier(Element e) {
- if (!SuperficialValidation.validateElement(e)) {
- throw new TypeNotPresentException(e.toString(), null);
- }
- checkNotNull(e);
- ImmutableCollection<? extends AnnotationMirror> qualifierAnnotations = getQualifiers(e);
- switch (qualifierAnnotations.size()) {
- case 0:
- return Optional.empty();
- case 1:
- return Optional.<AnnotationMirror>of(qualifierAnnotations.iterator().next());
- default:
- throw new IllegalArgumentException(
- e + " was annotated with more than one @Qualifier annotation");
- }
- }
-
- public ImmutableCollection<? extends AnnotationMirror> getQualifiers(Element element) {
- ImmutableSet<? extends AnnotationMirror> qualifiers =
- AnnotationMirrors.getAnnotatedAnnotations(element, Qualifier.class);
- if (element.getKind() == ElementKind.FIELD
- // static injected fields are not supported, no need to get qualifier from kotlin metadata
- && !element.getModifiers().contains(STATIC)
- && isAnnotationPresent(element, Inject.class)
- && kotlinMetadataUtil.hasMetadata(element)) {
- return Stream.concat(
- qualifiers.stream(), getQualifiersForKotlinProperty(asVariable(element)).stream())
- .map(EQUIVALENCE::wrap) // Wrap in equivalence to deduplicate
- .distinct()
- .map(Wrapper::get)
- .collect(DaggerStreams.toImmutableList());
- } else {
- return qualifiers.asList();
- }
- }
-
- /** Returns the constructors in {@code type} that are annotated with {@link Inject}. */
- public static ImmutableSet<ExecutableElement> injectedConstructors(TypeElement type) {
- return FluentIterable.from(constructorsIn(type.getEnclosedElements()))
- .filter(constructor -> isAnnotationPresent(constructor, Inject.class))
- .toSet();
- }
-
- /**
- * Gets the qualifiers annotation of a Kotlin Property. Finding these annotations involve finding
- * the synthetic method for annotations as described by the Kotlin metadata or finding the
- * corresponding MembersInjector method for the field, which also contains the qualifier
- * annotation.
- */
- private ImmutableCollection<? extends AnnotationMirror> getQualifiersForKotlinProperty(
- VariableElement fieldElement) {
- // TODO(bcorso): Consider moving this to KotlinMetadataUtil
- if (kotlinMetadataUtil.isMissingSyntheticPropertyForAnnotations(fieldElement)) {
- // If we detect that the synthetic method for annotations is missing, possibly due to the
- // element being from a compiled class, then find the MembersInjector that was generated
- // for the enclosing class and extract the qualifier information from it.
- TypeElement membersInjector =
- elements.getTypeElement(
- membersInjectorNameForType(asType(fieldElement.getEnclosingElement())));
- if (membersInjector != null) {
- String memberInjectedFieldSignature = memberInjectedFieldSignatureForVariable(fieldElement);
- // TODO(danysantiago): We have to iterate over all the injection methods for every qualifier
- // look up. Making this N^2 when looking through all the injected fields. :(
- return ElementFilter.methodsIn(membersInjector.getEnclosedElements()).stream()
- .filter(
- method ->
- getAnnotationMirror(method, InjectedFieldSignature.class)
- .map(annotation -> getStringValue(annotation, "value"))
- .map(memberInjectedFieldSignature::equals)
- // If a method is not an @InjectedFieldSignature method then filter it out
- .orElse(false))
- .collect(DaggerCollectors.toOptional())
- .map(this::getQualifiers)
- .orElseThrow(
- () ->
- new IllegalStateException(
- String.format(
- "No matching InjectedFieldSignature for %1$s. This likely means that "
- + "%1$s was compiled with an older, incompatible version of "
- + "Dagger. Please update all Dagger dependencies to the same "
- + "version.",
- memberInjectedFieldSignature)));
- } else {
- throw new IllegalStateException(
- "No MembersInjector found for " + fieldElement.getEnclosingElement());
- }
- } else {
- return kotlinMetadataUtil.getSyntheticPropertyAnnotations(fieldElement, Qualifier.class);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/InjectionSiteFactory.java b/java/dagger/internal/codegen/binding/InjectionSiteFactory.java
deleted file mode 100644
index 7a6f8d2..0000000
--- a/java/dagger/internal/codegen/binding/InjectionSiteFactory.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2017 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.langmodel.DaggerElements.DECLARATION_ORDER;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.SetMultimap;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-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.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementKindVisitor8;
-
-/** A factory for {@link Binding} objects. */
-final class InjectionSiteFactory {
-
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final DependencyRequestFactory dependencyRequestFactory;
-
- @Inject
- InjectionSiteFactory(
- DaggerTypes types,
- DaggerElements elements,
- DependencyRequestFactory dependencyRequestFactory) {
- this.types = types;
- this.elements = elements;
- this.dependencyRequestFactory = dependencyRequestFactory;
- }
-
- /** Returns the injection sites for a type. */
- ImmutableSortedSet<InjectionSite> getInjectionSites(DeclaredType declaredType) {
- Set<InjectionSite> injectionSites = new HashSet<>();
- List<TypeElement> ancestors = new ArrayList<>();
- InjectionSiteVisitor injectionSiteVisitor = new InjectionSiteVisitor();
- for (Optional<DeclaredType> currentType = Optional.of(declaredType);
- currentType.isPresent();
- currentType = types.nonObjectSuperclass(currentType.get())) {
- DeclaredType type = currentType.get();
- ancestors.add(MoreElements.asType(type.asElement()));
- for (Element enclosedElement : type.asElement().getEnclosedElements()) {
- injectionSiteVisitor.visit(enclosedElement, type).ifPresent(injectionSites::add);
- }
- }
- return ImmutableSortedSet.copyOf(
- // supertypes before subtypes
- Comparator.comparing(
- (InjectionSite injectionSite) ->
- ancestors.indexOf(injectionSite.element().getEnclosingElement()))
- .reversed()
- // fields before methods
- .thenComparing(injectionSite -> injectionSite.element().getKind())
- // then sort by whichever element comes first in the parent
- // this isn't necessary, but makes the processor nice and predictable
- .thenComparing(InjectionSite::element, DECLARATION_ORDER),
- injectionSites);
- }
-
- private final class InjectionSiteVisitor
- extends ElementKindVisitor8<Optional<InjectionSite>, DeclaredType> {
- private final SetMultimap<String, ExecutableElement> subclassMethodMap =
- LinkedHashMultimap.create();
-
- InjectionSiteVisitor() {
- super(Optional.empty());
- }
-
- @Override
- public Optional<InjectionSite> visitExecutableAsMethod(
- ExecutableElement method, DeclaredType type) {
- subclassMethodMap.put(method.getSimpleName().toString(), method);
- if (!shouldBeInjected(method)) {
- return Optional.empty();
- }
- // This visitor assumes that subclass methods are visited before superclass methods, so we can
- // skip any overridden method that has already been visited. To decrease the number of methods
- // that are checked, we store the already injected methods in a SetMultimap and only check the
- // methods with the same name.
- String methodName = method.getSimpleName().toString();
- TypeElement enclosingType = MoreElements.asType(method.getEnclosingElement());
- for (ExecutableElement subclassMethod : subclassMethodMap.get(methodName)) {
- if (method != subclassMethod && elements.overrides(subclassMethod, method, enclosingType)) {
- return Optional.empty();
- }
- }
- ExecutableType resolved = MoreTypes.asExecutable(types.asMemberOf(type, method));
- return Optional.of(
- InjectionSite.method(
- method,
- dependencyRequestFactory.forRequiredResolvedVariables(
- method.getParameters(), resolved.getParameterTypes())));
- }
-
- @Override
- public Optional<InjectionSite> visitVariableAsField(
- VariableElement field, DeclaredType type) {
- if (!shouldBeInjected(field)) {
- return Optional.empty();
- }
- TypeMirror resolved = types.asMemberOf(type, field);
- return Optional.of(
- InjectionSite.field(
- field, dependencyRequestFactory.forRequiredResolvedVariable(field, resolved)));
- }
-
- private boolean shouldBeInjected(Element injectionSite) {
- return isAnnotationPresent(injectionSite, Inject.class)
- && !injectionSite.getModifiers().contains(PRIVATE)
- && !injectionSite.getModifiers().contains(STATIC);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/KeyFactory.java b/java/dagger/internal/codegen/binding/KeyFactory.java
deleted file mode 100644
index d923666..0000000
--- a/java/dagger/internal/codegen/binding/KeyFactory.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.isType;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
-import static dagger.internal.codegen.binding.MapKeys.getMapKey;
-import static dagger.internal.codegen.binding.MapKeys.mapKeyType;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.Optionals.firstPresent;
-import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
-import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
-import static java.util.Arrays.asList;
-import static javax.lang.model.element.ElementKind.METHOD;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.Binds;
-import dagger.BindsOptionalOf;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.FrameworkTypes;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.OptionalType;
-import dagger.internal.codegen.base.RequestKinds;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.base.SimpleAnnotationMirror;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.Key.MultibindingContributionIdentifier;
-import dagger.model.RequestKind;
-import dagger.multibindings.Multibinds;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.Production;
-import dagger.producers.internal.ProductionImplementation;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.stream.Stream;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-
-/** A factory for {@link Key}s. */
-public final class KeyFactory {
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final InjectionAnnotations injectionAnnotations;
-
- @Inject
- KeyFactory(
- DaggerTypes types, DaggerElements elements, InjectionAnnotations injectionAnnotations) {
- this.types = checkNotNull(types);
- this.elements = checkNotNull(elements);
- this.injectionAnnotations = injectionAnnotations;
- }
-
- private TypeMirror boxPrimitives(TypeMirror type) {
- return type.getKind().isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type;
- }
-
- private DeclaredType setOf(TypeMirror elementType) {
- return types.getDeclaredType(elements.getTypeElement(Set.class), boxPrimitives(elementType));
- }
-
- private DeclaredType mapOf(TypeMirror keyType, TypeMirror valueType) {
- return types.getDeclaredType(
- elements.getTypeElement(Map.class), boxPrimitives(keyType), boxPrimitives(valueType));
- }
-
- /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */
- private TypeMirror mapOfFrameworkType(
- TypeMirror keyType, TypeElement frameworkType, TypeMirror valueType) {
- return mapOf(keyType, types.getDeclaredType(frameworkType, boxPrimitives(valueType)));
- }
-
- Key forComponentMethod(ExecutableElement componentMethod) {
- checkArgument(componentMethod.getKind().equals(METHOD));
- return forMethod(componentMethod, componentMethod.getReturnType());
- }
-
- Key forProductionComponentMethod(ExecutableElement componentMethod) {
- checkArgument(componentMethod.getKind().equals(METHOD));
- TypeMirror returnType = componentMethod.getReturnType();
- TypeMirror keyType =
- isFutureType(returnType)
- ? getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments())
- : returnType;
- return forMethod(componentMethod, keyType);
- }
-
- Key forSubcomponentCreatorMethod(
- ExecutableElement subcomponentCreatorMethod, DeclaredType declaredContainer) {
- checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD));
- ExecutableType resolvedMethod =
- asExecutable(types.asMemberOf(declaredContainer, subcomponentCreatorMethod));
- return Key.builder(resolvedMethod.getReturnType()).build();
- }
-
- public Key forSubcomponentCreator(TypeMirror creatorType) {
- return Key.builder(creatorType).build();
- }
-
- public Key forProvidesMethod(ExecutableElement method, TypeElement contributingModule) {
- return forBindingMethod(
- method, contributingModule, Optional.of(elements.getTypeElement(Provider.class)));
- }
-
- public Key forProducesMethod(ExecutableElement method, TypeElement contributingModule) {
- return forBindingMethod(
- method, contributingModule, Optional.of(elements.getTypeElement(Producer.class)));
- }
-
- /** Returns the key bound by a {@link Binds} method. */
- Key forBindsMethod(ExecutableElement method, TypeElement contributingModule) {
- checkArgument(isAnnotationPresent(method, Binds.class));
- return forBindingMethod(method, contributingModule, Optional.empty());
- }
-
- /** Returns the base key bound by a {@link BindsOptionalOf} method. */
- Key forBindsOptionalOfMethod(ExecutableElement method, TypeElement contributingModule) {
- checkArgument(isAnnotationPresent(method, BindsOptionalOf.class));
- return forBindingMethod(method, contributingModule, Optional.empty());
- }
-
- private Key forBindingMethod(
- ExecutableElement method,
- TypeElement contributingModule,
- Optional<TypeElement> frameworkType) {
- checkArgument(method.getKind().equals(METHOD));
- ExecutableType methodType =
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), method));
- ContributionType contributionType = ContributionType.fromBindingElement(method);
- TypeMirror returnType = methodType.getReturnType();
- if (frameworkType.isPresent()
- && frameworkType.get().equals(elements.getTypeElement(Producer.class))
- && isType(returnType)) {
- if (isFutureType(methodType.getReturnType())) {
- returnType = getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
- } else if (contributionType.equals(ContributionType.SET_VALUES)
- && SetType.isSet(returnType)) {
- SetType setType = SetType.from(returnType);
- if (isFutureType(setType.elementType())) {
- returnType =
- types.getDeclaredType(
- elements.getTypeElement(Set.class), unwrapType(setType.elementType()));
- }
- }
- }
- TypeMirror keyType = bindingMethodKeyType(returnType, method, contributionType, frameworkType);
- Key key = forMethod(method, keyType);
- return contributionType.equals(ContributionType.UNIQUE)
- ? key
- : key.toBuilder()
- .multibindingContributionIdentifier(
- new MultibindingContributionIdentifier(method, contributingModule))
- .build();
- }
-
- /**
- * Returns the key for a {@link Multibinds @Multibinds} method.
- *
- * <p>The key's type is either {@code Set<T>} or {@code Map<K, Provider<V>>}. The latter works
- * even for maps used by {@code Producer}s.
- */
- Key forMultibindsMethod(ExecutableType executableType, ExecutableElement method) {
- checkArgument(method.getKind().equals(METHOD), "%s must be a method", method);
- TypeMirror returnType = executableType.getReturnType();
- TypeMirror keyType =
- MapType.isMap(returnType)
- ? mapOfFrameworkType(
- MapType.from(returnType).keyType(),
- elements.getTypeElement(Provider.class),
- MapType.from(returnType).valueType())
- : returnType;
- return forMethod(method, keyType);
- }
-
- private TypeMirror bindingMethodKeyType(
- TypeMirror returnType,
- ExecutableElement method,
- ContributionType contributionType,
- Optional<TypeElement> frameworkType) {
- switch (contributionType) {
- case UNIQUE:
- return returnType;
- case SET:
- return setOf(returnType);
- case MAP:
- TypeMirror mapKeyType = mapKeyType(getMapKey(method).get(), types);
- return frameworkType.isPresent()
- ? mapOfFrameworkType(mapKeyType, frameworkType.get(), returnType)
- : mapOf(mapKeyType, returnType);
- case SET_VALUES:
- // TODO(gak): do we want to allow people to use "covariant return" here?
- checkArgument(SetType.isSet(returnType));
- return returnType;
- }
- throw new AssertionError();
- }
-
- /**
- * Returns the key for a binding associated with a {@link DelegateDeclaration}.
- *
- * <p>If {@code delegateDeclaration} is {@code @IntoMap}, transforms the {@code Map<K, V>} key
- * from {@link DelegateDeclaration#key()} to {@code Map<K, FrameworkType<V>>}. If {@code
- * delegateDeclaration} is not a map contribution, its key is returned.
- */
- Key forDelegateBinding(DelegateDeclaration delegateDeclaration, Class<?> frameworkType) {
- return delegateDeclaration.contributionType().equals(ContributionType.MAP)
- ? wrapMapValue(delegateDeclaration.key(), frameworkType)
- : delegateDeclaration.key();
- }
-
- private Key forMethod(ExecutableElement method, TypeMirror keyType) {
- return forQualifiedType(injectionAnnotations.getQualifier(method), keyType);
- }
-
- public Key forInjectConstructorWithResolvedType(TypeMirror type) {
- return Key.builder(type).build();
- }
-
- // TODO(ronshapiro): Remove these conveniences which are simple wrappers around Key.Builder
- Key forType(TypeMirror type) {
- return Key.builder(type).build();
- }
-
- public Key forMembersInjectedType(TypeMirror type) {
- return Key.builder(type).build();
- }
-
- Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
- return Key.builder(boxPrimitives(type)).qualifier(qualifier).build();
- }
-
- public Key forProductionExecutor() {
- return Key.builder(elements.getTypeElement(Executor.class).asType())
- .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(Production.class)))
- .build();
- }
-
- public Key forProductionImplementationExecutor() {
- return Key.builder(elements.getTypeElement(Executor.class).asType())
- .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(ProductionImplementation.class)))
- .build();
- }
-
- public Key forProductionComponentMonitor() {
- return Key.builder(elements.getTypeElement(ProductionComponentMonitor.class).asType()).build();
- }
-
- /**
- * If {@code requestKey} is for a {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns keys
- * for {@code Map<K, Provider<V>>} and {@code Map<K, Producer<V>>} (if Dagger-Producers is on
- * the classpath).
- */
- ImmutableSet<Key> implicitFrameworkMapKeys(Key requestKey) {
- return Stream.of(implicitMapProviderKeyFrom(requestKey), implicitMapProducerKeyFrom(requestKey))
- .filter(Optional::isPresent)
- .map(Optional::get)
- .collect(toImmutableSet());
- }
-
- /**
- * Optionally extract a {@link Key} for the underlying provision binding(s) if such a valid key
- * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code
- * <K, V>} or {@code Map<K, Producer<V>>}, a key of {@code Map<K, Provider<V>>} will be
- * returned.
- */
- Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
- return firstPresent(
- rewrapMapKey(possibleMapKey, Produced.class, Provider.class),
- wrapMapKey(possibleMapKey, Provider.class));
- }
-
- /**
- * Optionally extract a {@link Key} for the underlying production binding(s) if such a
- * valid key can be inferred from the given key. Specifically, if the key represents a
- * {@link Map}{@code <K, V>} or {@code Map<K, Produced<V>>}, a key of
- * {@code Map<K, Producer<V>>} will be returned.
- */
- Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
- return firstPresent(
- rewrapMapKey(possibleMapKey, Produced.class, Producer.class),
- wrapMapKey(possibleMapKey, Producer.class));
- }
-
- /**
- * If {@code key}'s type is {@code Map<K, Provider<V>>}, {@code Map<K, Producer<V>>}, or {@code
- * Map<K, Produced<V>>}, returns a key with the same qualifier and {@link
- * Key#multibindingContributionIdentifier()} whose type is simply {@code Map<K, V>}.
- *
- * <p>Otherwise, returns {@code key}.
- */
- public Key unwrapMapValueType(Key key) {
- if (MapType.isMap(key)) {
- MapType mapType = MapType.from(key);
- if (!mapType.isRawType()) {
- for (Class<?> frameworkClass : asList(Provider.class, Producer.class, Produced.class)) {
- if (mapType.valuesAreTypeOf(frameworkClass)) {
- return key.toBuilder()
- .type(mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass)))
- .build();
- }
- }
- }
- }
- return key;
- }
-
- /**
- * Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}.
- */
- private Key wrapMapValue(Key key, Class<?> newWrappingClass) {
- checkArgument(
- FrameworkTypes.isFrameworkType(elements.getTypeElement(newWrappingClass).asType()));
- return wrapMapKey(key, newWrappingClass).get();
- }
-
- /**
- * If {@code key}'s type is {@code Map<K, CurrentWrappingClass<Bar>>}, returns a key with type
- * {@code Map<K, NewWrappingClass<Bar>>} with the same qualifier. Otherwise returns {@link
- * Optional#empty()}.
- *
- * <p>Returns {@link Optional#empty()} if {@code newWrappingClass} is not in the classpath.
- *
- * @throws IllegalArgumentException if {@code newWrappingClass} is the same as {@code
- * currentWrappingClass}
- */
- public Optional<Key> rewrapMapKey(
- Key possibleMapKey, Class<?> currentWrappingClass, Class<?> newWrappingClass) {
- checkArgument(!currentWrappingClass.equals(newWrappingClass));
- if (MapType.isMap(possibleMapKey)) {
- MapType mapType = MapType.from(possibleMapKey);
- if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClass)) {
- TypeElement wrappingElement = elements.getTypeElement(newWrappingClass);
- if (wrappingElement == null) {
- // This target might not be compiled with Producers, so wrappingClass might not have an
- // associated element.
- return Optional.empty();
- }
- DeclaredType wrappedValueType =
- types.getDeclaredType(
- wrappingElement, mapType.unwrappedValueType(currentWrappingClass));
- return Optional.of(
- possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build());
- }
- }
- return Optional.empty();
- }
-
- /**
- * If {@code key}'s type is {@code Map<K, Foo>} and {@code Foo} is not {@code WrappingClass
- * <Bar>}, returns a key with type {@code Map<K, WrappingClass<Foo>>} with the same qualifier.
- * Otherwise returns {@link Optional#empty()}.
- *
- * <p>Returns {@link Optional#empty()} if {@code WrappingClass} is not in the classpath.
- */
- private Optional<Key> wrapMapKey(Key possibleMapKey, Class<?> wrappingClass) {
- if (MapType.isMap(possibleMapKey)) {
- MapType mapType = MapType.from(possibleMapKey);
- if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClass)) {
- TypeElement wrappingElement = elements.getTypeElement(wrappingClass);
- if (wrappingElement == null) {
- // This target might not be compiled with Producers, so wrappingClass might not have an
- // associated element.
- return Optional.empty();
- }
- DeclaredType wrappedValueType = types.getDeclaredType(wrappingElement, mapType.valueType());
- return Optional.of(
- possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build());
- }
- }
- return Optional.empty();
- }
-
- /**
- * If {@code key}'s type is {@code Set<WrappingClass<Bar>>}, returns a key with type {@code Set
- * <Bar>} with the same qualifier. Otherwise returns {@link Optional#empty()}.
- */
- Optional<Key> unwrapSetKey(Key key, Class<?> wrappingClass) {
- if (SetType.isSet(key)) {
- SetType setType = SetType.from(key);
- if (!setType.isRawType() && setType.elementsAreTypeOf(wrappingClass)) {
- return Optional.of(
- key.toBuilder().type(setOf(setType.unwrappedElementType(wrappingClass))).build());
- }
- }
- return Optional.empty();
- }
-
- /**
- * If {@code key}'s type is {@code Optional<T>} for some {@code T}, returns a key with the same
- * qualifier whose type is {@linkplain RequestKinds#extractKeyType(RequestKind, TypeMirror)}
- * extracted} from {@code T}.
- */
- Optional<Key> unwrapOptional(Key key) {
- if (!OptionalType.isOptional(key)) {
- return Optional.empty();
- }
-
- TypeMirror optionalValueType = OptionalType.from(key).valueType();
- return Optional.of(key.toBuilder().type(extractKeyType(optionalValueType)).build());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/KeyVariableNamer.java b/java/dagger/internal/codegen/binding/KeyVariableNamer.java
deleted file mode 100644
index 9ac0efa..0000000
--- a/java/dagger/internal/codegen/binding/KeyVariableNamer.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static dagger.internal.codegen.binding.SourceFiles.protectAgainstKeywords;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import java.util.Iterator;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/**
- * Suggests a variable name for a type based on a {@link Key}. Prefer {@link
- * DependencyVariableNamer} for cases where a specific {@link DependencyRequest} is present.
- */
-public final class KeyVariableNamer {
- /** Simple names that are very common. Inspired by https://errorprone.info/bugpattern/BadImport */
- private static final ImmutableSet<String> VERY_SIMPLE_NAMES =
- ImmutableSet.of(
- "Builder",
- "Factory",
- "Component",
- "Subcomponent",
- "Injector");
-
- private static final TypeVisitor<Void, StringBuilder> TYPE_NAMER =
- new SimpleTypeVisitor8<Void, StringBuilder>() {
- @Override
- public Void visitDeclared(DeclaredType declaredType, StringBuilder builder) {
- TypeElement element = MoreTypes.asTypeElement(declaredType);
- if (element.getNestingKind().isNested()
- && VERY_SIMPLE_NAMES.contains(element.getSimpleName().toString())) {
- builder.append(element.getEnclosingElement().getSimpleName());
- }
-
- builder.append(element.getSimpleName());
- Iterator<? extends TypeMirror> argumentIterator =
- declaredType.getTypeArguments().iterator();
- if (argumentIterator.hasNext()) {
- builder.append("Of");
- TypeMirror first = argumentIterator.next();
- first.accept(this, builder);
- while (argumentIterator.hasNext()) {
- builder.append("And");
- argumentIterator.next().accept(this, builder);
- }
- }
- return null;
- }
-
- @Override
- public Void visitPrimitive(PrimitiveType type, StringBuilder builder) {
- builder.append(LOWER_CAMEL.to(UPPER_CAMEL, type.toString()));
- return null;
- }
-
- @Override
- public Void visitArray(ArrayType type, StringBuilder builder) {
- type.getComponentType().accept(this, builder);
- builder.append("Array");
- return null;
- }
- };
-
- private KeyVariableNamer() {}
-
- public static String name(Key key) {
- if (key.multibindingContributionIdentifier().isPresent()) {
- return key.multibindingContributionIdentifier().get().bindingElement();
- }
-
- StringBuilder builder = new StringBuilder();
-
- if (key.qualifier().isPresent()) {
- // TODO(gak): Use a better name for fields with qualifiers with members.
- builder.append(key.qualifier().get().getAnnotationType().asElement().getSimpleName());
- }
-
- key.type().accept(TYPE_NAMER, builder);
-
- return protectAgainstKeywords(UPPER_CAMEL.to(LOWER_CAMEL, builder.toString()));
- }
-}
diff --git a/java/dagger/internal/codegen/binding/LegacyBindingGraph.java b/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
deleted file mode 100644
index 7c00401..0000000
--- a/java/dagger/internal/codegen/binding/LegacyBindingGraph.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2014 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimaps;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import java.util.Collection;
-import java.util.Map;
-import javax.lang.model.element.TypeElement;
-
-// TODO(bcorso): Remove the LegacyBindingGraph after we've migrated to the new BindingGraph.
-/** The canonical representation of a full-resolved graph. */
-final class LegacyBindingGraph {
- private final ComponentDescriptor componentDescriptor;
- private final ImmutableMap<Key, ResolvedBindings> contributionBindings;
- private final ImmutableMap<Key, ResolvedBindings> membersInjectionBindings;
- private final ImmutableList<LegacyBindingGraph> subgraphs;
-
- LegacyBindingGraph(
- ComponentDescriptor componentDescriptor,
- ImmutableMap<Key, ResolvedBindings> contributionBindings,
- ImmutableMap<Key, ResolvedBindings> membersInjectionBindings,
- ImmutableList<LegacyBindingGraph> subgraphs) {
- this.componentDescriptor = componentDescriptor;
- this.contributionBindings = contributionBindings;
- this.membersInjectionBindings = membersInjectionBindings;
- this.subgraphs = checkForDuplicates(subgraphs);
- }
-
- ComponentDescriptor componentDescriptor() {
- return componentDescriptor;
- }
-
- ResolvedBindings resolvedBindings(BindingRequest request) {
- return request.isRequestKind(RequestKind.MEMBERS_INJECTION)
- ? membersInjectionBindings.get(request.key())
- : contributionBindings.get(request.key());
- }
-
- Iterable<ResolvedBindings> resolvedBindings() {
- // Don't return an immutable collection - this is only ever used for looping over all bindings
- // in the graph. Copying is wasteful, especially if is a hashing collection, since the values
- // should all, by definition, be distinct.
- return Iterables.concat(membersInjectionBindings.values(), contributionBindings.values());
- }
-
- ImmutableList<LegacyBindingGraph> subgraphs() {
- return subgraphs;
- }
-
- private static ImmutableList<LegacyBindingGraph> checkForDuplicates(
- ImmutableList<LegacyBindingGraph> graphs) {
- Map<TypeElement, Collection<LegacyBindingGraph>> duplicateGraphs =
- Maps.filterValues(
- Multimaps.index(graphs, graph -> graph.componentDescriptor().typeElement()).asMap(),
- overlapping -> overlapping.size() > 1);
- if (!duplicateGraphs.isEmpty()) {
- throw new IllegalArgumentException("Expected no duplicates: " + duplicateGraphs);
- }
- return graphs;
- }
-}
diff --git a/java/dagger/internal/codegen/binding/MapKeys.java b/java/dagger/internal/codegen/binding/MapKeys.java
deleted file mode 100644
index ec7d79d..0000000
--- a/java/dagger/internal/codegen/binding/MapKeys.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.base.MapKeyAccessibility.isMapKeyPubliclyAccessible;
-import static dagger.internal.codegen.binding.SourceFiles.elementBasedClassName;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.MapKey;
-import dagger.internal.codegen.base.MapKeyAccessibility;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.NoSuchElementException;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleTypeVisitor6;
-
-/** Methods for extracting {@link MapKey} annotations and key code blocks from binding elements. */
-public final class MapKeys {
-
- /**
- * If {@code bindingElement} is annotated with a {@link MapKey} annotation, returns it.
- *
- * @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
- * annotation
- */
- static Optional<AnnotationMirror> getMapKey(Element bindingElement) {
- ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(bindingElement);
- return mapKeys.isEmpty()
- ? Optional.empty()
- : Optional.<AnnotationMirror>of(getOnlyElement(mapKeys));
- }
-
- /** Returns all of the {@link MapKey} annotations that annotate {@code bindingElement}. */
- public static ImmutableSet<? extends AnnotationMirror> getMapKeys(Element bindingElement) {
- return getAnnotatedAnnotations(bindingElement, MapKey.class);
- }
-
- /**
- * Returns the annotation value if {@code mapKey}'s type is annotated with
- * {@link MapKey @MapKey(unwrapValue = true)}.
- *
- * @throws IllegalArgumentException if {@code mapKey}'s type is not annotated with
- * {@link MapKey @MapKey} at all.
- */
- static Optional<? extends AnnotationValue> unwrapValue(AnnotationMirror mapKey) {
- MapKey mapKeyAnnotation = mapKey.getAnnotationType().asElement().getAnnotation(MapKey.class);
- checkArgument(
- mapKeyAnnotation != null, "%s is not annotated with @MapKey", mapKey.getAnnotationType());
- return mapKeyAnnotation.unwrapValue()
- ? Optional.of(getOnlyElement(getAnnotationValuesWithDefaults(mapKey).values()))
- : Optional.empty();
- }
-
- static TypeMirror mapKeyType(AnnotationMirror mapKeyAnnotation, DaggerTypes types) {
- return unwrapValue(mapKeyAnnotation).isPresent()
- ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
- : mapKeyAnnotation.getAnnotationType();
- }
-
- /**
- * Returns the map key type for an unwrapped {@link MapKey} annotation type. If the single member
- * type is primitive, returns the boxed type.
- *
- * @throws IllegalArgumentException if {@code mapKeyAnnotationType} is not an annotation type or
- * has more than one member, or if its single member is an array
- * @throws NoSuchElementException if the annotation has no members
- */
- public static DeclaredType getUnwrappedMapKeyType(
- final DeclaredType mapKeyAnnotationType, final DaggerTypes types) {
- checkArgument(
- MoreTypes.asTypeElement(mapKeyAnnotationType).getKind() == ElementKind.ANNOTATION_TYPE,
- "%s is not an annotation type",
- mapKeyAnnotationType);
-
- final ExecutableElement onlyElement =
- getOnlyElement(methodsIn(mapKeyAnnotationType.asElement().getEnclosedElements()));
-
- SimpleTypeVisitor6<DeclaredType, Void> keyTypeElementVisitor =
- new SimpleTypeVisitor6<DeclaredType, Void>() {
-
- @Override
- public DeclaredType visitArray(ArrayType t, Void p) {
- throw new IllegalArgumentException(
- mapKeyAnnotationType + "." + onlyElement.getSimpleName() + " cannot be an array");
- }
-
- @Override
- public DeclaredType visitPrimitive(PrimitiveType t, Void p) {
- return MoreTypes.asDeclared(types.boxedClass(t).asType());
- }
-
- @Override
- public DeclaredType visitDeclared(DeclaredType t, Void p) {
- return t;
- }
- };
- return keyTypeElementVisitor.visit(onlyElement.getReturnType());
- }
-
- /**
- * Returns a code block for {@code binding}'s {@link ContributionBinding#mapKeyAnnotation() map
- * key}. If for whatever reason the map key is not accessible from within {@code requestingClass}
- * (i.e. it has a package-private {@code enum} from a different package), this will return an
- * invocation of a proxy-method giving it access.
- *
- * @throws IllegalStateException if {@code binding} is not a {@link dagger.multibindings.IntoMap
- * map} contribution.
- */
- public static CodeBlock getMapKeyExpression(
- ContributionBinding binding, ClassName requestingClass, DaggerElements elements) {
- AnnotationMirror mapKeyAnnotation = binding.mapKeyAnnotation().get();
- return MapKeyAccessibility.isMapKeyAccessibleFrom(
- mapKeyAnnotation, requestingClass.packageName())
- ? directMapKeyExpression(mapKeyAnnotation, elements)
- : CodeBlock.of("$T.create()", mapKeyProxyClassName(binding));
- }
-
- /**
- * Returns a code block for the map key annotation {@code mapKey}.
- *
- * <p>This method assumes the map key will be accessible in the context that the returned {@link
- * CodeBlock} is used. Use {@link #getMapKeyExpression(ContributionBinding, ClassName,
- * DaggerElements)} when that assumption is not guaranteed.
- *
- * @throws IllegalArgumentException if the element is annotated with more than one {@code MapKey}
- * annotation
- * @throws IllegalStateException if {@code bindingElement} is not annotated with a {@code MapKey}
- * annotation
- */
- private static CodeBlock directMapKeyExpression(
- AnnotationMirror mapKey, DaggerElements elements) {
- Optional<? extends AnnotationValue> unwrappedValue = unwrapValue(mapKey);
- AnnotationExpression annotationExpression = new AnnotationExpression(mapKey);
-
- if (MoreTypes.asTypeElement(mapKey.getAnnotationType())
- .getQualifiedName()
- .contentEquals("dagger.android.AndroidInjectionKey")) {
- TypeElement unwrappedType =
- elements.checkTypePresent((String) unwrappedValue.get().getValue());
- return CodeBlock.of(
- "$T.of($S)",
- ClassName.get("dagger.android.internal", "AndroidInjectionKeys"),
- ClassName.get(unwrappedType).reflectionName());
- }
-
- if (unwrappedValue.isPresent()) {
- TypeMirror unwrappedValueType =
- getOnlyElement(getAnnotationValuesWithDefaults(mapKey).keySet()).getReturnType();
- return annotationExpression.getValueExpression(unwrappedValueType, unwrappedValue.get());
- } else {
- return annotationExpression.getAnnotationInstanceExpression();
- }
- }
-
- /**
- * Returns the {@link ClassName} in which {@link #mapKeyFactoryMethod(ContributionBinding,
- * DaggerTypes, DaggerElements)} is generated.
- */
- public static ClassName mapKeyProxyClassName(ContributionBinding binding) {
- return elementBasedClassName(
- MoreElements.asExecutable(binding.bindingElement().get()), "MapKey");
- }
-
- /**
- * A {@code static create()} method to be added to {@link
- * #mapKeyProxyClassName(ContributionBinding)} when the {@code @MapKey} annotation is not publicly
- * accessible.
- */
- public static Optional<MethodSpec> mapKeyFactoryMethod(
- ContributionBinding binding, DaggerTypes types, DaggerElements elements) {
- return binding
- .mapKeyAnnotation()
- .filter(mapKey -> !isMapKeyPubliclyAccessible(mapKey))
- .map(
- mapKey ->
- methodBuilder("create")
- .addModifiers(PUBLIC, STATIC)
- .returns(TypeName.get(mapKeyType(mapKey, types)))
- .addStatement("return $L", directMapKeyExpression(mapKey, elements))
- .build());
- }
-
- private MapKeys() {}
-}
diff --git a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java b/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
deleted file mode 100644
index 3dd1016..0000000
--- a/java/dagger/internal/codegen/binding/MembersInjectionBinding.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static java.util.stream.Collectors.toList;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import java.util.Optional;
-import javax.inject.Inject;
-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;
-
-/** Represents the full members injection of a particular type. */
-@AutoValue
-public abstract class MembersInjectionBinding extends Binding {
- @Override
- public final Optional<Element> bindingElement() {
- return Optional.of(membersInjectedType());
- }
-
- public abstract TypeElement membersInjectedType();
-
- @Override
- public abstract Optional<MembersInjectionBinding> unresolved();
-
- @Override
- public Optional<TypeElement> contributingModule() {
- return Optional.empty();
- }
-
- /** The set of individual sites where {@link Inject} is applied. */
- public abstract ImmutableSortedSet<InjectionSite> injectionSites();
-
- @Override
- public BindingType bindingType() {
- return BindingType.MEMBERS_INJECTION;
- }
-
- @Override
- public BindingKind kind() {
- return BindingKind.MEMBERS_INJECTION;
- }
-
- @Override
- public boolean isNullable() {
- return false;
- }
-
- /**
- * Returns {@code true} if any of this binding's injection sites are directly on the bound type.
- */
- public boolean hasLocalInjectionSites() {
- return injectionSites()
- .stream()
- .anyMatch(
- injectionSite ->
- injectionSite.element().getEnclosingElement().equals(membersInjectedType()));
- }
-
- @Override
- public boolean requiresModuleInstance() {
- return false;
- }
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- // TODO(ronshapiro,dpb): simplify the equality semantics
- @Override
- public abstract boolean equals(Object obj);
-
- /** Metadata about a field or method injection site. */
- @AutoValue
- public abstract static class InjectionSite {
- /** The type of injection site. */
- public enum Kind {
- FIELD,
- METHOD,
- }
-
- public abstract Kind kind();
-
- public abstract Element element();
-
- public abstract ImmutableSet<DependencyRequest> dependencies();
-
- /**
- * Returns the index of {@link #element()} in its parents {@code @Inject} members that have the
- * same simple name. This method filters out private elements so that the results will be
- * consistent independent of whether the build system uses header jars or not.
- */
- @Memoized
- public int indexAmongAtInjectMembersWithSameSimpleName() {
- return element()
- .getEnclosingElement()
- .getEnclosedElements()
- .stream()
- .filter(element -> isAnnotationPresent(element, Inject.class))
- .filter(element -> !element.getModifiers().contains(Modifier.PRIVATE))
- .filter(element -> element.getSimpleName().equals(this.element().getSimpleName()))
- .collect(toList())
- .indexOf(element());
- }
-
- public static InjectionSite field(VariableElement element, DependencyRequest dependency) {
- return new AutoValue_MembersInjectionBinding_InjectionSite(
- Kind.FIELD, element, ImmutableSet.of(dependency));
- }
-
- public static InjectionSite method(
- ExecutableElement element, Iterable<DependencyRequest> dependencies) {
- return new AutoValue_MembersInjectionBinding_InjectionSite(
- Kind.METHOD, element, ImmutableSet.copyOf(dependencies));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java b/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
deleted file mode 100644
index 97c680f..0000000
--- a/java/dagger/internal/codegen/binding/MethodSignatureFormatter.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.Preconditions.checkState;
-import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import dagger.internal.codegen.base.Formatter;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
-import javax.inject.Inject;
-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.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/** Formats the signature of an {@link ExecutableElement} suitable for use in error messages. */
-public final class MethodSignatureFormatter extends Formatter<ExecutableElement> {
- private final DaggerTypes types;
- private final InjectionAnnotations injectionAnnotations;
-
- @Inject
- public MethodSignatureFormatter(DaggerTypes types, InjectionAnnotations injectionAnnotations) {
- this.types = types;
- this.injectionAnnotations = injectionAnnotations;
- }
-
- /**
- * A formatter that uses the type where the method is declared for the annotations and name of the
- * method, but the method's resolved type as a member of {@code declaredType} for the key.
- */
- public Formatter<ExecutableElement> typedFormatter(DeclaredType declaredType) {
- return new Formatter<ExecutableElement>() {
- @Override
- public String format(ExecutableElement method) {
- return MethodSignatureFormatter.this.format(
- method,
- MoreTypes.asExecutable(types.asMemberOf(declaredType, method)),
- MoreElements.asType(method.getEnclosingElement()));
- }
- };
- }
-
- @Override
- public String format(ExecutableElement method) {
- return format(method, Optional.empty());
- }
-
- /**
- * Formats an ExecutableElement as if it were contained within the container, if the container is
- * present.
- */
- public String format(ExecutableElement method, Optional<DeclaredType> container) {
- TypeElement type = MoreElements.asType(method.getEnclosingElement());
- ExecutableType executableType = MoreTypes.asExecutable(method.asType());
- if (container.isPresent()) {
- executableType = MoreTypes.asExecutable(types.asMemberOf(container.get(), method));
- type = MoreElements.asType(container.get().asElement());
- }
- return format(method, executableType, type);
- }
-
- private String format(
- ExecutableElement method, ExecutableType methodType, TypeElement declaringType) {
- StringBuilder builder = new StringBuilder();
- // TODO(user): AnnotationMirror formatter.
- List<? extends AnnotationMirror> annotations = method.getAnnotationMirrors();
- if (!annotations.isEmpty()) {
- Iterator<? extends AnnotationMirror> annotationIterator = annotations.iterator();
- for (int i = 0; annotationIterator.hasNext(); i++) {
- if (i > 0) {
- builder.append(' ');
- }
- builder.append(formatAnnotation(annotationIterator.next()));
- }
- builder.append(' ');
- }
- if (method.getSimpleName().contentEquals("<init>")) {
- builder.append(declaringType.getQualifiedName());
- } else {
- builder
- .append(nameOfType(methodType.getReturnType()))
- .append(' ')
- .append(declaringType.getQualifiedName())
- .append('.')
- .append(method.getSimpleName());
- }
- builder.append('(');
- checkState(method.getParameters().size() == methodType.getParameterTypes().size());
- Iterator<? extends VariableElement> parameters = method.getParameters().iterator();
- Iterator<? extends TypeMirror> parameterTypes = methodType.getParameterTypes().iterator();
- for (int i = 0; parameters.hasNext(); i++) {
- if (i > 0) {
- builder.append(", ");
- }
- appendParameter(builder, parameters.next(), parameterTypes.next());
- }
- builder.append(')');
- return builder.toString();
- }
-
- private void appendParameter(StringBuilder builder, VariableElement parameter, TypeMirror type) {
- injectionAnnotations
- .getQualifier(parameter)
- .ifPresent(
- qualifier -> {
- builder.append(formatAnnotation(qualifier)).append(' ');
- });
- builder.append(nameOfType(type));
- }
-
- private static String nameOfType(TypeMirror type) {
- return stripCommonTypePrefixes(type.toString());
- }
-
- private static String formatAnnotation(AnnotationMirror annotation) {
- return stripCommonTypePrefixes(annotation.toString());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ModuleDescriptor.java b/java/dagger/internal/codegen/binding/ModuleDescriptor.java
deleted file mode 100644
index c471f94..0000000
--- a/java/dagger/internal/codegen/binding/ModuleDescriptor.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.getPackage;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.transform;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.SourceFiles.classFileName;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getMethodDescriptor;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.NONE;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.graph.Traverser;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.squareup.javapoet.ClassName;
-import dagger.Binds;
-import dagger.BindsOptionalOf;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.Key;
-import dagger.multibindings.Multibinds;
-import dagger.producers.Produces;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** Contains metadata that describes a module. */
-@AutoValue
-public abstract class ModuleDescriptor {
-
- public abstract TypeElement moduleElement();
-
- abstract ImmutableSet<TypeElement> includedModules();
-
- public abstract ImmutableSet<ContributionBinding> bindings();
-
- /** The multibinding declarations contained in this module. */
- abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
-
- /** The {@link Module#subcomponents() subcomponent declarations} contained in this module. */
- abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
-
- /** The {@link Binds} method declarations that define delegate bindings. */
- abstract ImmutableSet<DelegateDeclaration> delegateDeclarations();
-
- /** The {@link BindsOptionalOf} method declarations that define optional bindings. */
- abstract ImmutableSet<OptionalBindingDeclaration> optionalDeclarations();
-
- /** The kind of the module. */
- public abstract ModuleKind kind();
-
- /** Returns all of the bindings declared in this module. */
- @Memoized
- public ImmutableSet<BindingDeclaration> allBindingDeclarations() {
- return ImmutableSet.<BindingDeclaration>builder()
- .addAll(bindings())
- .addAll(delegateDeclarations())
- .addAll(multibindingDeclarations())
- .addAll(optionalDeclarations())
- .addAll(subcomponentDeclarations())
- .build();
- }
-
- /** Returns the keys of all bindings declared by this module. */
- ImmutableSet<Key> allBindingKeys() {
- return allBindingDeclarations().stream().map(BindingDeclaration::key).collect(toImmutableSet());
- }
-
- /** A {@link ModuleDescriptor} factory. */
- @Singleton
- public static final class Factory implements ClearableCache {
- private final DaggerElements elements;
- private final KotlinMetadataUtil metadataUtil;
- private final BindingFactory bindingFactory;
- private final MultibindingDeclaration.Factory multibindingDeclarationFactory;
- private final DelegateDeclaration.Factory bindingDelegateDeclarationFactory;
- private final SubcomponentDeclaration.Factory subcomponentDeclarationFactory;
- private final OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory;
- private final Map<TypeElement, ModuleDescriptor> cache = new HashMap<>();
-
- @Inject
- Factory(
- DaggerElements elements,
- KotlinMetadataUtil metadataUtil,
- BindingFactory bindingFactory,
- MultibindingDeclaration.Factory multibindingDeclarationFactory,
- DelegateDeclaration.Factory bindingDelegateDeclarationFactory,
- SubcomponentDeclaration.Factory subcomponentDeclarationFactory,
- OptionalBindingDeclaration.Factory optionalBindingDeclarationFactory) {
- this.elements = elements;
- this.metadataUtil = metadataUtil;
- this.bindingFactory = bindingFactory;
- this.multibindingDeclarationFactory = multibindingDeclarationFactory;
- this.bindingDelegateDeclarationFactory = bindingDelegateDeclarationFactory;
- this.subcomponentDeclarationFactory = subcomponentDeclarationFactory;
- this.optionalBindingDeclarationFactory = optionalBindingDeclarationFactory;
- }
-
- public ModuleDescriptor create(TypeElement moduleElement) {
- return reentrantComputeIfAbsent(cache, moduleElement, this::createUncached);
- }
-
- public ModuleDescriptor createUncached(TypeElement moduleElement) {
- ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
- ImmutableSet.Builder<DelegateDeclaration> delegates = ImmutableSet.builder();
- ImmutableSet.Builder<MultibindingDeclaration> multibindingDeclarations =
- ImmutableSet.builder();
- ImmutableSet.Builder<OptionalBindingDeclaration> optionalDeclarations =
- ImmutableSet.builder();
-
- for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
- if (isAnnotationPresent(moduleMethod, Provides.class)) {
- bindings.add(bindingFactory.providesMethodBinding(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, Produces.class)) {
- bindings.add(bindingFactory.producesMethodBinding(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, Binds.class)) {
- delegates.add(bindingDelegateDeclarationFactory.create(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, Multibinds.class)) {
- multibindingDeclarations.add(
- multibindingDeclarationFactory.forMultibindsMethod(moduleMethod, moduleElement));
- }
- if (isAnnotationPresent(moduleMethod, BindsOptionalOf.class)) {
- optionalDeclarations.add(
- optionalBindingDeclarationFactory.forMethod(moduleMethod, moduleElement));
- }
- }
-
- if (metadataUtil.hasEnclosedCompanionObject(moduleElement)) {
- collectCompanionModuleBindings(moduleElement, bindings);
- }
-
- return new AutoValue_ModuleDescriptor(
- moduleElement,
- ImmutableSet.copyOf(collectIncludedModules(new LinkedHashSet<>(), moduleElement)),
- bindings.build(),
- multibindingDeclarations.build(),
- subcomponentDeclarationFactory.forModule(moduleElement),
- delegates.build(),
- optionalDeclarations.build(),
- ModuleKind.forAnnotatedElement(moduleElement).get());
- }
-
- private void collectCompanionModuleBindings(
- TypeElement moduleElement, ImmutableSet.Builder<ContributionBinding> bindings) {
- checkArgument(metadataUtil.hasEnclosedCompanionObject(moduleElement));
- TypeElement companionModule = metadataUtil.getEnclosedCompanionObject(moduleElement);
- ImmutableSet<String> bindingElementDescriptors =
- bindings.build().stream()
- .map(binding -> getMethodDescriptor(asExecutable(binding.bindingElement().get())))
- .collect(toImmutableSet());
- methodsIn(elements.getAllMembers(companionModule)).stream()
- // Binding methods in companion objects with @JvmStatic are mirrored in the enclosing
- // class, therefore we should ignore it or else it'll be a duplicate binding.
- .filter(method -> !KotlinMetadataUtil.isJvmStaticPresent(method))
- // Fallback strategy for de-duping contributing bindings in the companion module with
- // @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)))
- .forEach(
- method -> {
- if (isAnnotationPresent(method, Provides.class)) {
- bindings.add(bindingFactory.providesMethodBinding(method, companionModule));
- }
- if (isAnnotationPresent(method, Produces.class)) {
- bindings.add(bindingFactory.producesMethodBinding(method, companionModule));
- }
- });
- }
-
- /** Returns all the modules transitively included by given modules, including the arguments. */
- ImmutableSet<ModuleDescriptor> transitiveModules(Iterable<TypeElement> modules) {
- return ImmutableSet.copyOf(
- Traverser.forGraph(
- (ModuleDescriptor module) -> transform(module.includedModules(), this::create))
- .depthFirstPreOrder(transform(modules, this::create)));
- }
-
- @CanIgnoreReturnValue
- private Set<TypeElement> collectIncludedModules(
- Set<TypeElement> includedModules, TypeElement moduleElement) {
- TypeMirror superclass = moduleElement.getSuperclass();
- if (!superclass.getKind().equals(NONE)) {
- verify(superclass.getKind().equals(DECLARED));
- TypeElement superclassElement = MoreTypes.asTypeElement(superclass);
- if (!superclassElement.getQualifiedName().contentEquals(Object.class.getCanonicalName())) {
- collectIncludedModules(includedModules, superclassElement);
- }
- }
- moduleAnnotation(moduleElement)
- .ifPresent(
- moduleAnnotation -> {
- includedModules.addAll(moduleAnnotation.includes());
- includedModules.addAll(implicitlyIncludedModules(moduleElement));
- });
- return includedModules;
- }
-
- // @ContributesAndroidInjector generates a module that is implicitly included in the enclosing
- // module
- private ImmutableSet<TypeElement> implicitlyIncludedModules(TypeElement moduleElement) {
- TypeElement contributesAndroidInjector =
- elements.getTypeElement("dagger.android.ContributesAndroidInjector");
- if (contributesAndroidInjector == null) {
- return ImmutableSet.of();
- }
- return methodsIn(moduleElement.getEnclosedElements()).stream()
- .filter(method -> isAnnotationPresent(method, contributesAndroidInjector.asType()))
- .map(method -> elements.checkTypePresent(implicitlyIncludedModuleName(method)))
- .collect(toImmutableSet());
- }
-
- private String implicitlyIncludedModuleName(ExecutableElement method) {
- return getPackage(method).getQualifiedName()
- + "."
- + classFileName(ClassName.get(MoreElements.asType(method.getEnclosingElement())))
- + "_"
- + LOWER_CAMEL.to(UPPER_CAMEL, method.getSimpleName().toString());
- }
-
- @Override
- public void clearCache() {
- cache.clear();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ModuleKind.java b/java/dagger/internal/codegen/binding/ModuleKind.java
deleted file mode 100644
index 6b52f04..0000000
--- a/java/dagger/internal/codegen/binding/ModuleKind.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import dagger.Module;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.producers.ProducerModule;
-import java.lang.annotation.Annotation;
-import java.util.EnumSet;
-import java.util.Optional;
-import java.util.Set;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.TypeElement;
-
-/** Enumeration of the kinds of modules. */
-public enum ModuleKind {
- /** {@code @Module} */
- MODULE(Module.class),
-
- /** {@code @ProducerModule} */
- PRODUCER_MODULE(ProducerModule.class);
-
- /** Returns the annotations for modules of the given kinds. */
- public static ImmutableSet<Class<? extends Annotation>> annotationsFor(Set<ModuleKind> kinds) {
- return kinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
- }
-
- /**
- * Returns the kind of an annotated element if it is annotated with one of the module {@linkplain
- * #annotation() annotations}.
- *
- * @throws IllegalArgumentException if the element is annotated with more than one of the module
- * annotations
- */
- public static Optional<ModuleKind> forAnnotatedElement(TypeElement element) {
- Set<ModuleKind> kinds = EnumSet.noneOf(ModuleKind.class);
- for (ModuleKind kind : values()) {
- if (MoreElements.isAnnotationPresent(element, kind.annotation())) {
- kinds.add(kind);
- }
- }
-
- if (kinds.size() > 1) {
- throw new IllegalArgumentException(
- element + " cannot be annotated with more than one of " + annotationsFor(kinds));
- }
- return kinds.stream().findAny();
- }
-
- public static void checkIsModule(TypeElement moduleElement, KotlinMetadataUtil metadataUtil) {
- // If the type element is a Kotlin companion object, then assert it is a module if its enclosing
- // type is a module.
- if (metadataUtil.isCompanionObjectClass(moduleElement)) {
- checkArgument(forAnnotatedElement(asType(moduleElement.getEnclosingElement())).isPresent());
- } else {
- checkArgument(forAnnotatedElement(moduleElement).isPresent());
- }
- }
-
- private final Class<? extends Annotation> moduleAnnotation;
-
- ModuleKind(Class<? extends Annotation> moduleAnnotation) {
- this.moduleAnnotation = moduleAnnotation;
- }
-
- /**
- * Returns the annotation mirror for this module kind on the given type.
- *
- * @throws IllegalArgumentException if the annotation is not present on the type
- */
- public AnnotationMirror getModuleAnnotation(TypeElement element) {
- Optional<AnnotationMirror> result = getAnnotationMirror(element, moduleAnnotation);
- checkArgument(
- result.isPresent(), "annotation %s is not present on type %s", moduleAnnotation, element);
- return result.get();
- }
-
- /** Returns the annotation that marks a module of this kind. */
- public Class<? extends Annotation> annotation() {
- return moduleAnnotation;
- }
-
- /** Returns the kinds of modules that a module of this kind is allowed to include. */
- public ImmutableSet<ModuleKind> legalIncludedModuleKinds() {
- switch (this) {
- case MODULE:
- return Sets.immutableEnumSet(MODULE);
- case PRODUCER_MODULE:
- return Sets.immutableEnumSet(MODULE, PRODUCER_MODULE);
- }
- throw new AssertionError(this);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java b/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
deleted file mode 100644
index f1d3f8d..0000000
--- a/java/dagger/internal/codegen/binding/MultibindingDeclaration.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.ContributionType.HasContributionType;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.multibindings.Multibinds;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A declaration that a multibinding with a certain key is available to be injected in a component
- * even if the component has no multibindings for that key. Identified by a map- or set-returning
- * method annotated with {@link Multibinds @Multibinds}.
- */
-@AutoValue
-public abstract class MultibindingDeclaration extends BindingDeclaration
- implements HasContributionType {
-
- /**
- * The map or set key whose availability is declared. For maps, this will be {@code Map<K,
- * Provider<V>>}. For sets, this will be {@code Set<T>}.
- */
- @Override
- public abstract Key key();
-
- /**
- * {@link ContributionType#SET} if the declared type is a {@link Set}, or
- * {@link ContributionType#MAP} if it is a {@link Map}.
- */
- @Override
- public abstract ContributionType contributionType();
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object obj);
-
- /** A factory for {@link MultibindingDeclaration}s. */
- public static final class Factory {
- private final DaggerTypes types;
- private final KeyFactory keyFactory;
-
- @Inject
- Factory(DaggerTypes types, KeyFactory keyFactory) {
- this.types = types;
- this.keyFactory = keyFactory;
- }
-
- /** A multibinding declaration for a {@link Multibinds @Multibinds} method. */
- MultibindingDeclaration forMultibindsMethod(
- ExecutableElement moduleMethod, TypeElement moduleElement) {
- checkArgument(isAnnotationPresent(moduleMethod, Multibinds.class));
- return forDeclaredMethod(
- moduleMethod,
- MoreTypes.asExecutable(
- types.asMemberOf(MoreTypes.asDeclared(moduleElement.asType()), moduleMethod)),
- moduleElement);
- }
-
- private MultibindingDeclaration forDeclaredMethod(
- ExecutableElement method,
- ExecutableType methodType,
- TypeElement contributingType) {
- TypeMirror returnType = methodType.getReturnType();
- checkArgument(
- SetType.isSet(returnType) || MapType.isMap(returnType),
- "%s must return a set or map",
- method);
- return new AutoValue_MultibindingDeclaration(
- Optional.<Element>of(method),
- Optional.of(contributingType),
- keyFactory.forMultibindsMethod(methodType, method),
- contributionType(returnType));
- }
-
- private ContributionType contributionType(TypeMirror returnType) {
- if (MapType.isMap(returnType)) {
- return ContributionType.MAP;
- } else if (SetType.isSet(returnType)) {
- return ContributionType.SET;
- } else {
- throw new IllegalArgumentException("Must be Map or Set: " + returnType);
- }
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java b/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
deleted file mode 100644
index d7ba7bc..0000000
--- a/java/dagger/internal/codegen/binding/OptionalBindingDeclaration.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import dagger.BindsOptionalOf;
-import dagger.model.Key;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-
-/** A {@link BindsOptionalOf} declaration. */
-@AutoValue
-abstract class OptionalBindingDeclaration extends BindingDeclaration {
-
- /**
- * {@inheritDoc}
- *
- * <p>The key's type is the method's return type, even though the synthetic bindings will be for
- * {@code Optional} of derived types.
- */
- @Override
- public abstract Key key();
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object obj);
-
- static class Factory {
- private final KeyFactory keyFactory;
-
- @Inject
- Factory(KeyFactory keyFactory) {
- this.keyFactory = keyFactory;
- }
-
- OptionalBindingDeclaration forMethod(ExecutableElement method, TypeElement contributingModule) {
- checkArgument(isAnnotationPresent(method, BindsOptionalOf.class));
- return new AutoValue_OptionalBindingDeclaration(
- Optional.<Element>of(method),
- Optional.of(contributingModule),
- keyFactory.forBindsOptionalOfMethod(method, contributingModule));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ProductionBinding.java b/java/dagger/internal/codegen/binding/ProductionBinding.java
deleted file mode 100644
index ad85a68..0000000
--- a/java/dagger/internal/codegen/binding/ProductionBinding.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType;
-
-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.ImmutableSet;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.SetType;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import java.util.Optional;
-import java.util.stream.Stream;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A value object representing the mechanism by which a {@link Key} can be produced. */
-@AutoValue
-public abstract class ProductionBinding extends ContributionBinding {
-
- @Override
- public BindingType bindingType() {
- return BindingType.PRODUCTION;
- }
-
- @Override
- public abstract Optional<ProductionBinding> unresolved();
-
- @Override
- public ImmutableSet<DependencyRequest> implicitDependencies() {
- return Stream.of(executorRequest(), monitorRequest())
- .filter(Optional::isPresent)
- .map(Optional::get)
- .collect(toImmutableSet());
- }
-
- /** What kind of object a {@code @Produces}-annotated method returns. */
- public enum ProductionKind {
- /** A value. */
- IMMEDIATE,
- /** A {@code ListenableFuture<T>}. */
- FUTURE,
- /** A {@code Set<ListenableFuture<T>>}. */
- SET_OF_FUTURE;
-
- /** Returns the kind of object a {@code @Produces}-annotated method returns. */
- public static ProductionKind fromProducesMethod(ExecutableElement producesMethod) {
- if (isFutureType(producesMethod.getReturnType())) {
- return FUTURE;
- } else if (ContributionType.fromBindingElement(producesMethod)
- .equals(ContributionType.SET_VALUES)
- && isFutureType(SetType.from(producesMethod.getReturnType()).elementType())) {
- return SET_OF_FUTURE;
- } else {
- return IMMEDIATE;
- }
- }
- }
-
- /**
- * Returns the kind of object the produces method returns. All production bindings from
- * {@code @Produces} methods will have a production kind, but synthetic production bindings may
- * not.
- */
- public abstract Optional<ProductionKind> productionKind();
-
- /** Returns the list of types in the throws clause of the method. */
- public abstract ImmutableList<? extends TypeMirror> thrownTypes();
-
- /**
- * If this production requires an executor, this will be the corresponding request. All
- * production bindings from {@code @Produces} methods will have an executor request, but
- * synthetic production bindings may not.
- */
- abstract Optional<DependencyRequest> executorRequest();
-
- /** If this production requires a monitor, this will be the corresponding request. All
- * production bindings from {@code @Produces} methods will have a monitor request, but synthetic
- * production bindings may not.
- */
- abstract Optional<DependencyRequest> monitorRequest();
-
- // Profiling determined that this method is called enough times that memoizing it had a measurable
- // performance improvement for large components.
- @Memoized
- @Override
- public boolean requiresModuleInstance() {
- return super.requiresModuleInstance();
- }
-
- public static Builder builder() {
- return new AutoValue_ProductionBinding.Builder()
- .explicitDependencies(ImmutableList.<DependencyRequest>of())
- .thrownTypes(ImmutableList.<TypeMirror>of());
- }
-
- @Override
- public abstract Builder toBuilder();
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- // TODO(ronshapiro,dpb): simplify the equality semantics
- @Override
- public abstract boolean equals(Object obj);
-
- /** A {@link ProductionBinding} builder. */
- @AutoValue.Builder
- @CanIgnoreReturnValue
- public abstract static class Builder
- extends ContributionBinding.Builder<ProductionBinding, Builder> {
-
- @Override
- public Builder dependencies(Iterable<DependencyRequest> dependencies) {
- return explicitDependencies(dependencies);
- }
-
- abstract Builder explicitDependencies(Iterable<DependencyRequest> dependencies);
-
- abstract Builder productionKind(ProductionKind productionKind);
-
- @Override
- public abstract Builder unresolved(ProductionBinding unresolved);
-
- abstract Builder thrownTypes(Iterable<? extends TypeMirror> thrownTypes);
-
- abstract Builder executorRequest(DependencyRequest executorRequest);
-
- abstract Builder monitorRequest(DependencyRequest monitorRequest);
- }
-}
diff --git a/java/dagger/internal/codegen/binding/ProvisionBinding.java b/java/dagger/internal/codegen/binding/ProvisionBinding.java
deleted file mode 100644
index c917dd6..0000000
--- a/java/dagger/internal/codegen/binding/ProvisionBinding.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2014 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 dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.model.BindingKind.COMPONENT_PROVISION;
-import static dagger.model.BindingKind.PROVISION;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.Scope;
-import java.util.Optional;
-
-/** A value object representing the mechanism by which a {@link Key} can be provided. */
-@AutoValue
-public abstract class ProvisionBinding extends ContributionBinding {
-
- @Override
- @Memoized
- public ImmutableSet<DependencyRequest> explicitDependencies() {
- return ImmutableSet.<DependencyRequest>builder()
- .addAll(provisionDependencies())
- .addAll(membersInjectionDependencies())
- .build();
- }
-
- /**
- * Dependencies necessary to invoke an {@code @Inject} constructor or {@code @Provides} method.
- */
- public abstract ImmutableSet<DependencyRequest> provisionDependencies();
-
- @Memoized
- ImmutableSet<DependencyRequest> membersInjectionDependencies() {
- return injectionSites()
- .stream()
- .flatMap(i -> i.dependencies().stream())
- .collect(toImmutableSet());
- }
-
- /**
- * {@link InjectionSite}s for all {@code @Inject} members if {@link #kind()} is {@link
- * BindingKind#INJECTION}, otherwise empty.
- */
- public abstract ImmutableSortedSet<InjectionSite> injectionSites();
-
- @Override
- public BindingType bindingType() {
- return BindingType.PROVISION;
- }
-
- @Override
- public abstract Optional<ProvisionBinding> unresolved();
-
- // TODO(ronshapiro): we should be able to remove this, but AutoValue barks on the Builder's scope
- // method, saying that the method doesn't correspond to a property of ProvisionBinding
- @Override
- public abstract Optional<Scope> scope();
-
- public static Builder builder() {
- return new AutoValue_ProvisionBinding.Builder()
- .provisionDependencies(ImmutableSet.of())
- .injectionSites(ImmutableSortedSet.of());
- }
-
- @Override
- public abstract Builder toBuilder();
-
- private static final ImmutableSet<BindingKind> KINDS_TO_CHECK_FOR_NULL =
- ImmutableSet.of(PROVISION, COMPONENT_PROVISION);
-
- public boolean shouldCheckForNull(CompilerOptions compilerOptions) {
- return KINDS_TO_CHECK_FOR_NULL.contains(kind())
- && !contributedPrimitiveType().isPresent()
- && !nullableType().isPresent()
- && compilerOptions.doCheckForNulls();
- }
-
- // Profiling determined that this method is called enough times that memoizing it had a measurable
- // performance improvement for large components.
- @Memoized
- @Override
- public boolean requiresModuleInstance() {
- return super.requiresModuleInstance();
- }
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- // TODO(ronshapiro,dpb): simplify the equality semantics
- @Override
- public abstract boolean equals(Object obj);
-
- /** A {@link ProvisionBinding} builder. */
- @AutoValue.Builder
- @CanIgnoreReturnValue
- public abstract static class Builder
- extends ContributionBinding.Builder<ProvisionBinding, Builder> {
-
- @Override
- public Builder dependencies(Iterable<DependencyRequest> dependencies) {
- return provisionDependencies(dependencies);
- }
-
- abstract Builder provisionDependencies(Iterable<DependencyRequest> provisionDependencies);
-
- public abstract Builder injectionSites(ImmutableSortedSet<InjectionSite> injectionSites);
-
- @Override
- public abstract Builder unresolved(ProvisionBinding unresolved);
-
- public abstract Builder scope(Optional<Scope> scope);
- }
-
-}
diff --git a/java/dagger/internal/codegen/binding/ResolvedBindings.java b/java/dagger/internal/codegen/binding/ResolvedBindings.java
deleted file mode 100644
index 74301fe..0000000
--- a/java/dagger/internal/codegen/binding/ResolvedBindings.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.binding;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimap;
-import dagger.model.Key;
-import javax.lang.model.element.TypeElement;
-
-/**
- * The collection of bindings that have been resolved for a key. For valid graphs, contains exactly
- * one binding.
- *
- * <p>Separate {@link ResolvedBindings} instances should be used if a {@link
- * MembersInjectionBinding} and a {@link ProvisionBinding} for the same key exist in the same
- * component. (This will only happen if a type has an {@code @Inject} constructor and members, the
- * component has a members injection method, and the type is also requested normally.)
- */
-@AutoValue
-abstract class ResolvedBindings {
- /** The binding key for which the {@link #bindings()} have been resolved. */
- abstract Key key();
-
- /**
- * The {@link ContributionBinding}s for {@link #key()} indexed by the component that owns the
- * binding. Each key in the multimap is a part of the same component ancestry.
- */
- abstract ImmutableSetMultimap<TypeElement, ContributionBinding> allContributionBindings();
-
- /**
- * The {@link MembersInjectionBinding}s for {@link #key()} indexed by the component that owns the
- * binding. Each key in the map is a part of the same component ancestry.
- */
- abstract ImmutableMap<TypeElement, MembersInjectionBinding> allMembersInjectionBindings();
-
- /** The multibinding declarations for {@link #key()}. */
- abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
-
- /** The subcomponent declarations for {@link #key()}. */
- abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
-
- /** The optional binding declarations for {@link #key()}. */
- abstract ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations();
-
- // Computing the hash code is an expensive operation.
- @Memoized
- @Override
- public abstract int hashCode();
-
- // Suppresses ErrorProne warning that hashCode was overridden w/o equals
- @Override
- public abstract boolean equals(Object other);
-
- /** All bindings for {@link #key()}, indexed by the component that owns the binding. */
- final ImmutableSetMultimap<TypeElement, ? extends Binding> allBindings() {
- return !allMembersInjectionBindings().isEmpty()
- ? allMembersInjectionBindings().asMultimap()
- : allContributionBindings();
- }
-
- /** All bindings for {@link #key()}, regardless of which component owns them. */
- final ImmutableCollection<? extends Binding> bindings() {
- return allBindings().values();
- }
-
- /**
- * {@code true} if there are no {@link #bindings()}, {@link #multibindingDeclarations()}, {@link
- * #optionalBindingDeclarations()}, or {@link #subcomponentDeclarations()}.
- */
- final boolean isEmpty() {
- return allMembersInjectionBindings().isEmpty()
- && allContributionBindings().isEmpty()
- && multibindingDeclarations().isEmpty()
- && optionalBindingDeclarations().isEmpty()
- && subcomponentDeclarations().isEmpty();
- }
-
- /** All bindings for {@link #key()} that are owned by a component. */
- ImmutableSet<? extends Binding> bindingsOwnedBy(ComponentDescriptor component) {
- return allBindings().get(component.typeElement());
- }
-
- /**
- * All contribution bindings, regardless of owning component. Empty if this is a members-injection
- * binding.
- */
- @Memoized
- ImmutableSet<ContributionBinding> contributionBindings() {
- // TODO(ronshapiro): consider optimizing ImmutableSet.copyOf(Collection) for small immutable
- // collections so that it doesn't need to call toArray(). Even though this method is memoized,
- // toArray() can take ~150ms for large components, and there are surely other places in the
- // processor that can benefit from this.
- return ImmutableSet.copyOf(allContributionBindings().values());
- }
-
- /** The component that owns {@code binding}. */
- final TypeElement owningComponent(ContributionBinding binding) {
- checkArgument(
- contributionBindings().contains(binding),
- "binding is not resolved for %s: %s",
- key(),
- binding);
- return getOnlyElement(allContributionBindings().inverse().get(binding));
- }
-
- /** Creates a {@link ResolvedBindings} for contribution bindings. */
- static ResolvedBindings forContributionBindings(
- Key key,
- Multimap<TypeElement, ContributionBinding> contributionBindings,
- Iterable<MultibindingDeclaration> multibindings,
- Iterable<SubcomponentDeclaration> subcomponentDeclarations,
- Iterable<OptionalBindingDeclaration> optionalBindingDeclarations) {
- return new AutoValue_ResolvedBindings(
- key,
- ImmutableSetMultimap.copyOf(contributionBindings),
- ImmutableMap.of(),
- ImmutableSet.copyOf(multibindings),
- ImmutableSet.copyOf(subcomponentDeclarations),
- ImmutableSet.copyOf(optionalBindingDeclarations));
- }
-
- /**
- * Creates a {@link ResolvedBindings} for members injection bindings.
- */
- static ResolvedBindings forMembersInjectionBinding(
- Key key,
- ComponentDescriptor owningComponent,
- MembersInjectionBinding ownedMembersInjectionBinding) {
- return new AutoValue_ResolvedBindings(
- key,
- ImmutableSetMultimap.of(),
- ImmutableMap.of(owningComponent.typeElement(), ownedMembersInjectionBinding),
- ImmutableSet.of(),
- ImmutableSet.of(),
- ImmutableSet.of());
- }
-
- /**
- * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key.
- */
- static ResolvedBindings noBindings(Key key) {
- return new AutoValue_ResolvedBindings(
- key,
- ImmutableSetMultimap.of(),
- ImmutableMap.of(),
- ImmutableSet.of(),
- ImmutableSet.of(),
- ImmutableSet.of());
- }
-}
diff --git a/java/dagger/internal/codegen/binding/SourceFiles.java b/java/dagger/internal/codegen/binding/SourceFiles.java
deleted file mode 100644
index 3b6d9d9..0000000
--- a/java/dagger/internal/codegen/binding/SourceFiles.java
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCED_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_OF_PRODUCER_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_PROVIDER_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER_OF_LAZY;
-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.model.BindingKind.ASSISTED_INJECTION;
-import static dagger.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.model.BindingKind.MULTIBOUND_SET;
-import static javax.lang.model.SourceVersion.isName;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.base.Joiner;
-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.Maps;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeVariableName;
-import dagger.internal.SetFactory;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.SetType;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import dagger.producers.internal.SetOfProducedProducer;
-import dagger.producers.internal.SetProducer;
-import java.util.List;
-import javax.inject.Provider;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
-import javax.lang.model.element.VariableElement;
-
-/** Utilities for generating files. */
-public class SourceFiles {
-
- private static final Joiner CLASS_FILE_NAME_JOINER = Joiner.on('_');
-
- /**
- * Generates names and keys for the factory class fields needed to hold the framework classes for
- * all of the dependencies of {@code binding}. It is responsible for choosing a name that
- *
- * <ul>
- * <li>represents all of the dependency requests for this key
- * <li>is <i>probably</i> associated with the type being bound
- * <li>is unique within the class
- * </ul>
- *
- * @param binding must be an unresolved binding (type parameters must match its type element's)
- */
- public static ImmutableMap<DependencyRequest, FrameworkField>
- generateBindingFieldsForDependencies(Binding binding) {
- checkArgument(!binding.unresolved().isPresent(), "binding must be unresolved: %s", binding);
-
- FrameworkTypeMapper frameworkTypeMapper =
- FrameworkTypeMapper.forBindingType(binding.bindingType());
-
- return Maps.toMap(
- binding.dependencies(),
- dependency ->
- FrameworkField.create(
- ClassName.get(
- frameworkTypeMapper.getFrameworkType(dependency.kind()).frameworkClass()),
- TypeName.get(dependency.key().type()),
- DependencyVariableNamer.name(dependency)));
- }
-
- public static CodeBlock frameworkTypeUsageStatement(
- CodeBlock frameworkTypeMemberSelect, RequestKind dependencyKind) {
- switch (dependencyKind) {
- case LAZY:
- return CodeBlock.of("$T.lazy($L)", DOUBLE_CHECK, frameworkTypeMemberSelect);
- case INSTANCE:
- case FUTURE:
- return CodeBlock.of("$L.get()", frameworkTypeMemberSelect);
- case PROVIDER:
- case PRODUCER:
- return frameworkTypeMemberSelect;
- case PROVIDER_OF_LAZY:
- return CodeBlock.of("$T.create($L)", PROVIDER_OF_LAZY, frameworkTypeMemberSelect);
- default: // including PRODUCED
- throw new AssertionError(dependencyKind);
- }
- }
-
- /**
- * Returns a mapping of {@link DependencyRequest}s to {@link CodeBlock}s that {@linkplain
- * #frameworkTypeUsageStatement(CodeBlock, RequestKind) use them}.
- */
- public static ImmutableMap<DependencyRequest, CodeBlock> frameworkFieldUsages(
- ImmutableSet<DependencyRequest> dependencies,
- ImmutableMap<DependencyRequest, FieldSpec> fields) {
- return Maps.toMap(
- dependencies,
- dep -> frameworkTypeUsageStatement(CodeBlock.of("$N", fields.get(dep)), dep.kind()));
- }
-
- /** Returns the generated factory or members injector name for a binding. */
- public static ClassName generatedClassNameForBinding(Binding binding) {
- switch (binding.bindingType()) {
- case PROVISION:
- case PRODUCTION:
- ContributionBinding contribution = (ContributionBinding) binding;
- switch (contribution.kind()) {
- case ASSISTED_INJECTION:
- case INJECTION:
- case PROVISION:
- case PRODUCTION:
- return elementBasedClassName(
- MoreElements.asExecutable(binding.bindingElement().get()), "Factory");
-
- case ASSISTED_FACTORY:
- return siblingClassName(MoreElements.asType(binding.bindingElement().get()), "_Impl");
-
- default:
- throw new AssertionError();
- }
-
- case MEMBERS_INJECTION:
- return membersInjectorNameForType(
- ((MembersInjectionBinding) binding).membersInjectedType());
- }
- throw new AssertionError();
- }
-
- /**
- * Calculates an appropriate {@link ClassName} for a generated class that is based on {@code
- * element}, appending {@code suffix} at the end.
- *
- * <p>This will always return a {@linkplain ClassName#topLevelClassName() top level class name},
- * even if {@code element}'s enclosing class is a nested type.
- */
- public static ClassName elementBasedClassName(ExecutableElement element, String suffix) {
- ClassName enclosingClassName =
- ClassName.get(MoreElements.asType(element.getEnclosingElement()));
- String methodName =
- element.getKind().equals(ElementKind.CONSTRUCTOR)
- ? ""
- : LOWER_CAMEL.to(UPPER_CAMEL, element.getSimpleName().toString());
- return ClassName.get(
- enclosingClassName.packageName(),
- classFileName(enclosingClassName) + "_" + methodName + suffix);
- }
-
- public static TypeName parameterizedGeneratedTypeNameForBinding(Binding binding) {
- ClassName className = generatedClassNameForBinding(binding);
- ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding);
- return typeParameters.isEmpty()
- ? className
- : ParameterizedTypeName.get(className, Iterables.toArray(typeParameters, TypeName.class));
- }
-
- public static ClassName membersInjectorNameForType(TypeElement typeElement) {
- return siblingClassName(typeElement, "_MembersInjector");
- }
-
- public static String memberInjectedFieldSignatureForVariable(VariableElement variableElement) {
- return MoreElements.asType(variableElement.getEnclosingElement()).getQualifiedName()
- + "."
- + variableElement.getSimpleName();
- }
-
- public static String classFileName(ClassName className) {
- return CLASS_FILE_NAME_JOINER.join(className.simpleNames());
- }
-
- public static ClassName generatedMonitoringModuleName(TypeElement componentElement) {
- return siblingClassName(componentElement, "_MonitoringModule");
- }
-
- // TODO(ronshapiro): when JavaPoet migration is complete, replace the duplicated code
- // which could use this.
- private static ClassName siblingClassName(TypeElement typeElement, String suffix) {
- ClassName className = ClassName.get(typeElement);
- return className.topLevelClassName().peerClass(classFileName(className) + suffix);
- }
-
- /**
- * The {@link java.util.Set} factory class name appropriate for set bindings.
- *
- * <ul>
- * <li>{@link SetFactory} for provision bindings.
- * <li>{@link SetProducer} for production bindings for {@code Set<T>}.
- * <li>{@link SetOfProducedProducer} for production bindings for {@code Set<Produced<T>>}.
- * </ul>
- */
- public static ClassName setFactoryClassName(ContributionBinding binding) {
- checkArgument(binding.kind().equals(MULTIBOUND_SET));
- if (binding.bindingType().equals(BindingType.PROVISION)) {
- return SET_FACTORY;
- } else {
- SetType setType = SetType.from(binding.key());
- return setType.elementsAreTypeOf(Produced.class) ? SET_OF_PRODUCED_PRODUCER : SET_PRODUCER;
- }
- }
-
- /** The {@link java.util.Map} factory class name appropriate for map bindings. */
- public static ClassName mapFactoryClassName(ContributionBinding binding) {
- checkState(binding.kind().equals(MULTIBOUND_MAP), binding.kind());
- MapType mapType = MapType.from(binding.key());
- switch (binding.bindingType()) {
- case PROVISION:
- return mapType.valuesAreTypeOf(Provider.class) ? MAP_PROVIDER_FACTORY : MAP_FACTORY;
- case PRODUCTION:
- return mapType.valuesAreFrameworkType()
- ? mapType.valuesAreTypeOf(Producer.class)
- ? MAP_OF_PRODUCER_PRODUCER
- : MAP_OF_PRODUCED_PRODUCER
- : MAP_PRODUCER;
- default:
- throw new IllegalArgumentException(binding.bindingType().toString());
- }
- }
-
- public static ImmutableList<TypeVariableName> bindingTypeElementTypeVariableNames(
- Binding binding) {
- if (binding instanceof ContributionBinding) {
- ContributionBinding contributionBinding = (ContributionBinding) binding;
- if (!(contributionBinding.kind() == INJECTION
- || contributionBinding.kind() == ASSISTED_INJECTION)
- && !contributionBinding.requiresModuleInstance()) {
- return ImmutableList.of();
- }
- }
- List<? extends TypeParameterElement> typeParameters =
- binding.bindingTypeElement().get().getTypeParameters();
- return typeParameters.stream().map(TypeVariableName::get).collect(toImmutableList());
- }
-
- /**
- * Returns a name to be used for variables of the given {@linkplain TypeElement type}. Prefer
- * semantically meaningful variable names, but if none can be derived, this will produce something
- * readable.
- */
- // TODO(gak): maybe this should be a function of TypeMirrors instead of Elements?
- public static String simpleVariableName(TypeElement typeElement) {
- String candidateName = UPPER_CAMEL.to(LOWER_CAMEL, typeElement.getSimpleName().toString());
- String variableName = protectAgainstKeywords(candidateName);
- verify(isName(variableName), "'%s' was expected to be a valid variable name");
- return variableName;
- }
-
- public static String protectAgainstKeywords(String candidateName) {
- switch (candidateName) {
- case "package":
- return "pkg";
- case "boolean":
- return "b";
- case "double":
- return "d";
- case "byte":
- return "b";
- case "int":
- return "i";
- case "short":
- return "s";
- case "char":
- return "c";
- case "void":
- return "v";
- case "class":
- return "clazz";
- case "float":
- return "f";
- case "long":
- return "l";
- default:
- return SourceVersion.isKeyword(candidateName) ? candidateName + '_' : candidateName;
- }
- }
-
- private SourceFiles() {}
-}
diff --git a/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java b/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
deleted file mode 100644
index 93e79b5..0000000
--- a/java/dagger/internal/codegen/binding/SubcomponentCreatorBindingEdgeImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static java.util.stream.Collectors.joining;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.model.BindingGraph.SubcomponentCreatorBindingEdge;
-import javax.lang.model.element.TypeElement;
-
-/** An implementation of {@link SubcomponentCreatorBindingEdge}. */
-public final class SubcomponentCreatorBindingEdgeImpl implements SubcomponentCreatorBindingEdge {
-
- private final ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations;
-
- SubcomponentCreatorBindingEdgeImpl(
- ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations) {
- this.subcomponentDeclarations = subcomponentDeclarations;
- }
-
- @Override
- public ImmutableSet<TypeElement> declaringModules() {
- return subcomponentDeclarations.stream()
- .map(SubcomponentDeclaration::contributingModule)
- .flatMap(presentValues())
- .collect(toImmutableSet());
- }
-
- @Override
- public String toString() {
- return "subcomponent declared by "
- + (subcomponentDeclarations.size() == 1
- ? getOnlyElement(declaringModules()).getQualifiedName()
- : declaringModules().stream()
- .map(TypeElement::getQualifiedName)
- .collect(joining(", ", "{", "}")));
- }
-}
diff --git a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java b/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
deleted file mode 100644
index 4f1f3ef..0000000
--- a/java/dagger/internal/codegen/binding/SubcomponentDeclaration.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.AnnotationMirrors.getAnnotationElementAndValue;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getSubcomponentCreator;
-
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.base.ModuleAnnotation;
-import dagger.model.Key;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/**
- * A declaration for a subcomponent that is included in a module via {@link
- * dagger.Module#subcomponents()}.
- */
-@AutoValue
-public abstract class SubcomponentDeclaration extends BindingDeclaration {
- /**
- * Key for the {@link dagger.Subcomponent.Builder} or {@link
- * dagger.producers.ProductionSubcomponent.Builder} of {@link #subcomponentType()}.
- */
- @Override
- public abstract Key key();
-
- /**
- * The type element that defines the {@link dagger.Subcomponent} or {@link
- * dagger.producers.ProductionSubcomponent} for this declaration.
- */
- abstract TypeElement subcomponentType();
-
- /** The module annotation. */
- public abstract ModuleAnnotation moduleAnnotation();
-
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object obj);
-
- /** A {@link SubcomponentDeclaration} factory. */
- public static class Factory {
- private final KeyFactory keyFactory;
-
- @Inject
- Factory(KeyFactory keyFactory) {
- this.keyFactory = keyFactory;
- }
-
- ImmutableSet<SubcomponentDeclaration> forModule(TypeElement module) {
- ImmutableSet.Builder<SubcomponentDeclaration> declarations = ImmutableSet.builder();
- ModuleAnnotation moduleAnnotation = ModuleAnnotation.moduleAnnotation(module).get();
- Element subcomponentAttribute =
- getAnnotationElementAndValue(moduleAnnotation.annotation(), "subcomponents").getKey();
- for (TypeElement subcomponent : moduleAnnotation.subcomponents()) {
- declarations.add(
- new AutoValue_SubcomponentDeclaration(
- Optional.of(subcomponentAttribute),
- Optional.of(module),
- keyFactory.forSubcomponentCreator(
- getSubcomponentCreator(subcomponent).get().asType()),
- subcomponent,
- moduleAnnotation));
- }
- return declarations.build();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BUILD b/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
deleted file mode 100644
index da35b51..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BUILD
+++ /dev/null
@@ -1,45 +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.
-
-# Description:
-# Classes related to BindingGraph validation.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "bindinggraphvalidation",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java b/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
deleted file mode 100644
index a1f1848..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/BindingGraphValidationModule.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.validation.CompositeBindingGraphPlugin;
-import dagger.internal.codegen.validation.Validation;
-import dagger.spi.BindingGraphPlugin;
-
-/** Binds the set of {@link BindingGraphPlugin}s used to implement Dagger validation. */
-@Module
-public interface BindingGraphValidationModule {
-
- @Provides
- @Validation
- static ImmutableSet<BindingGraphPlugin> providePlugins(
- CompositeBindingGraphPlugin.Factory factory,
- CompilerOptions compilerOptions,
- DependencyCycleValidator validation1,
- DependsOnProductionExecutorValidator validation2,
- DuplicateBindingsValidator validation3,
- IncompatiblyScopedBindingsValidator validation4,
- InjectBindingValidator validation5,
- MapMultibindingValidator validation6,
- MissingBindingValidator validation7,
- NullableBindingValidator validation8,
- ProvisionDependencyOnProducerBindingValidator validation9,
- SubcomponentFactoryMethodValidator validation10) {
- ImmutableSet<BindingGraphPlugin> plugins = ImmutableSet.of(
- validation1,
- validation2,
- validation3,
- validation4,
- validation5,
- validation6,
- validation7,
- validation8,
- validation9,
- validation10);
- if (compilerOptions.experimentalDaggerErrorMessages()) {
- return ImmutableSet.of(factory.create(plugins, "Dagger/Validation"));
- } else {
- return plugins;
- }
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
deleted file mode 100644
index bc89ebb..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependencyCycleValidator.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getLast;
-import static com.google.common.collect.Iterables.limit;
-import static com.google.common.collect.Iterables.skip;
-import static com.google.common.collect.Sets.newHashSetWithExpectedSize;
-import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
-import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
-import static dagger.internal.codegen.extension.DaggerGraphs.shortestPath;
-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 javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.graph.EndpointPair;
-import com.google.common.graph.Graphs;
-import com.google.common.graph.ImmutableNetwork;
-import com.google.common.graph.MutableNetwork;
-import com.google.common.graph.NetworkBuilder;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.OptionalType;
-import dagger.internal.codegen.binding.DependencyRequestFormatter;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Node;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Stream;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/** Reports errors for dependency cycles. */
-final class DependencyCycleValidator implements BindingGraphPlugin {
-
- private final DependencyRequestFormatter dependencyRequestFormatter;
-
- @Inject
- DependencyCycleValidator(DependencyRequestFormatter dependencyRequestFormatter) {
- this.dependencyRequestFormatter = dependencyRequestFormatter;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/DependencyCycle";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- ImmutableNetwork<Node, DependencyEdge> dependencyGraph =
- nonCycleBreakingDependencyGraph(bindingGraph);
- // First check the graph for a cycle. If there is one, then we'll do more work to report where.
- if (!Graphs.hasCycle(dependencyGraph)) {
- return;
- }
- // Check each endpoint pair only once, no matter how many parallel edges connect them.
- Set<EndpointPair<Node>> dependencyEndpointPairs = dependencyGraph.asGraph().edges();
- Set<EndpointPair<Node>> visited = newHashSetWithExpectedSize(dependencyEndpointPairs.size());
- for (EndpointPair<Node> endpointPair : dependencyEndpointPairs) {
- cycleContainingEndpointPair(endpointPair, dependencyGraph, visited)
- .ifPresent(cycle -> reportCycle(cycle, bindingGraph, diagnosticReporter));
- }
- }
-
- private Optional<Cycle<Node>> cycleContainingEndpointPair(
- EndpointPair<Node> endpoints,
- ImmutableNetwork<Node, DependencyEdge> dependencyGraph,
- Set<EndpointPair<Node>> visited) {
- if (!visited.add(endpoints)) {
- // don't recheck endpoints we already know are part of a cycle
- return Optional.empty();
- }
-
- // If there's a path from the target back to the source, there's a cycle.
- ImmutableList<Node> cycleNodes =
- shortestPath(dependencyGraph, endpoints.target(), endpoints.source());
- if (cycleNodes.isEmpty()) {
- return Optional.empty();
- }
-
- Cycle<Node> cycle = Cycle.fromPath(cycleNodes);
- visited.addAll(cycle.endpointPairs()); // no need to check any edge in this cycle again
- return Optional.of(cycle);
- }
-
- /**
- * Reports a dependency cycle at the dependency into the cycle that is closest to an entry point.
- *
- * <p>For cycles found in reachable binding graphs, looks for the shortest path from the component
- * that contains the cycle (all bindings in a cycle must be in the same component; see below) to
- * some binding in the cycle. Then looks for the last dependency in that path that is not in the
- * cycle; that is the dependency that will be reported, so that the dependency trace will end just
- * before the cycle.
- *
- * <p>For cycles found during full binding graph validation, just reports the component that
- * contains the cycle.
- *
- * <p>Proof (by counterexample) that all bindings in a cycle must be in the same component: Assume
- * one binding in the cycle is in a parent component. Bindings cannot depend on bindings in child
- * components, so that binding cannot depend on the next binding in the cycle.
- */
- private void reportCycle(
- Cycle<Node> cycle, BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- if (bindingGraph.isFullBindingGraph()) {
- diagnosticReporter.reportComponent(
- ERROR,
- bindingGraph.componentNode(cycle.nodes().asList().get(0).componentPath()).get(),
- errorMessage(cycle, bindingGraph));
- return;
- }
-
- ImmutableList<Node> path = shortestPathToCycleFromAnEntryPoint(cycle, bindingGraph);
- Node cycleStartNode = path.get(path.size() - 1);
- Node previousNode = path.get(path.size() - 2);
- DependencyEdge dependencyToReport =
- chooseDependencyEdgeConnecting(previousNode, cycleStartNode, bindingGraph);
- diagnosticReporter.reportDependency(
- ERROR, dependencyToReport, errorMessage(cycle.shift(cycleStartNode), bindingGraph));
- }
-
- private ImmutableList<Node> shortestPathToCycleFromAnEntryPoint(
- Cycle<Node> cycle, BindingGraph bindingGraph) {
- Node someCycleNode = cycle.nodes().asList().get(0);
- ComponentNode componentContainingCycle =
- bindingGraph.componentNode(someCycleNode.componentPath()).get();
- ImmutableList<Node> pathToCycle =
- shortestPath(bindingGraph.network(), componentContainingCycle, someCycleNode);
- return subpathToCycle(pathToCycle, cycle);
- }
-
- /**
- * Returns the subpath from the head of {@code path} to the first node in {@code path} that's in
- * the cycle.
- */
- private ImmutableList<Node> subpathToCycle(ImmutableList<Node> path, Cycle<Node> cycle) {
- ImmutableList.Builder<Node> subpath = ImmutableList.builder();
- for (Node node : path) {
- subpath.add(node);
- if (cycle.nodes().contains(node)) {
- return subpath.build();
- }
- }
- throw new IllegalArgumentException(
- "path " + path + " doesn't contain any nodes in cycle " + cycle);
- }
-
- private String errorMessage(Cycle<Node> cycle, BindingGraph graph) {
- StringBuilder message = new StringBuilder("Found a dependency cycle:");
- ImmutableList<DependencyRequest> cycleRequests =
- cycle.endpointPairs().stream()
- // TODO(dpb): Would be nice to take the dependency graph here.
- .map(endpointPair -> nonCycleBreakingEdge(endpointPair, graph))
- .map(DependencyEdge::dependencyRequest)
- .collect(toImmutableList())
- .reverse();
- dependencyRequestFormatter.formatIndentedList(message, cycleRequests, 0);
- return message.toString();
- }
-
- /**
- * Returns one of the edges between two nodes that doesn't {@linkplain
- * #breaksCycle(DependencyEdge, BindingGraph) break} a cycle.
- */
- private DependencyEdge nonCycleBreakingEdge(EndpointPair<Node> endpointPair, BindingGraph graph) {
- return graph.network().edgesConnecting(endpointPair.source(), endpointPair.target()).stream()
- .flatMap(instancesOf(DependencyEdge.class))
- .filter(edge -> !breaksCycle(edge, graph))
- .findFirst()
- .get();
- }
-
- private boolean breaksCycle(DependencyEdge edge, BindingGraph graph) {
- // Map<K, V> multibindings depend on Map<K, Provider<V>> entries, but those don't break any
- // cycles, so ignore them.
- if (edge.dependencyRequest().key().multibindingContributionIdentifier().isPresent()) {
- return false;
- }
- if (breaksCycle(edge.dependencyRequest().key().type(), edge.dependencyRequest().kind())) {
- return true;
- }
- Node target = graph.network().incidentNodes(edge).target();
- if (target instanceof dagger.model.Binding
- && ((dagger.model.Binding) target).kind().equals(BindingKind.OPTIONAL)) {
- /* For @BindsOptionalOf bindings, unwrap the type inside the Optional. If the unwrapped type
- * breaks the cycle, so does the optional binding. */
- TypeMirror optionalValueType = OptionalType.from(edge.dependencyRequest().key()).valueType();
- RequestKind requestKind = getRequestKind(optionalValueType);
- return breaksCycle(extractKeyType(optionalValueType), requestKind);
- }
- return false;
- }
-
- private boolean breaksCycle(TypeMirror requestedType, RequestKind requestKind) {
- switch (requestKind) {
- case PROVIDER:
- case LAZY:
- case PROVIDER_OF_LAZY:
- return true;
-
- case INSTANCE:
- if (MapType.isMap(requestedType)) {
- MapType mapType = MapType.from(requestedType);
- return !mapType.isRawType() && mapType.valuesAreTypeOf(Provider.class);
- }
- // fall through
-
- default:
- return false;
- }
- }
-
- private DependencyEdge chooseDependencyEdgeConnecting(
- Node source, Node target, BindingGraph bindingGraph) {
- return bindingGraph.network().edgesConnecting(source, target).stream()
- .flatMap(instancesOf(DependencyEdge.class))
- .findFirst()
- .get();
- }
-
- /** Returns the subgraph containing only {@link DependencyEdge}s that would not break a cycle. */
- // TODO(dpb): Return a network containing only Binding nodes.
- private ImmutableNetwork<Node, DependencyEdge> nonCycleBreakingDependencyGraph(
- BindingGraph bindingGraph) {
- MutableNetwork<Node, DependencyEdge> dependencyNetwork =
- NetworkBuilder.from(bindingGraph.network())
- .expectedNodeCount(bindingGraph.network().nodes().size())
- .expectedEdgeCount(bindingGraph.dependencyEdges().size())
- .build();
- bindingGraph.dependencyEdges().stream()
- .filter(edge -> !breaksCycle(edge, bindingGraph))
- .forEach(
- edge -> {
- EndpointPair<Node> endpoints = bindingGraph.network().incidentNodes(edge);
- dependencyNetwork.addEdge(endpoints.source(), endpoints.target(), edge);
- });
- return ImmutableNetwork.copyOf(dependencyNetwork);
- }
-
- /**
- * An ordered set of endpoint pairs representing the edges in the cycle. The target of each pair
- * is the source of the next pair. The target of the last pair is the source of the first pair.
- */
- @AutoValue
- abstract static class Cycle<N> {
- /**
- * The ordered set of endpoint pairs representing the edges in the cycle. The target of each
- * pair is the source of the next pair. The target of the last pair is the source of the first
- * pair.
- */
- abstract ImmutableSet<EndpointPair<N>> endpointPairs();
-
- /** Returns the nodes that participate in the cycle. */
- ImmutableSet<N> nodes() {
- return endpointPairs().stream()
- .flatMap(pair -> Stream.of(pair.source(), pair.target()))
- .collect(toImmutableSet());
- }
-
- /** Returns the number of edges in the cycle. */
- int size() {
- return endpointPairs().size();
- }
-
- /**
- * Shifts this cycle so that it starts with a specific node.
- *
- * @return a cycle equivalent to this one but whose first pair starts with {@code startNode}
- */
- Cycle<N> shift(N startNode) {
- int startIndex = Iterables.indexOf(endpointPairs(), pair -> pair.source().equals(startNode));
- checkArgument(
- startIndex >= 0, "startNode (%s) is not part of this cycle: %s", startNode, this);
- if (startIndex == 0) {
- return this;
- }
- ImmutableSet.Builder<EndpointPair<N>> shifted = ImmutableSet.builder();
- shifted.addAll(skip(endpointPairs(), startIndex));
- shifted.addAll(limit(endpointPairs(), size() - startIndex));
- return new AutoValue_DependencyCycleValidator_Cycle<>(shifted.build());
- }
-
- @Override
- public final String toString() {
- return endpointPairs().toString();
- }
-
- /**
- * Creates a {@link Cycle} from a nonempty list of nodes, assuming there is an edge between each
- * pair of nodes as well as an edge from the last node to the first.
- */
- static <N> Cycle<N> fromPath(List<N> nodes) {
- checkArgument(!nodes.isEmpty());
- ImmutableSet.Builder<EndpointPair<N>> cycle = ImmutableSet.builder();
- cycle.add(EndpointPair.ordered(getLast(nodes), nodes.get(0)));
- for (int i = 0; i < nodes.size() - 1; i++) {
- cycle.add(EndpointPair.ordered(nodes.get(i), nodes.get(i + 1)));
- }
- return new AutoValue_DependencyCycleValidator_Cycle<>(cycle.build());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
deleted file mode 100644
index 08e2c3e..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DependsOnProductionExecutorValidator.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2018 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.extension.DaggerStreams.instancesOf;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import javax.inject.Inject;
-
-/**
- * Reports an error on all bindings that depend explicitly on the {@code @Production Executor} key.
- */
-// TODO(dpb,beder): Validate this during @Inject/@Provides/@Produces validation.
-final class DependsOnProductionExecutorValidator implements BindingGraphPlugin {
- private final CompilerOptions compilerOptions;
- private final KeyFactory keyFactory;
-
- @Inject
- DependsOnProductionExecutorValidator(CompilerOptions compilerOptions, KeyFactory keyFactory) {
- this.compilerOptions = compilerOptions;
- this.keyFactory = keyFactory;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/DependsOnProductionExecutor";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- if (!compilerOptions.usesProducers()) {
- return;
- }
-
- Key productionImplementationExecutorKey = keyFactory.forProductionImplementationExecutor();
- Key productionExecutorKey = keyFactory.forProductionExecutor();
-
- bindingGraph.network().nodes().stream()
- .flatMap(instancesOf(MaybeBinding.class))
- .filter(node -> node.key().equals(productionExecutorKey))
- .flatMap(productionExecutor -> bindingGraph.requestingBindings(productionExecutor).stream())
- .filter(binding -> !binding.key().equals(productionImplementationExecutorKey))
- .forEach(binding -> reportError(diagnosticReporter, binding));
- }
-
- private void reportError(DiagnosticReporter diagnosticReporter, dagger.model.Binding binding) {
- diagnosticReporter.reportBinding(
- ERROR, binding, "%s may not depend on the production executor", binding.key());
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
deleted file mode 100644
index 5c4da51..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/DuplicateBindingsValidator.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2018 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 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.model.BindingKind.INJECTION;
-import static dagger.model.BindingKind.MEMBERS_INJECTION;
-import static java.util.Comparator.comparing;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMultiset;
-import com.google.common.collect.ImmutableSet;
-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.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingKind;
-import dagger.model.ComponentPath;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-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.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic.Kind;
-
-/** Reports errors for conflicting bindings with the same key. */
-final class DuplicateBindingsValidator implements BindingGraphPlugin {
-
- private static final Comparator<Binding> BY_LENGTH_OF_COMPONENT_PATH =
- comparing(binding -> binding.componentPath().components().size());
-
- private final BindingDeclarationFormatter bindingDeclarationFormatter;
- private final CompilerOptions compilerOptions;
-
- @Inject
- DuplicateBindingsValidator(
- BindingDeclarationFormatter bindingDeclarationFormatter, CompilerOptions compilerOptions) {
- this.bindingDeclarationFormatter = bindingDeclarationFormatter;
- this.compilerOptions = compilerOptions;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/DuplicateBindings";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- // If two unrelated subcomponents have the same duplicate bindings only because they install the
- // 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<>();
- 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);
- }
- });
- }
-
- /**
- * Returns sets of duplicate bindings. Bindings are duplicates if they bind the same key and are
- * visible from the same component. Two bindings that differ only in the component that owns them
- * are not considered to be duplicates, because that means the same binding was "copied" down to a
- * 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(
- BindingGraph bindingGraph) {
- return groupBindingsByKey(bindingGraph).stream()
- .flatMap(bindings -> mutuallyVisibleSubsets(bindings).stream())
- .map(BindingElement::index)
- .filter(duplicates -> duplicates.keySet().size() > 1)
- .collect(toImmutableSet());
- }
-
- private static ImmutableSet<ImmutableSet<Binding>> groupBindingsByKey(BindingGraph bindingGraph) {
- return valueSetsForEachKey(
- bindingGraph.bindings().stream()
- .filter(binding -> !binding.kind().equals(MEMBERS_INJECTION))
- .collect(toImmutableSetMultimap(Binding::key, binding -> binding)));
- }
-
- /**
- * Returns the subsets of the input set that contain bindings that are all visible from the same
- * component. A binding is visible from its component and all its descendants.
- */
- private static ImmutableSet<ImmutableSet<Binding>> mutuallyVisibleSubsets(
- Set<Binding> duplicateBindings) {
- ImmutableListMultimap<ComponentPath, Binding> bindingsByComponentPath =
- Multimaps.index(duplicateBindings, Binding::componentPath);
- ImmutableSetMultimap.Builder<ComponentPath, Binding> mutuallyVisibleBindings =
- ImmutableSetMultimap.builder();
- bindingsByComponentPath
- .asMap()
- .forEach(
- (componentPath, bindings) -> {
- mutuallyVisibleBindings.putAll(componentPath, bindings);
- for (ComponentPath ancestor = componentPath; !ancestor.atRoot(); ) {
- ancestor = ancestor.parent();
- ImmutableList<Binding> bindingsInAncestor = bindingsByComponentPath.get(ancestor);
- mutuallyVisibleBindings.putAll(componentPath, bindingsInAncestor);
- }
- });
- return valueSetsForEachKey(mutuallyVisibleBindings.build());
- }
-
- private void reportDuplicateBindings(
- ImmutableSetMultimap<BindingElement, Binding> duplicateBindings,
- BindingGraph bindingGraph,
- DiagnosticReporter diagnosticReporter) {
- if (explicitBindingConfictsWithInject(duplicateBindings.keySet())) {
- compilerOptions
- .explicitBindingConflictsWithInjectValidationType()
- .diagnosticKind()
- .ifPresent(
- diagnosticKind ->
- reportExplicitBindingConflictsWithInject(
- duplicateBindings,
- 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);
- }
- }
-
- /**
- * Returns {@code true} if the bindings contain one {@code @Inject} binding and one that isn't.
- */
- private static boolean explicitBindingConfictsWithInject(
- ImmutableSet<BindingElement> duplicateBindings) {
- ImmutableMultiset<BindingKind> bindingKinds =
- Multimaps.index(duplicateBindings, BindingElement::bindingKind).keys();
- return bindingKinds.count(INJECTION) == 1 && bindingKinds.size() == 2;
- }
-
- private void reportExplicitBindingConflictsWithInject(
- ImmutableSetMultimap<BindingElement, Binding> duplicateBindings,
- DiagnosticReporter diagnosticReporter,
- Kind diagnosticKind,
- ComponentNode rootComponent) {
- Binding injectBinding =
- rootmostBindingWithKind(k -> k.equals(INJECTION), duplicateBindings.values());
- Binding explicitBinding =
- rootmostBindingWithKind(k -> !k.equals(INJECTION), duplicateBindings.values());
- StringBuilder message =
- new StringBuilder()
- .append(explicitBinding.key())
- .append(" is bound multiple times:")
- .append(formatWithComponentPath(injectBinding))
- .append(formatWithComponentPath(explicitBinding))
- .append(
- "\nThis condition was never validated before, and will soon be an error. "
- + "See https://dagger.dev/conflicting-inject.");
-
- if (compilerOptions.experimentalDaggerErrorMessages()) {
- diagnosticReporter.reportComponent(diagnosticKind, rootComponent, message.toString());
- } else {
- diagnosticReporter.reportBinding(diagnosticKind, explicitBinding, message.toString());
- }
- }
-
- private String formatWithComponentPath(Binding binding) {
- return String.format(
- "\n%s%s [%s]",
- Formatter.INDENT,
- bindingDeclarationFormatter.format(((BindingNode) binding).delegate()),
- 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.model.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.model.Binding multibinding = getOnlyElement(multibindings);
- messageFormatter.format("%s bindings and declarations:", multibindingTypeString(multibinding));
- formatDeclarations(message, 2, declarations(graph, multibindings));
-
- Set<dagger.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()));
- }
- return message.toString();
- }
-
- private void formatDeclarations(
- StringBuilder builder,
- int indentLevel,
- Iterable<? extends BindingDeclaration> bindingDeclarations) {
- bindingDeclarationFormatter.formatIndentedList(
- builder, ImmutableList.copyOf(bindingDeclarations), indentLevel);
- }
-
- private ImmutableSet<BindingDeclaration> declarations(
- BindingGraph graph, Set<dagger.model.Binding> bindings) {
- return bindings.stream()
- .flatMap(binding -> declarations(graph, binding).stream())
- .distinct()
- .sorted(BindingDeclaration.COMPARATOR)
- .collect(toImmutableSet());
- }
-
- private ImmutableSet<BindingDeclaration> declarations(
- BindingGraph graph, dagger.model.Binding binding) {
- ImmutableSet.Builder<BindingDeclaration> declarations = ImmutableSet.builder();
- BindingNode bindingNode = (BindingNode) binding;
- bindingNode.associatedDeclarations().forEach(declarations::add);
- if (bindingDeclarationFormatter.canFormat(bindingNode.delegate())) {
- declarations.add(bindingNode.delegate());
- } else {
- graph.requestedBindings(binding).stream()
- .flatMap(requestedBinding -> declarations(graph, requestedBinding).stream())
- .forEach(declarations::add);
- }
- return declarations.build();
- }
-
- private String multibindingTypeString(dagger.model.Binding multibinding) {
- switch (multibinding.kind()) {
- case MULTIBOUND_MAP:
- return "Map";
- case MULTIBOUND_SET:
- return "Set";
- default:
- throw new AssertionError(multibinding);
- }
- }
-
- private static <E> ImmutableSet<ImmutableSet<E>> valueSetsForEachKey(Multimap<?, E> multimap) {
- return multimap.asMap().values().stream().map(ImmutableSet::copyOf).collect(toImmutableSet());
- }
-
- /** Returns the binding of the given kind that is closest to the root component. */
- private static Binding rootmostBindingWithKind(
- Predicate<BindingKind> bindingKindPredicate, ImmutableCollection<Binding> bindings) {
- return bindings.stream()
- .filter(b -> bindingKindPredicate.test(b.kind()))
- .min(BY_LENGTH_OF_COMPONENT_PATH)
- .get();
- }
-
- /** The identifying information about a binding, excluding its {@link Binding#componentPath()}. */
- @AutoValue
- abstract static class BindingElement {
-
- abstract BindingKind bindingKind();
-
- abstract Optional<Element> bindingElement();
-
- abstract Optional<TypeElement> contributingModule();
-
- static ImmutableSetMultimap<BindingElement, Binding> index(Set<Binding> bindings) {
- return bindings.stream().collect(toImmutableSetMultimap(BindingElement::forBinding, b -> b));
- }
-
- private static BindingElement forBinding(Binding binding) {
- return new AutoValue_DuplicateBindingsValidator_BindingElement(
- binding.kind(), binding.bindingElement(), binding.contributingModule());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
deleted file mode 100644
index a01dbaf..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/IncompatiblyScopedBindingsValidator.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2018 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.base.Formatter.INDENT;
-import static dagger.internal.codegen.base.Scopes.getReadableSource;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-import static dagger.model.BindingKind.INJECTION;
-import static java.util.stream.Collectors.joining;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimaps;
-import dagger.internal.codegen.base.Scopes;
-import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.Binding;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.tools.Diagnostic;
-
-/**
- * Reports an error for any component that uses bindings with scopes that are not assigned to the
- * component.
- */
-final class IncompatiblyScopedBindingsValidator implements BindingGraphPlugin {
-
- private final MethodSignatureFormatter methodSignatureFormatter;
- private final CompilerOptions compilerOptions;
-
- @Inject
- IncompatiblyScopedBindingsValidator(
- MethodSignatureFormatter methodSignatureFormatter, CompilerOptions compilerOptions) {
- this.methodSignatureFormatter = methodSignatureFormatter;
- this.compilerOptions = compilerOptions;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/IncompatiblyScopedBindings";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- ImmutableSetMultimap.Builder<ComponentNode, dagger.model.Binding> incompatibleBindings =
- ImmutableSetMultimap.builder();
- for (dagger.model.Binding binding : bindingGraph.bindings()) {
- binding
- .scope()
- .filter(scope -> !scope.isReusable())
- .ifPresent(
- scope -> {
- ComponentNode componentNode =
- bindingGraph.componentNode(binding.componentPath()).get();
- if (!componentNode.scopes().contains(scope)) {
- // @Inject bindings in module or subcomponent binding graphs will appear at the
- // properly scoped ancestor component, so ignore them here.
- if (binding.kind().equals(INJECTION)
- && (bindingGraph.rootComponentNode().isSubcomponent()
- || !bindingGraph.rootComponentNode().isRealComponent())) {
- return;
- }
- incompatibleBindings.put(componentNode, binding);
- }
- });
- }
- Multimaps.asMap(incompatibleBindings.build())
- .forEach((componentNode, bindings) -> report(componentNode, bindings, diagnosticReporter));
- }
-
- private void report(
- ComponentNode componentNode,
- Set<Binding> bindings,
- DiagnosticReporter diagnosticReporter) {
- Diagnostic.Kind diagnosticKind = ERROR;
- StringBuilder message =
- new StringBuilder(componentNode.componentPath().currentComponent().getQualifiedName());
-
- if (!componentNode.isRealComponent()) {
- // If the "component" is really a module, it will have no scopes attached. We want to report
- // if there is more than one scope in that component.
- if (bindings.stream().map(Binding::scope).map(Optional::get).distinct().count() <= 1) {
- return;
- }
- message.append(" contains bindings with different scopes:");
- diagnosticKind = compilerOptions.moduleHasDifferentScopesDiagnosticKind();
- } else if (componentNode.scopes().isEmpty()) {
- message.append(" (unscoped) may not reference scoped bindings:");
- } else {
- message
- .append(" scoped with ")
- .append(
- componentNode.scopes().stream().map(Scopes::getReadableSource).collect(joining(" ")))
- .append(" may not reference bindings with different scopes:");
- }
-
- // TODO(ronshapiro): Should we group by scope?
- for (Binding binding : bindings) {
- message.append('\n').append(INDENT);
-
- // TODO(dpb): Use BindingDeclarationFormatter.
- // But that doesn't print scopes for @Inject-constructed types.
- switch (binding.kind()) {
- case DELEGATE:
- case PROVISION:
- message.append(
- methodSignatureFormatter.format(
- MoreElements.asExecutable(binding.bindingElement().get())));
- break;
-
- case INJECTION:
- message
- .append(getReadableSource(binding.scope().get()))
- .append(" class ")
- .append(
- closestEnclosingTypeElement(binding.bindingElement().get()).getQualifiedName());
- break;
-
- default:
- throw new AssertionError(binding);
- }
- }
- diagnosticReporter.reportComponent(diagnosticKind, componentNode, message.toString());
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
deleted file mode 100644
index fe1c3e0..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/InjectBindingValidator.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2018 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.model.BindingKind.INJECTION;
-
-import com.google.auto.common.MoreTypes;
-import dagger.internal.codegen.validation.InjectValidator;
-import dagger.internal.codegen.validation.ValidationReport;
-import dagger.internal.codegen.validation.ValidationReport.Item;
-import dagger.model.BindingGraph;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-
-/** Validates bindings from {@code @Inject}-annotated constructors. */
-final class InjectBindingValidator implements BindingGraphPlugin {
-
- private final InjectValidator injectValidator;
-
- @Inject
- InjectBindingValidator(InjectValidator injectValidator) {
- this.injectValidator = injectValidator.whenGeneratingCode();
- }
-
- @Override
- public String pluginName() {
- return "Dagger/InjectBinding";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- bindingGraph.bindings().stream()
- .filter(binding -> binding.kind().equals(INJECTION)) // TODO(dpb): Move to BindingGraph
- .forEach(binding -> validateInjectionBinding(binding, diagnosticReporter));
- }
-
- private void validateInjectionBinding(
- dagger.model.Binding node, DiagnosticReporter diagnosticReporter) {
- ValidationReport<TypeElement> typeReport =
- injectValidator.validateType(MoreTypes.asTypeElement(node.key().type()));
- for (Item item : typeReport.allItems()) {
- diagnosticReporter.reportBinding(item.kind(), node, item.message());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
deleted file mode 100644
index 481c6d8..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MapMultibindingValidator.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Multimaps.filterKeys;
-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.model.BindingKind.MULTIBOUND_MAP;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.binding.BindingDeclaration;
-import dagger.internal.codegen.binding.BindingDeclarationFormatter;
-import dagger.internal.codegen.binding.BindingNode;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.model.BindingGraph;
-import dagger.model.Key;
-import dagger.producers.Producer;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.type.DeclaredType;
-
-/**
- * Reports an error for any map binding with either more than one contribution with the same map key
- * or contributions with inconsistent map key annotation types.
- */
-final class MapMultibindingValidator implements BindingGraphPlugin {
-
- private final BindingDeclarationFormatter bindingDeclarationFormatter;
- private final KeyFactory keyFactory;
-
- @Inject
- MapMultibindingValidator(
- BindingDeclarationFormatter bindingDeclarationFormatter, KeyFactory keyFactory) {
- this.bindingDeclarationFormatter = bindingDeclarationFormatter;
- this.keyFactory = keyFactory;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/MapKeys";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- mapMultibindings(bindingGraph)
- .forEach(
- binding -> {
- ImmutableSet<ContributionBinding> contributions =
- mapBindingContributions(binding, bindingGraph);
- checkForDuplicateMapKeys(binding, contributions, diagnosticReporter);
- checkForInconsistentMapKeyAnnotationTypes(binding, contributions, diagnosticReporter);
- });
- }
-
- /**
- * Returns the map multibindings in the binding graph. If a graph contains bindings for more than
- * one of the following for the same {@code K} and {@code V}, then only the first one found will
- * be returned so we don't report the same map contribution problem more than once.
- *
- * <ol>
- * <li>{@code Map<K, V>}
- * <li>{@code Map<K, Provider<V>>}
- * <li>{@code Map<K, Producer<V>>}
- * </ol>
- */
- private ImmutableSet<dagger.model.Binding> mapMultibindings(BindingGraph bindingGraph) {
- ImmutableSetMultimap<Key, dagger.model.Binding> mapMultibindings =
- bindingGraph.bindings().stream()
- .filter(node -> node.kind().equals(MULTIBOUND_MAP))
- .collect(toImmutableSetMultimap(dagger.model.Binding::key, node -> node));
-
- // Mutlbindings for Map<K, V>
- SetMultimap<Key, dagger.model.Binding> plainValueMapMultibindings =
- filterKeys(mapMultibindings, key -> !MapType.from(key).valuesAreFrameworkType());
-
- // Multibindings for Map<K, Provider<V>> where Map<K, V> isn't in plainValueMapMultibindings
- SetMultimap<Key, dagger.model.Binding> providerValueMapMultibindings =
- filterKeys(
- mapMultibindings,
- key ->
- MapType.from(key).valuesAreTypeOf(Provider.class)
- && !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key)));
-
- // Multibindings for Map<K, Producer<V>> where Map<K, V> isn't in plainValueMapMultibindings and
- // Map<K, Provider<V>> isn't in providerValueMapMultibindings
- SetMultimap<Key, dagger.model.Binding> producerValueMapMultibindings =
- filterKeys(
- mapMultibindings,
- key ->
- MapType.from(key).valuesAreTypeOf(Producer.class)
- && !plainValueMapMultibindings.containsKey(keyFactory.unwrapMapValueType(key))
- && !providerValueMapMultibindings.containsKey(
- keyFactory.rewrapMapKey(key, Producer.class, Provider.class).get()));
-
- return new ImmutableSet.Builder<dagger.model.Binding>()
- .addAll(plainValueMapMultibindings.values())
- .addAll(providerValueMapMultibindings.values())
- .addAll(producerValueMapMultibindings.values())
- .build();
- }
-
- private ImmutableSet<ContributionBinding> mapBindingContributions(
- dagger.model.Binding binding, BindingGraph bindingGraph) {
- checkArgument(binding.kind().equals(MULTIBOUND_MAP));
- return bindingGraph.requestedBindings(binding).stream()
- .map(b -> (BindingNode) b)
- .map(b -> (ContributionBinding) b.delegate())
- .collect(toImmutableSet());
- }
-
- private void checkForDuplicateMapKeys(
- dagger.model.Binding multiboundMapBinding,
- ImmutableSet<ContributionBinding> contributions,
- DiagnosticReporter diagnosticReporter) {
- ImmutableSetMultimap<?, ContributionBinding> contributionsByMapKey =
- ImmutableSetMultimap.copyOf(
- Multimaps.index(contributions, ContributionBinding::wrappedMapKeyAnnotation));
-
- for (Set<ContributionBinding> contributionsForOneMapKey :
- Multimaps.asMap(contributionsByMapKey).values()) {
- if (contributionsForOneMapKey.size() > 1) {
- diagnosticReporter.reportBinding(
- ERROR,
- multiboundMapBinding,
- duplicateMapKeyErrorMessage(contributionsForOneMapKey, multiboundMapBinding.key()));
- }
- }
- }
-
- private void checkForInconsistentMapKeyAnnotationTypes(
- dagger.model.Binding multiboundMapBinding,
- ImmutableSet<ContributionBinding> contributions,
- DiagnosticReporter diagnosticReporter) {
- ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
- contributionsByMapKeyAnnotationType = indexByMapKeyAnnotationType(contributions);
-
- if (contributionsByMapKeyAnnotationType.keySet().size() > 1) {
- diagnosticReporter.reportBinding(
- ERROR,
- multiboundMapBinding,
- inconsistentMapKeyAnnotationTypesErrorMessage(
- contributionsByMapKeyAnnotationType, multiboundMapBinding.key()));
- }
- }
-
- private static ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
- indexByMapKeyAnnotationType(ImmutableSet<ContributionBinding> contributions) {
- return ImmutableSetMultimap.copyOf(
- Multimaps.index(
- contributions,
- mapBinding ->
- MoreTypes.equivalence()
- .wrap(mapBinding.mapKeyAnnotation().get().getAnnotationType())));
- }
-
- private String inconsistentMapKeyAnnotationTypesErrorMessage(
- ImmutableSetMultimap<Equivalence.Wrapper<DeclaredType>, ContributionBinding>
- contributionsByMapKeyAnnotationType,
- Key mapBindingKey) {
- StringBuilder message =
- new StringBuilder(mapBindingKey.toString())
- .append(" uses more than one @MapKey annotation type");
- Multimaps.asMap(contributionsByMapKeyAnnotationType)
- .forEach(
- (annotationType, contributions) -> {
- message.append('\n').append(INDENT).append(annotationType.get()).append(':');
- bindingDeclarationFormatter.formatIndentedList(message, contributions, 2);
- });
- return message.toString();
- }
-
- private String duplicateMapKeyErrorMessage(
- Set<ContributionBinding> contributionsForOneMapKey, Key mapBindingKey) {
- StringBuilder message =
- new StringBuilder("The same map key is bound more than once for ").append(mapBindingKey);
-
- bindingDeclarationFormatter.formatIndentedList(
- message,
- ImmutableList.sortedCopyOf(BindingDeclaration.COMPARATOR, contributionsForOneMapKey),
- 1);
- return message.toString();
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
deleted file mode 100644
index 7334cd9..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/MissingBindingValidator.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Verify.verify;
-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.extension.DaggerStreams.instancesOf;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import dagger.internal.codegen.binding.InjectBindingRegistry;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.MissingBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.Key;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import javax.inject.Inject;
-import javax.lang.model.type.TypeKind;
-
-/** Reports errors for missing bindings. */
-final class MissingBindingValidator implements BindingGraphPlugin {
-
- private final DaggerTypes types;
- private final InjectBindingRegistry injectBindingRegistry;
-
- @Inject
- MissingBindingValidator(
- DaggerTypes types, InjectBindingRegistry injectBindingRegistry) {
- this.types = types;
- this.injectBindingRegistry = injectBindingRegistry;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/MissingBinding";
- }
-
- @Override
- public void visitGraph(BindingGraph graph, DiagnosticReporter diagnosticReporter) {
- // Don't report missing bindings when validating a full binding graph or a graph built from a
- // subcomponent.
- if (graph.isFullBindingGraph() || graph.rootComponentNode().isSubcomponent()) {
- return;
- }
- graph
- .missingBindings()
- .forEach(missingBinding -> reportMissingBinding(missingBinding, graph, diagnosticReporter));
- }
-
- private void reportMissingBinding(
- MissingBinding missingBinding, BindingGraph graph, DiagnosticReporter diagnosticReporter) {
- diagnosticReporter.reportBinding(
- ERROR, missingBinding, missingBindingErrorMessage(missingBinding, graph));
- }
-
- private String missingBindingErrorMessage(MissingBinding missingBinding, BindingGraph graph) {
- Key key = missingBinding.key();
- StringBuilder errorMessage = new StringBuilder();
- // Wildcards should have already been checked by DependencyRequestValidator.
- verify(!key.type().getKind().equals(TypeKind.WILDCARD), "unexpected wildcard request: %s", key);
- // TODO(ronshapiro): replace "provided" with "satisfied"?
- errorMessage.append(key).append(" cannot be provided without ");
- if (isValidImplicitProvisionKey(key, types)) {
- errorMessage.append("an @Inject constructor or ");
- }
- errorMessage.append("an @Provides-"); // TODO(dpb): s/an/a
- if (allIncomingDependenciesCanUseProduction(missingBinding, graph)) {
- errorMessage.append(" or @Produces-");
- }
- errorMessage.append("annotated method.");
- if (isValidMembersInjectionKey(key) && typeHasInjectionSites(key)) {
- errorMessage.append(
- " This type supports members injection but cannot be implicitly provided.");
- }
- graph.bindings(key).stream()
- .map(binding -> binding.componentPath().currentComponent())
- .distinct()
- .forEach(
- component ->
- errorMessage
- .append("\nA binding with matching key exists in component: ")
- .append(component.getQualifiedName()));
- return errorMessage.toString();
- }
-
- private boolean allIncomingDependenciesCanUseProduction(
- MissingBinding missingBinding, BindingGraph graph) {
- return graph.network().inEdges(missingBinding).stream()
- .flatMap(instancesOf(DependencyEdge.class))
- .allMatch(edge -> dependencyCanBeProduction(edge, graph));
- }
-
- // TODO(ronshapiro): merge with
- // ProvisionDependencyOnProduerBindingValidator.dependencyCanUseProduction
- private boolean dependencyCanBeProduction(DependencyEdge edge, BindingGraph graph) {
- Node source = graph.network().incidentNodes(edge).source();
- if (source instanceof ComponentNode) {
- return canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind());
- }
- if (source instanceof dagger.model.Binding) {
- return ((dagger.model.Binding) source).isProduction();
- }
- throw new IllegalArgumentException(
- "expected a dagger.model.Binding or ComponentNode: " + source);
- }
-
- private boolean typeHasInjectionSites(Key key) {
- return injectBindingRegistry
- .getOrFindMembersInjectionBinding(key)
- .map(binding -> !binding.injectionSites().isEmpty())
- .orElse(false);
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
deleted file mode 100644
index 9800b15..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/NullableBindingValidator.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2018 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.extension.DaggerStreams.instancesOf;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import javax.inject.Inject;
-
-/**
- * Reports errors or warnings (depending on the {@code -Adagger.nullableValidation} value) for each
- * non-nullable dependency request that is satisfied by a nullable binding.
- */
-final class NullableBindingValidator implements BindingGraphPlugin {
-
- private final CompilerOptions compilerOptions;
-
- @Inject
- NullableBindingValidator(CompilerOptions compilerOptions) {
- this.compilerOptions = compilerOptions;
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- for (dagger.model.Binding binding : nullableBindings(bindingGraph)) {
- for (DependencyEdge dependencyEdge : nonNullableDependencies(bindingGraph, binding)) {
- diagnosticReporter.reportDependency(
- compilerOptions.nullableValidationKind(),
- dependencyEdge,
- nullableToNonNullable(
- binding.key().toString(),
- binding.toString())); // binding.toString() will include the @Nullable
- }
- }
- }
-
- @Override
- public String pluginName() {
- return "Dagger/Nullable";
- }
-
- private ImmutableList<dagger.model.Binding> nullableBindings(BindingGraph bindingGraph) {
- return bindingGraph.bindings().stream()
- .filter(binding -> binding.isNullable())
- .collect(toImmutableList());
- }
-
- private ImmutableSet<DependencyEdge> nonNullableDependencies(
- BindingGraph bindingGraph, dagger.model.Binding binding) {
- return bindingGraph.network().inEdges(binding).stream()
- .flatMap(instancesOf(DependencyEdge.class))
- .filter(edge -> !edge.dependencyRequest().isNullable())
- .collect(toImmutableSet());
- }
-
- @VisibleForTesting
- static String nullableToNonNullable(String key, String binding) {
- return String.format("%s is not nullable, but is being provided by %s", key, binding);
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
deleted file mode 100644
index 7d742f9..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/ProvisionDependencyOnProducerBindingValidator.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.base.RequestKinds.canBeSatisfiedByProductionBinding;
-import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Node;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.stream.Stream;
-import javax.inject.Inject;
-
-/**
- * Reports an error for each provision-only dependency request that is satisfied by a production
- * binding.
- */
-// TODO(b/29509141): Clarify the error.
-final class ProvisionDependencyOnProducerBindingValidator implements BindingGraphPlugin {
-
- @Inject
- ProvisionDependencyOnProducerBindingValidator() {}
-
- @Override
- public String pluginName() {
- return "Dagger/ProviderDependsOnProducer";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- provisionDependenciesOnProductionBindings(bindingGraph)
- .forEach(
- provisionDependent ->
- diagnosticReporter.reportDependency(
- ERROR,
- provisionDependent,
- provisionDependent.isEntryPoint()
- ? entryPointErrorMessage(provisionDependent)
- : dependencyErrorMessage(provisionDependent, bindingGraph)));
- }
-
- private Stream<DependencyEdge> provisionDependenciesOnProductionBindings(
- BindingGraph bindingGraph) {
- return bindingGraph.bindings().stream()
- .filter(binding -> binding.isProduction())
- .flatMap(binding -> incomingDependencies(binding, bindingGraph))
- .filter(edge -> !dependencyCanUseProduction(edge, bindingGraph));
- }
-
- /** Returns the dependencies on {@code binding}. */
- // TODO(dpb): Move to BindingGraph.
- private Stream<DependencyEdge> incomingDependencies(
- dagger.model.Binding binding, BindingGraph bindingGraph) {
- return bindingGraph.network().inEdges(binding).stream()
- .flatMap(instancesOf(DependencyEdge.class));
- }
-
- // TODO(ronshapiro): merge with MissingBindingValidator.dependencyCanUseProduction
- private boolean dependencyCanUseProduction(DependencyEdge edge, BindingGraph bindingGraph) {
- return edge.isEntryPoint()
- ? canBeSatisfiedByProductionBinding(edge.dependencyRequest().kind())
- : bindingRequestingDependency(edge, bindingGraph).isProduction();
- }
-
- /**
- * Returns the binding that requests a dependency.
- *
- * @throws IllegalArgumentException if {@code dependency} is an {@linkplain
- * DependencyEdge#isEntryPoint() entry point}.
- */
- // TODO(dpb): Move to BindingGraph.
- private dagger.model.Binding bindingRequestingDependency(
- DependencyEdge dependency, BindingGraph bindingGraph) {
- checkArgument(!dependency.isEntryPoint());
- Node source = bindingGraph.network().incidentNodes(dependency).source();
- verify(
- source instanceof dagger.model.Binding,
- "expected source of %s to be a binding, but was: %s",
- dependency,
- source);
- return (dagger.model.Binding) source;
- }
-
- private String entryPointErrorMessage(DependencyEdge entryPoint) {
- return String.format(
- "%s is a provision entry-point, which cannot depend on a production.",
- entryPoint.dependencyRequest().key());
- }
-
- private String dependencyErrorMessage(
- DependencyEdge dependencyOnProduction, BindingGraph bindingGraph) {
- return String.format(
- "%s is a provision, which cannot depend on a production.",
- bindingRequestingDependency(dependencyOnProduction, bindingGraph).key());
- }
-}
diff --git a/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java b/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
deleted file mode 100644
index bf83a69..0000000
--- a/java/dagger/internal/codegen/bindinggraphvalidation/SubcomponentFactoryMethodValidator.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.asTypeElements;
-import static com.google.common.collect.Sets.union;
-import static dagger.internal.codegen.binding.ComponentRequirement.componentCanMakeNewInstances;
-import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Sets.SetView;
-import dagger.internal.codegen.base.Util;
-import dagger.internal.codegen.binding.ComponentNodeImpl;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-
-/** Reports an error if a subcomponent factory method is missing required modules. */
-final class SubcomponentFactoryMethodValidator implements BindingGraphPlugin {
-
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
- private final Map<ComponentNode, Set<TypeElement>> inheritedModulesCache = new HashMap<>();
-
- @Inject
- SubcomponentFactoryMethodValidator(DaggerTypes types, KotlinMetadataUtil metadataUtil) {
- this.types = types;
- this.metadataUtil = metadataUtil;
- }
-
- @Override
- public String pluginName() {
- return "Dagger/SubcomponentFactoryMethodMissingModule";
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- if (!bindingGraph.rootComponentNode().isRealComponent()
- || bindingGraph.rootComponentNode().isSubcomponent()) {
- // We don't know all the modules that might be owned by the child until we know the real root
- // component, which we don't if the root component node is really a module or a subcomponent.
- return;
- }
- bindingGraph.network().edges().stream()
- .flatMap(instancesOf(ChildFactoryMethodEdge.class))
- .forEach(
- edge -> {
- ImmutableSet<TypeElement> missingModules = findMissingModules(edge, bindingGraph);
- if (!missingModules.isEmpty()) {
- reportMissingModuleParameters(
- edge, missingModules, bindingGraph, diagnosticReporter);
- }
- });
- }
-
- private ImmutableSet<TypeElement> findMissingModules(
- ChildFactoryMethodEdge edge, BindingGraph graph) {
- ImmutableSet<TypeElement> factoryMethodParameters =
- subgraphFactoryMethodParameters(edge, graph);
- ComponentNode child = (ComponentNode) graph.network().incidentNodes(edge).target();
- SetView<TypeElement> modulesOwnedByChild = ownedModules(child, graph);
- return graph.bindings().stream()
- // bindings owned by child
- .filter(binding -> binding.componentPath().equals(child.componentPath()))
- // that require a module instance
- .filter(binding -> binding.requiresModuleInstance())
- .map(binding -> binding.contributingModule().get())
- .distinct()
- // module owned by child
- .filter(module -> modulesOwnedByChild.contains(module))
- // module not in the method parameters
- .filter(module -> !factoryMethodParameters.contains(module))
- // module doesn't have an accessible no-arg constructor
- .filter(moduleType -> !componentCanMakeNewInstances(moduleType, metadataUtil))
- .collect(toImmutableSet());
- }
-
- private ImmutableSet<TypeElement> subgraphFactoryMethodParameters(
- ChildFactoryMethodEdge edge, BindingGraph bindingGraph) {
- ComponentNode parent = (ComponentNode) bindingGraph.network().incidentNodes(edge).source();
- DeclaredType parentType = asDeclared(parent.componentPath().currentComponent().asType());
- ExecutableType factoryMethodType =
- asExecutable(types.asMemberOf(parentType, edge.factoryMethod()));
- return asTypeElements(factoryMethodType.getParameterTypes());
- }
-
- private SetView<TypeElement> ownedModules(ComponentNode component, BindingGraph graph) {
- return Sets.difference(
- ((ComponentNodeImpl) component).componentDescriptor().moduleTypes(),
- inheritedModules(component, graph));
- }
-
- private Set<TypeElement> inheritedModules(ComponentNode component, BindingGraph graph) {
- return Util.reentrantComputeIfAbsent(
- inheritedModulesCache, component, uncachedInheritedModules(graph));
- }
-
- private Function<ComponentNode, Set<TypeElement>> uncachedInheritedModules(BindingGraph graph) {
- return componentNode ->
- componentNode.componentPath().atRoot()
- ? ImmutableSet.of()
- : graph
- .componentNode(componentNode.componentPath().parent())
- .map(parent -> union(ownedModules(parent, graph), inheritedModules(parent, graph)))
- .get();
- }
-
- private void reportMissingModuleParameters(
- ChildFactoryMethodEdge edge,
- ImmutableSet<TypeElement> missingModules,
- BindingGraph graph,
- DiagnosticReporter diagnosticReporter) {
- diagnosticReporter.reportSubcomponentFactoryMethod(
- ERROR,
- edge,
- "%s requires modules which have no visible default constructors. "
- + "Add the following modules as parameters to this method: %s",
- graph
- .network()
- .incidentNodes(edge)
- .target()
- .componentPath()
- .currentComponent()
- .getQualifiedName(),
- Joiner.on(", ").join(missingModules));
- }
-}
diff --git a/java/dagger/internal/codegen/bootstrap/BUILD b/java/dagger/internal/codegen/bootstrap/BUILD
deleted file mode 100644
index 2527d3c..0000000
--- a/java/dagger/internal/codegen/bootstrap/BUILD
+++ /dev/null
@@ -1,33 +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.
-
-# Description:
-# Bootstrap libraries for building Dagger with Dagger.
-
-load("@rules_java//java:defs.bzl", "java_import", "java_plugin")
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "bootstrap",
- generates_api = 1,
- processor_class = "dagger.internal.codegen.ComponentProcessor",
- deps = [":bootstrap_compiler"],
-)
-
-java_import(
- name = "bootstrap_compiler",
- jars = ["bootstrap_compiler_deploy.jar"],
- visibility = ["//visibility:private"],
-)
diff --git a/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar b/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
deleted file mode 100644
index b69dc65..0000000
--- a/java/dagger/internal/codegen/bootstrap/bootstrap_compiler_deploy.jar
+++ /dev/null
Binary files differ
diff --git a/java/dagger/internal/codegen/bootstrap_compiler_deploy.jar b/java/dagger/internal/codegen/bootstrap_compiler_deploy.jar
new file mode 100644
index 0000000..ad9761d
--- /dev/null
+++ b/java/dagger/internal/codegen/bootstrap_compiler_deploy.jar
Binary files differ
diff --git a/java/dagger/internal/codegen/compileroption/BUILD b/java/dagger/internal/codegen/compileroption/BUILD
deleted file mode 100644
index ef39b34..0000000
--- a/java/dagger/internal/codegen/compileroption/BUILD
+++ /dev/null
@@ -1,38 +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.
-
-# Description:
-# Sources related to compiler options.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "compileroption",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "@google_bazel_common//third_party/java/google_java_format",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/compileroption/CompilerOptions.java b/java/dagger/internal/codegen/compileroption/CompilerOptions.java
deleted file mode 100644
index a0d1cda..0000000
--- a/java/dagger/internal/codegen/compileroption/CompilerOptions.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2016 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.compileroption;
-
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
-
-/** A collection of options that dictate how the compiler will run. */
-public abstract class CompilerOptions {
- public abstract boolean usesProducers();
-
- /**
- * Returns true if the fast initialization flag, {@code fastInit}, is enabled.
- *
- * <p>If enabled, the generated code will attempt to optimize for fast component initialization.
- * This is done by reducing the number of factory classes loaded during initialization and the
- * number of eagerly initialized fields at the cost of potential memory leaks and higher
- * per-provision instantiation time.
- */
- public abstract boolean fastInit(TypeElement element);
-
- public abstract boolean formatGeneratedSource();
-
- public abstract boolean writeProducerNameInToken();
-
- public abstract Diagnostic.Kind nullableValidationKind();
-
- public final boolean doCheckForNulls() {
- return nullableValidationKind().equals(Diagnostic.Kind.ERROR);
- }
-
- public abstract Diagnostic.Kind privateMemberValidationKind();
-
- public abstract Diagnostic.Kind staticMemberValidationKind();
-
- /**
- * If {@code true}, Dagger will generate factories and components even if some members-injected
- * types have {@code private} or {@code static} {@code @Inject}-annotated members.
- *
- * <p>This should only ever be enabled by the TCK tests. Disabling this validation could lead to
- * generating code that does not compile.
- */
- public abstract boolean ignorePrivateAndStaticInjectionForComponent();
-
- public abstract ValidationType scopeCycleValidationType();
-
- /**
- * If {@code true}, Dagger will validate all transitive component dependencies of a component.
- * Otherwise, Dagger will only validate the direct component dependencies.
- *
- * <p>Note: this is different from scopeCycleValidationType, which lets you silence errors of
- * transitive component dependencies, but still requires the full transitive dependencies in the
- * classpath.
- *
- * <p>The main motivation for this flag is to prevent requiring the transitive component
- * dependencies in the classpath to speed up builds. See
- * https://github.com/google/dagger/issues/970.
- */
- public abstract boolean validateTransitiveComponentDependencies();
-
- public abstract boolean warnIfInjectionFactoryNotGeneratedUpstream();
-
- public abstract boolean headerCompilation();
-
- public abstract ValidationType fullBindingGraphValidationType();
-
- /**
- * If {@code true}, each plugin will visit the full binding graph for the given element.
- *
- * @throws IllegalArgumentException if {@code element} is not a module or (sub)component
- */
- public abstract boolean pluginsVisitFullBindingGraphs(TypeElement element);
-
- public abstract Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind();
-
- public abstract ValidationType explicitBindingConflictsWithInjectValidationType();
-
- public abstract boolean experimentalDaggerErrorMessages();
-
- /** Returns the number of bindings allowed per shard. */
- public int keysPerComponentShard(TypeElement component) {
- return 3500;
- }
-
- /**
- * This option enables a fix to an issue where Dagger previously would erroneously allow
- * multibinding contributions in a component to have dependencies on child components. This will
- * eventually become the default and enforced.
- */
- public abstract boolean strictMultibindingValidation();
-}
diff --git a/java/dagger/internal/codegen/compileroption/FeatureStatus.java b/java/dagger/internal/codegen/compileroption/FeatureStatus.java
deleted file mode 100644
index d989679..0000000
--- a/java/dagger/internal/codegen/compileroption/FeatureStatus.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2016 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.compileroption;
-
-/** Allows options to control how features in component processing are enabled. */
-public enum FeatureStatus {
- ENABLED,
- DISABLED;
-}
diff --git a/java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java b/java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java
deleted file mode 100644
index a86cc1b..0000000
--- a/java/dagger/internal/codegen/compileroption/JavacPluginCompilerOptions.java
+++ /dev/null
@@ -1,121 +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.internal.codegen.compileroption;
-
-import static dagger.internal.codegen.compileroption.ValidationType.NONE;
-import static javax.tools.Diagnostic.Kind.NOTE;
-
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
-
-/** {@link CompilerOptions} for Javac plugins (e.g. for Dagger statistics or Kythe). */
-public final class JavacPluginCompilerOptions extends CompilerOptions {
-
- @Inject
- JavacPluginCompilerOptions() {}
-
- @Override
- public boolean usesProducers() {
- return true;
- }
-
- @Override
- public boolean fastInit(TypeElement element) {
- return false;
- }
-
- @Override
- public boolean formatGeneratedSource() {
- return false;
- }
-
- @Override
- public boolean writeProducerNameInToken() {
- return true;
- }
-
- @Override
- public Diagnostic.Kind nullableValidationKind() {
- return NOTE;
- }
-
- @Override
- public Diagnostic.Kind privateMemberValidationKind() {
- return NOTE;
- }
-
- @Override
- public Diagnostic.Kind staticMemberValidationKind() {
- return NOTE;
- }
-
- @Override
- public boolean ignorePrivateAndStaticInjectionForComponent() {
- return false;
- }
-
- @Override
- public ValidationType scopeCycleValidationType() {
- return NONE;
- }
-
- @Override
- public boolean validateTransitiveComponentDependencies() {
- return true;
- }
-
- @Override
- public boolean warnIfInjectionFactoryNotGeneratedUpstream() {
- return false;
- }
-
- @Override
- public boolean headerCompilation() {
- return false;
- }
-
- @Override
- public ValidationType fullBindingGraphValidationType() {
- return NONE;
- }
-
- @Override
- public boolean pluginsVisitFullBindingGraphs(TypeElement element) {
- return false;
- }
-
- @Override
- public Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind() {
- return NOTE;
- }
-
- @Override
- public ValidationType explicitBindingConflictsWithInjectValidationType() {
- return NONE;
- }
-
- @Override
- public boolean experimentalDaggerErrorMessages() {
- return false;
- }
-
- @Override
- public boolean strictMultibindingValidation() {
- return false;
- }
-}
diff --git a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java b/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
deleted file mode 100644
index 06d15a2..0000000
--- a/java/dagger/internal/codegen/compileroption/ProcessingEnvironmentCompilerOptions.java
+++ /dev/null
@@ -1,520 +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.internal.codegen.compileroption;
-
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Sets.immutableEnumSet;
-import static dagger.internal.codegen.compileroption.FeatureStatus.DISABLED;
-import static dagger.internal.codegen.compileroption.FeatureStatus.ENABLED;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_ANDROID_MODE;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.EXPERIMENTAL_DAGGER_ERROR_MESSAGES;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FAST_INIT;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FLOATING_BINDS_METHODS;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.WRITE_PRODUCER_NAME_IN_TOKEN;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.KeyOnlyOption.HEADER_COMPILATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.KeyOnlyOption.USE_GRADLE_INCREMENTAL_PROCESSING;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.DISABLE_INTER_COMPONENT_SCOPE_VALIDATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.EXPLICIT_BINDING_CONFLICTS_WITH_INJECT;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.FULL_BINDING_GRAPH_VALIDATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.MODULE_HAS_DIFFERENT_SCOPES_VALIDATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.NULLABLE_VALIDATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.PRIVATE_MEMBER_VALIDATION;
-import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Validation.STATIC_MEMBER_VALIDATION;
-import static dagger.internal.codegen.compileroption.ValidationType.ERROR;
-import static dagger.internal.codegen.compileroption.ValidationType.NONE;
-import static dagger.internal.codegen.compileroption.ValidationType.WARNING;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Stream.concat;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.base.Ascii;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.producers.Produces;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Stream;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
-
-/** {@link CompilerOptions} for the given {@link ProcessingEnvironment}. */
-public final class ProcessingEnvironmentCompilerOptions extends CompilerOptions {
- // EnumOption<T> doesn't support integer inputs so just doing this as a 1-off for now.
- private static final String KEYS_PER_COMPONENT_SHARD = "dagger.keysPerComponentShard";
-
- private final ProcessingEnvironment processingEnvironment;
- private final DaggerElements daggerElements;
- private final Map<EnumOption<?>, Object> enumOptions = new HashMap<>();
- private final Map<EnumOption<?>, ImmutableMap<String, ? extends Enum<?>>> allCommandLineOptions =
- new HashMap<>();
-
- @Inject
- ProcessingEnvironmentCompilerOptions(
- ProcessingEnvironment processingEnvironment, DaggerElements daggerElements) {
- this.processingEnvironment = processingEnvironment;
- this.daggerElements = daggerElements;
- checkValid();
- }
-
- @Override
- public boolean usesProducers() {
- return processingEnvironment.getElementUtils().getTypeElement(Produces.class.getCanonicalName())
- != null;
- }
-
- @Override
- public boolean headerCompilation() {
- return isEnabled(HEADER_COMPILATION);
- }
-
- @Override
- public boolean fastInit(TypeElement component) {
- return isEnabled(FAST_INIT);
- }
-
- @Override
- public boolean formatGeneratedSource() {
- return isEnabled(FORMAT_GENERATED_SOURCE);
- }
-
- @Override
- public boolean writeProducerNameInToken() {
- return isEnabled(WRITE_PRODUCER_NAME_IN_TOKEN);
- }
-
- @Override
- public Diagnostic.Kind nullableValidationKind() {
- return diagnosticKind(NULLABLE_VALIDATION);
- }
-
- @Override
- public Diagnostic.Kind privateMemberValidationKind() {
- return diagnosticKind(PRIVATE_MEMBER_VALIDATION);
- }
-
- @Override
- public Diagnostic.Kind staticMemberValidationKind() {
- return diagnosticKind(STATIC_MEMBER_VALIDATION);
- }
-
- @Override
- public boolean ignorePrivateAndStaticInjectionForComponent() {
- return isEnabled(IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT);
- }
-
- @Override
- public ValidationType scopeCycleValidationType() {
- return parseOption(DISABLE_INTER_COMPONENT_SCOPE_VALIDATION);
- }
-
- @Override
- public boolean validateTransitiveComponentDependencies() {
- return isEnabled(VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES);
- }
-
- @Override
- public boolean warnIfInjectionFactoryNotGeneratedUpstream() {
- return isEnabled(WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM);
- }
-
- @Override
- public ValidationType fullBindingGraphValidationType() {
- return parseOption(FULL_BINDING_GRAPH_VALIDATION);
- }
-
- @Override
- public boolean pluginsVisitFullBindingGraphs(TypeElement component) {
- return isEnabled(PLUGINS_VISIT_FULL_BINDING_GRAPHS);
- }
-
- @Override
- public Diagnostic.Kind moduleHasDifferentScopesDiagnosticKind() {
- return diagnosticKind(MODULE_HAS_DIFFERENT_SCOPES_VALIDATION);
- }
-
- @Override
- public ValidationType explicitBindingConflictsWithInjectValidationType() {
- return parseOption(EXPLICIT_BINDING_CONFLICTS_WITH_INJECT);
- }
-
- @Override
- public boolean experimentalDaggerErrorMessages() {
- return isEnabled(EXPERIMENTAL_DAGGER_ERROR_MESSAGES);
- }
-
- @Override
- public boolean strictMultibindingValidation() {
- return isEnabled(STRICT_MULTIBINDING_VALIDATION);
- }
-
- @Override
- public int keysPerComponentShard(TypeElement component) {
- if (processingEnvironment.getOptions().containsKey(KEYS_PER_COMPONENT_SHARD)) {
- checkArgument(
- "dagger.internal.codegen".contentEquals(
- MoreElements.getPackage(component).getQualifiedName()),
- "Cannot set %s. It is only meant for internal testing.", KEYS_PER_COMPONENT_SHARD);
- return Integer.parseInt(
- processingEnvironment.getOptions().get(KEYS_PER_COMPONENT_SHARD));
- }
- return super.keysPerComponentShard(component);
- }
-
- private boolean isEnabled(KeyOnlyOption keyOnlyOption) {
- return processingEnvironment.getOptions().containsKey(keyOnlyOption.toString());
- }
-
- private boolean isEnabled(Feature feature) {
- return parseOption(feature).equals(ENABLED);
- }
-
- private Diagnostic.Kind diagnosticKind(Validation validation) {
- return parseOption(validation).diagnosticKind().get();
- }
-
- @SuppressWarnings("CheckReturnValue")
- private ProcessingEnvironmentCompilerOptions checkValid() {
- for (KeyOnlyOption keyOnlyOption : KeyOnlyOption.values()) {
- isEnabled(keyOnlyOption);
- }
- for (Feature feature : Feature.values()) {
- parseOption(feature);
- }
- for (Validation validation : Validation.values()) {
- parseOption(validation);
- }
- noLongerRecognized(EXPERIMENTAL_ANDROID_MODE);
- noLongerRecognized(FLOATING_BINDS_METHODS);
- noLongerRecognized(EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS);
- noLongerRecognized(USE_GRADLE_INCREMENTAL_PROCESSING);
- return this;
- }
-
- private void noLongerRecognized(CommandLineOption commandLineOption) {
- if (processingEnvironment.getOptions().containsKey(commandLineOption.toString())) {
- processingEnvironment
- .getMessager()
- .printMessage(
- Diagnostic.Kind.WARNING, commandLineOption + " is no longer recognized by Dagger");
- }
- }
-
- private interface CommandLineOption {
- /** The key of the option (appears after "-A"). */
- @Override
- String toString();
-
- /**
- * Returns all aliases besides {@link #toString()}, such as old names for an option, in order of
- * precedence.
- */
- default ImmutableList<String> aliases() {
- return ImmutableList.of();
- }
-
- /** All the command-line names for this option, in order of precedence. */
- default Stream<String> allNames() {
- return concat(Stream.of(toString()), aliases().stream());
- }
- }
-
- /** An option that can be set on the command line. */
- private interface EnumOption<E extends Enum<E>> extends CommandLineOption {
- /** The default value for this option. */
- E defaultValue();
-
- /** The valid values for this option. */
- Set<E> validValues();
- }
-
- enum KeyOnlyOption implements CommandLineOption {
- HEADER_COMPILATION {
- @Override
- public String toString() {
- return "experimental_turbine_hjar";
- }
- },
-
- USE_GRADLE_INCREMENTAL_PROCESSING {
- @Override
- public String toString() {
- return "dagger.gradle.incremental";
- }
- },
- }
-
- /**
- * A feature that can be enabled or disabled on the command line by setting {@code -Akey=ENABLED}
- * or {@code -Akey=DISABLED}.
- */
- enum Feature implements EnumOption<FeatureStatus> {
- FAST_INIT,
-
- EXPERIMENTAL_ANDROID_MODE,
-
- FORMAT_GENERATED_SOURCE,
-
- WRITE_PRODUCER_NAME_IN_TOKEN,
-
- WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM,
-
- IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT,
-
- EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS,
-
- FORCE_USE_SERIALIZED_COMPONENT_IMPLEMENTATIONS,
-
- EMIT_MODIFIABLE_METADATA_ANNOTATIONS(ENABLED),
-
- PLUGINS_VISIT_FULL_BINDING_GRAPHS,
-
- FLOATING_BINDS_METHODS,
-
- EXPERIMENTAL_DAGGER_ERROR_MESSAGES,
-
- STRICT_MULTIBINDING_VALIDATION,
-
- VALIDATE_TRANSITIVE_COMPONENT_DEPENDENCIES(ENABLED)
- ;
-
- final FeatureStatus defaultValue;
-
- Feature() {
- this(DISABLED);
- }
-
- Feature(FeatureStatus defaultValue) {
- this.defaultValue = defaultValue;
- }
-
- @Override
- public FeatureStatus defaultValue() {
- return defaultValue;
- }
-
- @Override
- public Set<FeatureStatus> validValues() {
- return EnumSet.allOf(FeatureStatus.class);
- }
-
- @Override
- public String toString() {
- return optionName(this);
- }
- }
-
- /** The diagnostic kind or validation type for a kind of validation. */
- enum Validation implements EnumOption<ValidationType> {
- DISABLE_INTER_COMPONENT_SCOPE_VALIDATION(),
-
- NULLABLE_VALIDATION(ERROR, WARNING),
-
- PRIVATE_MEMBER_VALIDATION(ERROR, WARNING),
-
- STATIC_MEMBER_VALIDATION(ERROR, WARNING),
-
- /** Whether to validate full binding graphs for components, subcomponents, and modules. */
- FULL_BINDING_GRAPH_VALIDATION(NONE, ERROR, WARNING) {
- @Override
- public ImmutableList<String> aliases() {
- return ImmutableList.of("dagger.moduleBindingValidation");
- }
- },
-
- /**
- * How to report conflicting scoped bindings when validating partial binding graphs associated
- * with modules.
- */
- MODULE_HAS_DIFFERENT_SCOPES_VALIDATION(ERROR, WARNING),
-
- /**
- * How to report that an explicit binding in a subcomponent conflicts with an {@code @Inject}
- * constructor used in an ancestor component.
- */
- EXPLICIT_BINDING_CONFLICTS_WITH_INJECT(WARNING, ERROR, NONE),
- ;
-
- final ValidationType defaultType;
- final ImmutableSet<ValidationType> validTypes;
-
- Validation() {
- this(ERROR, WARNING, NONE);
- }
-
- Validation(ValidationType defaultType, ValidationType... moreValidTypes) {
- this.defaultType = defaultType;
- this.validTypes = immutableEnumSet(defaultType, moreValidTypes);
- }
-
- @Override
- public ValidationType defaultValue() {
- return defaultType;
- }
-
- @Override
- public Set<ValidationType> validValues() {
- return validTypes;
- }
-
- @Override
- public String toString() {
- return optionName(this);
- }
- }
-
- private static String optionName(Enum<? extends EnumOption<?>> option) {
- return "dagger." + UPPER_UNDERSCORE.to(LOWER_CAMEL, option.name());
- }
-
- /** The supported command-line options. */
- public static ImmutableSet<String> supportedOptions() {
- // need explicit type parameter to avoid a runtime stream error
- return ImmutableSet.<String>builder()
- .addAll(
- Stream.<CommandLineOption[]>of(
- KeyOnlyOption.values(), Feature.values(), Validation.values())
- .flatMap(Arrays::stream)
- .flatMap(CommandLineOption::allNames)
- .collect(toImmutableSet()))
- .add(KEYS_PER_COMPONENT_SHARD)
- .build();
- }
-
- /**
- * Returns the value for the option as set on the command line by any name, or the default value
- * if not set.
- *
- * <p>If more than one name is used to set the value, but all names specify the same value,
- * reports a warning and returns that value.
- *
- * <p>If more than one name is used to set the value, and not all names specify the same value,
- * reports an error and returns the default value.
- */
- private <T extends Enum<T>> T parseOption(EnumOption<T> option) {
- @SuppressWarnings("unchecked") // we only put covariant values into the map
- T value = (T) enumOptions.computeIfAbsent(option, this::parseOptionUncached);
- return value;
- }
-
- private boolean isSetOnCommandLine(Feature feature) {
- return getUsedNames(feature).count() > 0;
- }
-
- private <T extends Enum<T>> T parseOptionUncached(EnumOption<T> option) {
- ImmutableMap<String, T> values = parseOptionWithAllNames(option);
-
- // If no value is specified, return the default value.
- if (values.isEmpty()) {
- return option.defaultValue();
- }
-
- // If all names have the same value, return that.
- if (values.asMultimap().inverse().keySet().size() == 1) {
- // Warn if an option was set with more than one name. That would be an error if the values
- // differed.
- if (values.size() > 1) {
- reportUseOfDifferentNamesForOption(Diagnostic.Kind.WARNING, option, values.keySet());
- }
- return values.values().asList().get(0);
- }
-
- // If different names have different values, report an error and return the default
- // value.
- reportUseOfDifferentNamesForOption(Diagnostic.Kind.ERROR, option, values.keySet());
- return option.defaultValue();
- }
-
- private void reportUseOfDifferentNamesForOption(
- Diagnostic.Kind diagnosticKind, EnumOption<?> option, ImmutableSet<String> usedNames) {
- processingEnvironment
- .getMessager()
- .printMessage(
- diagnosticKind,
- String.format(
- "Only one of the equivalent options (%s) should be used; prefer -A%s",
- usedNames.stream().map(name -> "-A" + name).collect(joining(", ")), option));
- }
-
- private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNames(
- EnumOption<T> option) {
- @SuppressWarnings("unchecked") // map is covariant
- ImmutableMap<String, T> aliasValues =
- (ImmutableMap<String, T>)
- allCommandLineOptions.computeIfAbsent(option, this::parseOptionWithAllNamesUncached);
- return aliasValues;
- }
-
- private <T extends Enum<T>> ImmutableMap<String, T> parseOptionWithAllNamesUncached(
- EnumOption<T> option) {
- ImmutableMap.Builder<String, T> values = ImmutableMap.builder();
- getUsedNames(option)
- .forEach(
- name -> parseOptionWithName(option, name).ifPresent(value -> values.put(name, value)));
- return values.build();
- }
-
- private <T extends Enum<T>> Optional<T> parseOptionWithName(EnumOption<T> option, String key) {
- checkArgument(processingEnvironment.getOptions().containsKey(key), "key %s not found", key);
- String stringValue = processingEnvironment.getOptions().get(key);
- if (stringValue == null) {
- processingEnvironment
- .getMessager()
- .printMessage(Diagnostic.Kind.ERROR, "Processor option -A" + key + " needs a value");
- } else {
- try {
- T value =
- Enum.valueOf(option.defaultValue().getDeclaringClass(), Ascii.toUpperCase(stringValue));
- if (option.validValues().contains(value)) {
- return Optional.of(value);
- }
- } catch (IllegalArgumentException e) {
- // handled below
- }
- processingEnvironment
- .getMessager()
- .printMessage(
- Diagnostic.Kind.ERROR,
- String.format(
- "Processor option -A%s may only have the values %s "
- + "(case insensitive), found: %s",
- key, option.validValues(), stringValue));
- }
- return Optional.empty();
- }
-
- private Stream<String> getUsedNames(CommandLineOption option) {
- return option.allNames().filter(name -> processingEnvironment.getOptions().containsKey(name));
- }
-}
diff --git a/java/dagger/internal/codegen/compileroption/ProcessingOptions.java b/java/dagger/internal/codegen/compileroption/ProcessingOptions.java
deleted file mode 100644
index 39c4728..0000000
--- a/java/dagger/internal/codegen/compileroption/ProcessingOptions.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 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.compileroption;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * A qualifier for the {@link javax.annotation.processing.ProcessingEnvironment#getOptions()
- * processing options} passed to the current invocation of {@code javac}.
- */
-@Retention(RUNTIME)
-@Qualifier
-public @interface ProcessingOptions {}
diff --git a/java/dagger/internal/codegen/compileroption/ValidationType.java b/java/dagger/internal/codegen/compileroption/ValidationType.java
deleted file mode 100644
index d7be4ca..0000000
--- a/java/dagger/internal/codegen/compileroption/ValidationType.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.compileroption;
-
-import java.util.Optional;
-import javax.tools.Diagnostic;
-
-/**
- * Allows options to control how component process validates things such as scope cycles or
- * nullability.
- */
-public enum ValidationType {
- ERROR,
- WARNING,
- NONE;
-
- public Optional<Diagnostic.Kind> diagnosticKind() {
- switch (this) {
- case ERROR:
- return Optional.of(Diagnostic.Kind.ERROR);
- case WARNING:
- return Optional.of(Diagnostic.Kind.WARNING);
- default:
- return Optional.empty();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/BUILD b/java/dagger/internal/codegen/componentgenerator/BUILD
deleted file mode 100644
index d898d4d..0000000
--- a/java/dagger/internal/codegen/componentgenerator/BUILD
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A JSR-330 compliant dependency injection system for android and java
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "componentgenerator",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/writing",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentCreatorImplementationFactory.java b/java/dagger/internal/codegen/componentgenerator/ComponentCreatorImplementationFactory.java
deleted file mode 100644
index e1b35da..0000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentCreatorImplementationFactory.java
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (C) 2017 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.componentgenerator;
-
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeSpecs.addSupertype;
-import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.Preconditions;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ComponentRequirement.NullPolicy;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.ComponentCreatorImplementation;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.ModuleProxies;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-
-/** Factory for creating {@link ComponentCreatorImplementation} instances. */
-final class ComponentCreatorImplementationFactory {
-
- private final ComponentImplementation componentImplementation;
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
- private final ModuleProxies moduleProxies;
-
- @Inject
- ComponentCreatorImplementationFactory(
- ComponentImplementation componentImplementation,
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil metadataUtil,
- ModuleProxies moduleProxies) {
- this.componentImplementation = componentImplementation;
- this.elements = elements;
- this.types = types;
- this.metadataUtil = metadataUtil;
- this.moduleProxies = moduleProxies;
- }
-
- /** Returns a new creator implementation for the given component, if necessary. */
- Optional<ComponentCreatorImplementation> create() {
- if (!componentImplementation.componentDescriptor().hasCreator()) {
- return Optional.empty();
- }
-
- Optional<ComponentCreatorDescriptor> creatorDescriptor =
- componentImplementation.componentDescriptor().creatorDescriptor();
-
- Builder builder =
- creatorDescriptor.isPresent()
- ? new BuilderForCreatorDescriptor(componentImplementation, creatorDescriptor.get())
- : new BuilderForGeneratedRootComponentBuilder(componentImplementation);
- return Optional.of(builder.build());
- }
-
- /** Base class for building a creator implementation. */
- private abstract class Builder {
- final ComponentImplementation componentImplementation;
- final ClassName className;
- final TypeSpec.Builder classBuilder;
-
- private ImmutableMap<ComponentRequirement, FieldSpec> fields;
-
- Builder(ComponentImplementation componentImplementation) {
- this.componentImplementation = componentImplementation;
- this.className = componentImplementation.getCreatorName();
- this.classBuilder = classBuilder(className);
- }
-
- /** Builds the {@link ComponentCreatorImplementation}. */
- ComponentCreatorImplementation build() {
- setModifiers();
- setSupertype();
- this.fields = addFields();
- addConstructor();
- addSetterMethods();
- addFactoryMethod();
- return ComponentCreatorImplementation.create(classBuilder.build(), className, fields);
- }
-
- /** Returns the descriptor for the component. */
- final ComponentDescriptor componentDescriptor() {
- return componentImplementation.componentDescriptor();
- }
-
- /**
- * The set of requirements that must be passed to the component's constructor in the order
- * they must be passed.
- */
- final ImmutableSet<ComponentRequirement> componentConstructorRequirements() {
- return componentImplementation.graph().componentRequirements();
- }
-
- /** Returns the requirements that have setter methods on the creator type. */
- abstract ImmutableSet<ComponentRequirement> setterMethods();
-
- /**
- * Returns the component requirements that have factory method parameters, mapped to the name
- * for that parameter.
- */
- abstract ImmutableMap<ComponentRequirement, String> factoryMethodParameters();
-
- /**
- * The {@link ComponentRequirement}s that this creator allows users to set. Values are a status
- * for each requirement indicating what's needed for that requirement in the implementation
- * class currently being generated.
- */
- abstract ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements();
-
- /**
- * Component requirements that are both settable by the creator and needed to construct the
- * component.
- */
- private Set<ComponentRequirement> neededUserSettableRequirements() {
- return Sets.intersection(
- userSettableRequirements().keySet(), componentConstructorRequirements());
- }
-
- private void setModifiers() {
- visibility().ifPresent(classBuilder::addModifiers);
- if (!componentImplementation.isNested()) {
- classBuilder.addModifiers(STATIC);
- }
- classBuilder.addModifiers(FINAL);
- }
-
- /** Returns the visibility modifier the generated class should have, if any. */
- protected abstract Optional<Modifier> visibility();
-
- /** Sets the superclass being extended or interface being implemented for this creator. */
- protected abstract void setSupertype();
-
- /** Adds a constructor for the creator type, if needed. */
- protected abstract void addConstructor();
-
- private ImmutableMap<ComponentRequirement, FieldSpec> addFields() {
- // Fields in an abstract creator class need to be visible from subclasses.
- UniqueNameSet fieldNames = new UniqueNameSet();
- ImmutableMap<ComponentRequirement, FieldSpec> result =
- Maps.toMap(
- Sets.intersection(neededUserSettableRequirements(), setterMethods()),
- requirement ->
- FieldSpec.builder(
- TypeName.get(requirement.type()),
- fieldNames.getUniqueName(requirement.variableName()),
- PRIVATE)
- .build());
- classBuilder.addFields(result.values());
- return result;
- }
-
- private void addSetterMethods() {
- Maps.filterKeys(userSettableRequirements(), setterMethods()::contains)
- .forEach(
- (requirement, status) ->
- createSetterMethod(requirement, status).ifPresent(classBuilder::addMethod));
- }
-
- /** Creates a new setter method builder, with no method body, for the given requirement. */
- protected abstract MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement);
-
- private Optional<MethodSpec> createSetterMethod(
- ComponentRequirement requirement, RequirementStatus status) {
- switch (status) {
- case NEEDED:
- return Optional.of(normalSetterMethod(requirement));
- case UNNEEDED:
- // TODO(bcorso): Don't generate noop setters for any unneeded requirements.
- // However, since this is a breaking change we can at least avoid trying
- // to generate noop setters for impossible cases like when the requirement type
- // is in another package. This avoids unnecessary breakages in Dagger's generated
- // due to the noop setters.
- if (isElementAccessibleFrom(requirement.typeElement(), className.packageName())) {
- return Optional.of(noopSetterMethod(requirement));
- } else {
- return Optional.empty();
- }
- case UNSETTABLE_REPEATED_MODULE:
- return Optional.of(repeatedModuleSetterMethod(requirement));
- }
- throw new AssertionError();
- }
-
- private MethodSpec normalSetterMethod(ComponentRequirement requirement) {
- MethodSpec.Builder method = setterMethodBuilder(requirement);
- ParameterSpec parameter = parameter(method.build());
- method.addStatement(
- "this.$N = $L",
- fields.get(requirement),
- requirement.nullPolicy(elements, types, metadataUtil).equals(NullPolicy.ALLOW)
- ? CodeBlock.of("$N", parameter)
- : CodeBlock.of("$T.checkNotNull($N)", Preconditions.class, parameter));
- return maybeReturnThis(method);
- }
-
- private MethodSpec noopSetterMethod(ComponentRequirement requirement) {
- MethodSpec.Builder method = setterMethodBuilder(requirement);
- ParameterSpec parameter = parameter(method.build());
- method
- .addAnnotation(Deprecated.class)
- .addJavadoc(
- "@deprecated This module is declared, but an instance is not used in the component. "
- + "This method is a no-op. For more, see https://dagger.dev/unused-modules.\n")
- .addStatement("$T.checkNotNull($N)", Preconditions.class, parameter);
- return maybeReturnThis(method);
- }
-
- private MethodSpec repeatedModuleSetterMethod(ComponentRequirement requirement) {
- return setterMethodBuilder(requirement)
- .addStatement(
- "throw new $T($T.format($S, $T.class.getCanonicalName()))",
- UnsupportedOperationException.class,
- String.class,
- "%s cannot be set because it is inherited from the enclosing component",
- TypeNames.rawTypeName(TypeName.get(requirement.type())))
- .build();
- }
-
- private ParameterSpec parameter(MethodSpec method) {
- return getOnlyElement(method.parameters);
- }
-
- private MethodSpec maybeReturnThis(MethodSpec.Builder method) {
- MethodSpec built = method.build();
- return built.returnType.equals(TypeName.VOID)
- ? built
- : method.addStatement("return this").build();
- }
-
- private void addFactoryMethod() {
- classBuilder.addMethod(factoryMethod());
- }
-
- MethodSpec factoryMethod() {
- MethodSpec.Builder factoryMethod = factoryMethodBuilder();
- factoryMethod
- .returns(ClassName.get(componentDescriptor().typeElement()))
- .addModifiers(PUBLIC);
-
- ImmutableMap<ComponentRequirement, String> factoryMethodParameters =
- factoryMethodParameters();
- userSettableRequirements()
- .keySet()
- .forEach(
- requirement -> {
- if (fields.containsKey(requirement)) {
- FieldSpec field = fields.get(requirement);
- addNullHandlingForField(requirement, field, factoryMethod);
- } else if (factoryMethodParameters.containsKey(requirement)) {
- String parameterName = factoryMethodParameters.get(requirement);
- addNullHandlingForParameter(requirement, parameterName, factoryMethod);
- }
- });
- factoryMethod.addStatement(
- "return new $T($L)",
- componentImplementation.name(),
- componentConstructorArgs(factoryMethodParameters));
- return factoryMethod.build();
- }
-
- private void addNullHandlingForField(
- ComponentRequirement requirement, FieldSpec field, MethodSpec.Builder factoryMethod) {
- switch (requirement.nullPolicy(elements, types, metadataUtil)) {
- case NEW:
- checkState(requirement.kind().isModule());
- factoryMethod
- .beginControlFlow("if ($N == null)", field)
- .addStatement("this.$N = $L", field, newModuleInstance(requirement))
- .endControlFlow();
- break;
- case THROW:
- // TODO(cgdecker,ronshapiro): ideally this should use the key instead of a class for
- // @BindsInstance requirements, but that's not easily proguardable.
- factoryMethod.addStatement(
- "$T.checkBuilderRequirement($N, $T.class)",
- Preconditions.class,
- field,
- TypeNames.rawTypeName(field.type));
- break;
- case ALLOW:
- break;
- }
- }
-
- private void addNullHandlingForParameter(
- ComponentRequirement requirement, String parameter, MethodSpec.Builder factoryMethod) {
- if (!requirement.nullPolicy(elements, types, metadataUtil).equals(NullPolicy.ALLOW)) {
- // Factory method parameters are always required unless they are a nullable
- // binds-instance (i.e. ALLOW)
- factoryMethod.addStatement("$T.checkNotNull($L)", Preconditions.class, parameter);
- }
- }
-
- /** Returns a builder for the creator's factory method. */
- protected abstract MethodSpec.Builder factoryMethodBuilder();
-
- private CodeBlock componentConstructorArgs(
- ImmutableMap<ComponentRequirement, String> factoryMethodParameters) {
- return componentConstructorRequirements().stream()
- .map(
- requirement -> {
- if (fields.containsKey(requirement)) {
- return CodeBlock.of("$N", fields.get(requirement));
- } else if (factoryMethodParameters.containsKey(requirement)) {
- return CodeBlock.of("$L", factoryMethodParameters.get(requirement));
- } else {
- return newModuleInstance(requirement);
- }
- })
- .collect(toParametersCodeBlock());
- }
-
- private CodeBlock newModuleInstance(ComponentRequirement requirement) {
- checkArgument(requirement.kind().isModule()); // this should be guaranteed to be true here
- return moduleProxies.newModuleInstance(requirement.typeElement(), className);
- }
- }
-
- /** Builder for a creator type defined by a {@code ComponentCreatorDescriptor}. */
- private final class BuilderForCreatorDescriptor extends Builder {
- final ComponentCreatorDescriptor creatorDescriptor;
-
- BuilderForCreatorDescriptor(
- ComponentImplementation componentImplementation,
- ComponentCreatorDescriptor creatorDescriptor) {
- super(componentImplementation);
- this.creatorDescriptor = creatorDescriptor;
- }
-
- @Override
- protected ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements() {
- return Maps.toMap(creatorDescriptor.userSettableRequirements(), this::requirementStatus);
- }
-
- @Override
- protected Optional<Modifier> visibility() {
- return Optional.of(PRIVATE);
- }
-
- @Override
- protected void setSupertype() {
- addSupertype(classBuilder, creatorDescriptor.typeElement());
- }
-
- @Override
- protected void addConstructor() {
- // Just use the implicit no-arg public constructor.
- }
-
- @Override
- protected ImmutableSet<ComponentRequirement> setterMethods() {
- return ImmutableSet.copyOf(creatorDescriptor.setterMethods().keySet());
- }
-
- @Override
- protected ImmutableMap<ComponentRequirement, String> factoryMethodParameters() {
- return ImmutableMap.copyOf(
- Maps.transformValues(
- creatorDescriptor.factoryParameters(),
- element -> element.getSimpleName().toString()));
- }
-
- private DeclaredType creatorType() {
- return asDeclared(creatorDescriptor.typeElement().asType());
- }
-
- @Override
- protected MethodSpec.Builder factoryMethodBuilder() {
- return MethodSpec.overriding(creatorDescriptor.factoryMethod(), creatorType(), types);
- }
-
- private RequirementStatus requirementStatus(ComponentRequirement requirement) {
- if (isRepeatedModule(requirement)) {
- return RequirementStatus.UNSETTABLE_REPEATED_MODULE;
- }
-
- return componentConstructorRequirements().contains(requirement)
- ? RequirementStatus.NEEDED
- : RequirementStatus.UNNEEDED;
- }
-
- /**
- * Returns whether the given requirement is for a repeat of a module inherited from an ancestor
- * component. This creator is not allowed to set such a module.
- */
- final boolean isRepeatedModule(ComponentRequirement requirement) {
- return !componentConstructorRequirements().contains(requirement)
- && !isOwnedModule(requirement);
- }
-
- /**
- * Returns whether the given {@code requirement} is for a module type owned by the component.
- */
- private boolean isOwnedModule(ComponentRequirement requirement) {
- return componentImplementation.graph().ownedModuleTypes().contains(requirement.typeElement());
- }
-
- @Override
- protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
- ExecutableElement supertypeMethod = creatorDescriptor.setterMethods().get(requirement);
- MethodSpec.Builder method = MethodSpec.overriding(supertypeMethod, creatorType(), types);
- if (!supertypeMethod.getReturnType().getKind().equals(TypeKind.VOID)) {
- // Take advantage of covariant returns so that we don't have to worry about type variables
- method.returns(className);
- }
- return method;
- }
- }
-
- /**
- * Builder for a component builder class that is automatically generated for a root component that
- * does not have its own user-defined creator type (i.e. a {@code ComponentCreatorDescriptor}).
- */
- private final class BuilderForGeneratedRootComponentBuilder extends Builder {
- BuilderForGeneratedRootComponentBuilder(ComponentImplementation componentImplementation) {
- super(componentImplementation);
- }
-
- @Override
- protected ImmutableMap<ComponentRequirement, RequirementStatus> userSettableRequirements() {
- return Maps.toMap(
- setterMethods(),
- requirement ->
- componentConstructorRequirements().contains(requirement)
- ? RequirementStatus.NEEDED
- : RequirementStatus.UNNEEDED);
- }
-
- @Override
- protected Optional<Modifier> visibility() {
- return componentImplementation
- .componentDescriptor()
- .typeElement()
- .getModifiers()
- .contains(PUBLIC) ? Optional.of(PUBLIC) : Optional.empty();
- }
-
- @Override
- protected void setSupertype() {
- // There's never a supertype for a root component auto-generated builder type.
- }
-
- @Override
- protected void addConstructor() {
- classBuilder.addMethod(constructorBuilder().addModifiers(PRIVATE).build());
- }
-
- @Override
- protected ImmutableSet<ComponentRequirement> setterMethods() {
- return componentDescriptor().dependenciesAndConcreteModules();
- }
-
- @Override
- protected ImmutableMap<ComponentRequirement, String> factoryMethodParameters() {
- return ImmutableMap.of();
- }
-
- @Override
- protected MethodSpec.Builder factoryMethodBuilder() {
- return methodBuilder("build");
- }
-
- @Override
- protected MethodSpec.Builder setterMethodBuilder(ComponentRequirement requirement) {
- String name = simpleVariableName(requirement.typeElement());
- return methodBuilder(name)
- .addModifiers(PUBLIC)
- .addParameter(TypeName.get(requirement.type()), name)
- .returns(className);
- }
- }
-
- /** Enumeration of statuses a component requirement may have in a creator. */
- enum RequirementStatus {
- /** An instance is needed to create the component. */
- NEEDED,
-
- /**
- * An instance is not needed to create the component, but the requirement is for a module owned
- * by the component. Setting the requirement is a no-op and any setter method should be marked
- * deprecated on the generated type as a warning to the user.
- */
- UNNEEDED,
-
- /**
- * The requirement may not be set in this creator because the module it is for is already
- * inherited from an ancestor component. Any setter method for it should throw an exception.
- */
- UNSETTABLE_REPEATED_MODULE,
- ;
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java b/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java
deleted file mode 100644
index e04ee14..0000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentGenerator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2014 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.componentgenerator;
-
-import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.binding.SourceFiles.classFileName;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.Component;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/** Generates the implementation of the abstract types annotated with {@link Component}. */
-final class ComponentGenerator extends SourceFileGenerator<BindingGraph> {
- private final ComponentImplementationFactory componentImplementationFactory;
-
- @Inject
- ComponentGenerator(
- Filer filer,
- DaggerElements elements,
- SourceVersion sourceVersion,
- ComponentImplementationFactory componentImplementationFactory) {
- super(filer, elements, sourceVersion);
- this.componentImplementationFactory = componentImplementationFactory;
- }
-
- @Override
- public ClassName nameGeneratedType(BindingGraph input) {
- return componentName(input.componentTypeElement());
- }
-
- static ClassName componentName(TypeElement componentDefinitionType) {
- ClassName componentName = ClassName.get(componentDefinitionType);
- return ClassName.get(componentName.packageName(), "Dagger" + classFileName(componentName));
- }
-
- @Override
- public Element originatingElement(BindingGraph input) {
- return input.componentTypeElement();
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(BindingGraph bindingGraph) {
- ComponentImplementation componentImplementation =
- componentImplementationFactory.createComponentImplementation(bindingGraph);
- verify(componentImplementation.name().equals(nameGeneratedType(bindingGraph)));
- return Optional.of(componentImplementation.generate());
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentGeneratorModule.java b/java/dagger/internal/codegen/componentgenerator/ComponentGeneratorModule.java
deleted file mode 100644
index 84179d6..0000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentGeneratorModule.java
+++ /dev/null
@@ -1,48 +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.internal.codegen.componentgenerator;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.multibindings.IntoSet;
-
-/** Provides bindings needed to generated the component. */
-@Module(subcomponents = TopLevelImplementationComponent.class)
-public interface ComponentGeneratorModule {
-
- @Binds
- abstract SourceFileGenerator<BindingGraph> componentGenerator(ComponentGenerator generator);
-
- // The HjarSourceFileGenerator wrapper first generates the entire TypeSpec before stripping out
- // things that aren't needed for the hjar. However, this can be really expensive for the component
- // because it is usually the most expensive file to generate, and most of its content is not
- // needed in the hjar. Thus, instead of wrapping the ComponentGenerator in HjarSourceFileGenerator
- // we provide a completely separate processing step, ComponentHjarProcessingStep, and generator,
- // ComponentHjarGenerator, for when generating hjars for components, which can avoid generating
- // the parts of the component that would have been stripped out by the HjarSourceFileGenerator.
- @Binds
- abstract SourceFileGenerator<ComponentDescriptor> componentHjarGenerator(
- ComponentHjarGenerator hjarGenerator);
-
- @Binds
- @IntoSet
- ClearableCache componentImplementationFactory(ComponentImplementationFactory cache);
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java b/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
deleted file mode 100644
index b386a4f..0000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentHjarGenerator.java
+++ /dev/null
@@ -1,269 +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.internal.codegen.componentgenerator;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.componentgenerator.ComponentGenerator.componentName;
-import static dagger.internal.codegen.javapoet.TypeSpecs.addSupertype;
-import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Ascii;
-import com.google.common.collect.Sets;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.BindsInstance;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.internal.CancellationListener;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Stream;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-
-/**
- * A component generator that emits only API, without any actual implementation.
- *
- * <p>When compiling a header jar (hjar), Bazel needs to run annotation processors that generate
- * API, like Dagger, to see what code they might output. Full binding graph analysis is costly and
- * unnecessary from the perspective of the header compiler; it's sole goal is to pass along a
- * slimmed down version of what will be the jar for a particular compilation, whether or not that
- * compilation succeeds. If it does not, the compilation pipeline will fail, even if header
- * compilation succeeded.
- *
- * <p>The components emitted by this processing step include all of the API elements exposed by the
- * normal step. Method bodies are omitted as Turbine ignores them entirely.
- */
-final class ComponentHjarGenerator extends SourceFileGenerator<ComponentDescriptor> {
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- ComponentHjarGenerator(
- Filer filer,
- DaggerElements elements,
- DaggerTypes types,
- SourceVersion sourceVersion,
- KotlinMetadataUtil metadataUtil) {
- super(filer, elements, sourceVersion);
- this.elements = elements;
- this.types = types;
- this.metadataUtil = metadataUtil;
- }
-
- @Override
- public ClassName nameGeneratedType(ComponentDescriptor input) {
- return componentName(input.typeElement());
- }
-
- @Override
- public Element originatingElement(ComponentDescriptor input) {
- return input.typeElement();
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(ComponentDescriptor componentDescriptor) {
- ClassName generatedTypeName = nameGeneratedType(componentDescriptor);
- TypeSpec.Builder generatedComponent =
- TypeSpec.classBuilder(generatedTypeName)
- .addModifiers(FINAL)
- .addMethod(privateConstructor());
- if (componentDescriptor.typeElement().getModifiers().contains(PUBLIC)) {
- generatedComponent.addModifiers(PUBLIC);
- }
-
- TypeElement componentElement = componentDescriptor.typeElement();
- addSupertype(generatedComponent, componentElement);
-
- TypeName builderMethodReturnType;
- ComponentCreatorKind creatorKind;
- boolean noArgFactoryMethod;
- if (componentDescriptor.creatorDescriptor().isPresent()) {
- ComponentCreatorDescriptor creatorDescriptor = componentDescriptor.creatorDescriptor().get();
- builderMethodReturnType = ClassName.get(creatorDescriptor.typeElement());
- creatorKind = creatorDescriptor.kind();
- noArgFactoryMethod = creatorDescriptor.factoryParameters().isEmpty();
- } else {
- TypeSpec.Builder builder =
- TypeSpec.classBuilder("Builder")
- .addModifiers(STATIC, FINAL)
- .addMethod(privateConstructor());
- if (componentDescriptor.typeElement().getModifiers().contains(PUBLIC)) {
- builder.addModifiers(PUBLIC);
- }
-
- ClassName builderClassName = generatedTypeName.nestedClass("Builder");
- builderMethodReturnType = builderClassName;
- creatorKind = BUILDER;
- noArgFactoryMethod = true;
- componentRequirements(componentDescriptor)
- .map(requirement -> builderSetterMethod(requirement.typeElement(), builderClassName))
- .forEach(builder::addMethod);
- builder.addMethod(builderBuildMethod(componentDescriptor));
- generatedComponent.addType(builder.build());
- }
-
- generatedComponent.addMethod(staticCreatorMethod(builderMethodReturnType, creatorKind));
-
- if (noArgFactoryMethod
- && !hasBindsInstanceMethods(componentDescriptor)
- && componentRequirements(componentDescriptor)
- .noneMatch(
- requirement ->
- requirement.requiresAPassedInstance(elements, types, metadataUtil))) {
- generatedComponent.addMethod(createMethod(componentDescriptor));
- }
-
- DeclaredType componentType = MoreTypes.asDeclared(componentElement.asType());
- // TODO(ronshapiro): unify with ComponentImplementationBuilder
- Set<MethodSignature> methodSignatures =
- Sets.newHashSetWithExpectedSize(componentDescriptor.componentMethods().size());
- componentDescriptor.componentMethods().stream()
- .filter(
- method -> {
- return methodSignatures.add(
- MethodSignature.forComponentMethod(method, componentType, types));
- })
- .forEach(
- method ->
- generatedComponent.addMethod(
- emptyComponentMethod(componentElement, method.methodElement())));
-
- if (componentDescriptor.isProduction()) {
- generatedComponent
- .addSuperinterface(ClassName.get(CancellationListener.class))
- .addMethod(onProducerFutureCancelledMethod());
- }
-
- return Optional.of(generatedComponent);
- }
-
- private MethodSpec emptyComponentMethod(TypeElement typeElement, ExecutableElement baseMethod) {
- return MethodSpec.overriding(baseMethod, MoreTypes.asDeclared(typeElement.asType()), types)
- .build();
- }
-
- private static MethodSpec privateConstructor() {
- return constructorBuilder().addModifiers(PRIVATE).build();
- }
-
- /**
- * Returns the {@link ComponentRequirement}s for a component that does not have a {@link
- * ComponentDescriptor#creatorDescriptor()}.
- */
- private static Stream<ComponentRequirement> componentRequirements(ComponentDescriptor component) {
- // TODO(b/152802759): See if you can merge logics that normal component processing and hjar
- // component processing use. So that there would't be a duplicated logic (like the lines below)
- // everytime we modify the generated code for the component.
- checkArgument(!component.isSubcomponent());
- return Stream.concat(
- component.dependencies().stream(),
- component.modules().stream()
- .filter(
- module ->
- !module.moduleElement().getModifiers().contains(ABSTRACT)
- && isElementAccessibleFrom(
- module.moduleElement(),
- ClassName.get(component.typeElement()).packageName()))
- .map(module -> ComponentRequirement.forModule(module.moduleElement().asType())));
- }
-
- private boolean hasBindsInstanceMethods(ComponentDescriptor componentDescriptor) {
- return componentDescriptor.creatorDescriptor().isPresent()
- && elements
- .getUnimplementedMethods(componentDescriptor.creatorDescriptor().get().typeElement())
- .stream()
- .anyMatch(method -> isBindsInstance(method));
- }
-
- private static boolean isBindsInstance(ExecutableElement method) {
- if (isAnnotationPresent(method, BindsInstance.class)) {
- return true;
- }
-
- if (method.getParameters().size() == 1) {
- return isAnnotationPresent(method.getParameters().get(0), BindsInstance.class);
- }
-
- return false;
- }
-
- private static MethodSpec builderSetterMethod(
- TypeElement componentRequirement, ClassName builderClass) {
- String simpleName =
- UPPER_CAMEL.to(LOWER_CAMEL, componentRequirement.getSimpleName().toString());
- return MethodSpec.methodBuilder(simpleName)
- .addModifiers(PUBLIC)
- .addParameter(ClassName.get(componentRequirement), simpleName)
- .returns(builderClass)
- .build();
- }
-
- private static MethodSpec builderBuildMethod(ComponentDescriptor component) {
- return MethodSpec.methodBuilder("build")
- .addModifiers(PUBLIC)
- .returns(ClassName.get(component.typeElement()))
- .build();
- }
-
- private static MethodSpec staticCreatorMethod(
- TypeName creatorMethodReturnType, ComponentCreatorKind creatorKind) {
- return MethodSpec.methodBuilder(Ascii.toLowerCase(creatorKind.typeName()))
- .addModifiers(PUBLIC, STATIC)
- .returns(creatorMethodReturnType)
- .build();
- }
-
- private static MethodSpec createMethod(ComponentDescriptor componentDescriptor) {
- return MethodSpec.methodBuilder("create")
- .addModifiers(PUBLIC, STATIC)
- .returns(ClassName.get(componentDescriptor.typeElement()))
- .build();
- }
-
- private static MethodSpec onProducerFutureCancelledMethod() {
- return MethodSpec.methodBuilder("onProducerFutureCancelled")
- .addModifiers(PUBLIC)
- .addParameter(TypeName.BOOLEAN, "mayInterruptIfRunning")
- .build();
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java b/java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java
deleted file mode 100644
index 04cb80f..0000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationBuilder.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.componentgenerator;
-
-import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkState;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.BUILDER_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CANCELLATION_LISTENER_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.COMPONENT_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.CONSTRUCTOR;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.INITIALIZE_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_CREATOR;
-import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.SUBCOMPONENT;
-import static dagger.producers.CancellationPolicy.Propagation.PROPAGATE;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimaps;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.Preconditions;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.ComponentBindingExpressions;
-import dagger.internal.codegen.writing.ComponentCreatorImplementation;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.ComponentRequirementExpressions;
-import dagger.internal.codegen.writing.ParentComponent;
-import dagger.model.Key;
-import dagger.producers.internal.CancellationListener;
-import dagger.producers.internal.Producers;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-
-/** A builder of {@link ComponentImplementation}s. */
-// This only needs to be public because it's referenced in an entry point.
-public final class ComponentImplementationBuilder {
- private static final String MAY_INTERRUPT_IF_RUNNING = "mayInterruptIfRunning";
-
- /**
- * How many statements per {@code initialize()} or {@code onProducerFutureCancelled()} method
- * before they get partitioned.
- */
- private static final int STATEMENTS_PER_METHOD = 100;
-
- private static final String CANCELLATION_LISTENER_METHOD_NAME = "onProducerFutureCancelled";
-
- private final Optional<ComponentImplementationBuilder> parent;
- private final BindingGraph graph;
- private final ComponentBindingExpressions bindingExpressions;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final ComponentImplementation componentImplementation;
- private final ComponentCreatorImplementationFactory componentCreatorImplementationFactory;
- private final TopLevelImplementationComponent topLevelImplementationComponent;
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final KotlinMetadataUtil metadataUtil;
- private boolean done;
-
- @Inject
- ComponentImplementationBuilder(
- @ParentComponent Optional<ComponentImplementationBuilder> parent,
- BindingGraph graph,
- ComponentBindingExpressions bindingExpressions,
- ComponentRequirementExpressions componentRequirementExpressions,
- ComponentImplementation componentImplementation,
- ComponentCreatorImplementationFactory componentCreatorImplementationFactory,
- TopLevelImplementationComponent topLevelImplementationComponent,
- DaggerTypes types,
- DaggerElements elements,
- KotlinMetadataUtil metadataUtil) {
- this.parent = parent;
- this.graph = graph;
- this.bindingExpressions = bindingExpressions;
- this.componentRequirementExpressions = componentRequirementExpressions;
- this.componentImplementation = componentImplementation;
- this.componentCreatorImplementationFactory = componentCreatorImplementationFactory;
- this.types = types;
- this.elements = elements;
- this.topLevelImplementationComponent = topLevelImplementationComponent;
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Returns a {@link ComponentImplementation} for this component. This is only intended to be
- * called once (and will throw on successive invocations). If the component must be regenerated,
- * use a new instance.
- */
- ComponentImplementation build() {
- checkState(
- !done,
- "ComponentImplementationBuilder has already built the ComponentImplementation for [%s].",
- componentImplementation.name());
- setSupertype();
-
- componentCreatorImplementationFactory.create()
- .map(ComponentCreatorImplementation::spec)
- .ifPresent(this::addCreatorClass);
-
- getLocalAndInheritedMethods(graph.componentTypeElement(), types, elements)
- .forEach(method -> componentImplementation.claimMethodName(method.getSimpleName()));
-
- addFactoryMethods();
- addInterfaceMethods();
- addChildComponents();
-
- addConstructorAndInitializationMethods();
-
- if (graph.componentDescriptor().isProduction()) {
- addCancellationListenerImplementation();
- }
-
- done = true;
- return componentImplementation;
- }
-
- /** Set the supertype for this generated class. */
- private void setSupertype() {
- componentImplementation.addSupertype(graph.componentTypeElement());
- }
-
- private void addCreatorClass(TypeSpec creator) {
- if (parent.isPresent()) {
- // In an inner implementation of a subcomponent the creator is a peer class.
- parent.get().componentImplementation.addType(SUBCOMPONENT, creator);
- } else {
- componentImplementation.addType(COMPONENT_CREATOR, creator);
- }
- }
-
- private void addFactoryMethods() {
- if (parent.isPresent()) {
- graph.factoryMethod().ifPresent(this::createSubcomponentFactoryMethod);
- } else {
- createRootComponentFactoryMethod();
- }
- }
-
- private void addInterfaceMethods() {
- // Each component method may have been declared by several supertypes. We want to implement
- // only one method for each distinct signature.
- ImmutableListMultimap<MethodSignature, ComponentMethodDescriptor> componentMethodsBySignature =
- Multimaps.index(graph.componentDescriptor().entryPointMethods(), this::getMethodSignature);
- for (List<ComponentMethodDescriptor> methodsWithSameSignature :
- Multimaps.asMap(componentMethodsBySignature).values()) {
- ComponentMethodDescriptor anyOneMethod = methodsWithSameSignature.stream().findAny().get();
- MethodSpec methodSpec = bindingExpressions.getComponentMethod(anyOneMethod);
-
- componentImplementation.addMethod(COMPONENT_METHOD, methodSpec);
- }
- }
-
- private void addCancellationListenerImplementation() {
- componentImplementation.addSupertype(elements.getTypeElement(CancellationListener.class));
- componentImplementation.claimMethodName(CANCELLATION_LISTENER_METHOD_NAME);
-
- ImmutableList<ParameterSpec> parameters =
- ImmutableList.of(ParameterSpec.builder(boolean.class, MAY_INTERRUPT_IF_RUNNING).build());
-
- MethodSpec.Builder methodBuilder =
- methodBuilder(CANCELLATION_LISTENER_METHOD_NAME)
- .addModifiers(PUBLIC)
- .addAnnotation(Override.class)
- .addParameters(parameters);
-
- ImmutableList<CodeBlock> cancellationStatements = cancellationStatements();
-
- if (cancellationStatements.size() < STATEMENTS_PER_METHOD) {
- methodBuilder.addCode(CodeBlocks.concat(cancellationStatements)).build();
- } else {
- ImmutableList<MethodSpec> cancelProducersMethods =
- createPartitionedMethods(
- "cancelProducers",
- parameters,
- cancellationStatements,
- methodName -> methodBuilder(methodName).addModifiers(PRIVATE));
- for (MethodSpec cancelProducersMethod : cancelProducersMethods) {
- methodBuilder.addStatement("$N($L)", cancelProducersMethod, MAY_INTERRUPT_IF_RUNNING);
- componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, cancelProducersMethod);
- }
- }
-
- cancelParentStatement().ifPresent(methodBuilder::addCode);
-
- componentImplementation.addMethod(CANCELLATION_LISTENER_METHOD, methodBuilder.build());
- }
-
- private ImmutableList<CodeBlock> cancellationStatements() {
- // Reversing should order cancellations starting from entry points and going down to leaves
- // rather than the other way around. This shouldn't really matter but seems *slightly*
- // preferable because:
- // When a future that another future depends on is cancelled, that cancellation will propagate
- // up the future graph toward the entry point. Cancelling in reverse order should ensure that
- // everything that depends on a particular node has already been cancelled when that node is
- // cancelled, so there's no need to propagate. Otherwise, when we cancel a leaf node, it might
- // propagate through most of the graph, making most of the cancel calls that follow in the
- // onProducerFutureCancelled method do nothing.
- ImmutableList<Key> cancellationKeys =
- componentImplementation.getCancellableProducerKeys().reverse();
-
- ImmutableList.Builder<CodeBlock> cancellationStatements = ImmutableList.builder();
- for (Key cancellationKey : cancellationKeys) {
- cancellationStatements.add(
- CodeBlock.of(
- "$T.cancel($L, $N);",
- Producers.class,
- bindingExpressions
- .getDependencyExpression(
- bindingRequest(cancellationKey, FrameworkType.PRODUCER_NODE),
- componentImplementation.name())
- .codeBlock(),
- MAY_INTERRUPT_IF_RUNNING));
- }
- return cancellationStatements.build();
- }
-
- private Optional<CodeBlock> cancelParentStatement() {
- if (!shouldPropagateCancellationToParent()) {
- return Optional.empty();
- }
- return Optional.of(
- CodeBlock.builder()
- .addStatement(
- "$T.this.$N($N)",
- parent.get().componentImplementation.name(),
- CANCELLATION_LISTENER_METHOD_NAME,
- MAY_INTERRUPT_IF_RUNNING)
- .build());
- }
-
- private boolean shouldPropagateCancellationToParent() {
- return parent.isPresent()
- && parent
- .get()
- .componentImplementation
- .componentDescriptor()
- .cancellationPolicy()
- .map(policy -> policy.fromSubcomponents().equals(PROPAGATE))
- .orElse(false);
- }
-
- private MethodSignature getMethodSignature(ComponentMethodDescriptor method) {
- return MethodSignature.forComponentMethod(
- method, MoreTypes.asDeclared(graph.componentTypeElement().asType()), types);
- }
-
- private void addChildComponents() {
- for (BindingGraph subgraph : graph.subgraphs()) {
- componentImplementation.addType(SUBCOMPONENT, childComponent(subgraph));
- }
- }
-
- private TypeSpec childComponent(BindingGraph childGraph) {
- return topLevelImplementationComponent
- .currentImplementationSubcomponentBuilder()
- .componentImplementation(subcomponent(childGraph))
- .bindingGraph(childGraph)
- .parentBuilder(Optional.of(this))
- .parentBindingExpressions(Optional.of(bindingExpressions))
- .parentRequirementExpressions(Optional.of(componentRequirementExpressions))
- .build()
- .componentImplementationBuilder()
- .build()
- .generate()
- .build();
- }
-
- /** Creates an inner subcomponent implementation. */
- private ComponentImplementation subcomponent(BindingGraph childGraph) {
- return componentImplementation.childComponentImplementation(childGraph);
- }
-
- /** Creates and adds the constructor and methods needed for initializing the component. */
- private void addConstructorAndInitializationMethods() {
- MethodSpec.Builder constructor = constructorBuilder().addModifiers(PRIVATE);
- implementInitializationMethod(constructor, initializationParameters());
- componentImplementation.addMethod(CONSTRUCTOR, constructor.build());
- }
-
- /** Adds parameters and code to the given {@code initializationMethod}. */
- private void implementInitializationMethod(
- MethodSpec.Builder initializationMethod,
- ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters) {
- initializationMethod.addParameters(initializationParameters.values());
- initializationMethod.addCode(
- CodeBlocks.concat(componentImplementation.getComponentRequirementInitializations()));
- addInitializeMethods(initializationMethod, initializationParameters.values().asList());
- }
-
- /**
- * Adds any necessary {@code initialize} methods to the component and adds calls to them to the
- * given {@code callingMethod}.
- */
- private void addInitializeMethods(
- MethodSpec.Builder callingMethod, ImmutableList<ParameterSpec> parameters) {
- // TODO(cgdecker): It's not the case that each initialize() method has need for all of the
- // given parameters. In some cases, those parameters may have already been assigned to fields
- // which could be referenced instead. In other cases, an initialize method may just not need
- // some of the parameters because the set of initializations in that partition does not
- // include any reference to them. Right now, the Dagger code has no way of getting that
- // information because, among other things, componentImplementation.getImplementations() just
- // returns a bunch of CodeBlocks with no semantic information. Additionally, we may not know
- // yet whether a field will end up needing to be created for a specific requirement, and we
- // don't want to create a field that ends up only being used during initialization.
- CodeBlock args = parameterNames(parameters);
- ImmutableList<MethodSpec> methods =
- createPartitionedMethods(
- "initialize",
- makeFinal(parameters),
- componentImplementation.getInitializations(),
- methodName ->
- methodBuilder(methodName)
- .addModifiers(PRIVATE)
- /* TODO(gak): Strictly speaking, we only need the suppression here if we are
- * also initializing a raw field in this method, but the structure of this
- * code makes it awkward to pass that bit through. This will be cleaned up
- * when we no longer separate fields and initialization as we do now. */
- .addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED)));
- for (MethodSpec method : methods) {
- callingMethod.addStatement("$N($L)", method, args);
- componentImplementation.addMethod(INITIALIZE_METHOD, method);
- }
- }
-
- /**
- * Creates one or more methods, all taking the given {@code parameters}, which partition the given
- * list of {@code statements} among themselves such that no method has more than {@code
- * STATEMENTS_PER_METHOD} statements in it and such that the returned methods, if called in order,
- * will execute the {@code statements} in the given order.
- */
- private ImmutableList<MethodSpec> createPartitionedMethods(
- String methodName,
- Iterable<ParameterSpec> parameters,
- List<CodeBlock> statements,
- Function<String, MethodSpec.Builder> methodBuilderCreator) {
- return Lists.partition(statements, STATEMENTS_PER_METHOD).stream()
- .map(
- partition ->
- methodBuilderCreator
- .apply(componentImplementation.getUniqueMethodName(methodName))
- .addParameters(parameters)
- .addCode(CodeBlocks.concat(partition))
- .build())
- .collect(toImmutableList());
- }
-
- /** Returns the given parameters with a final modifier added. */
- private final ImmutableList<ParameterSpec> makeFinal(Collection<ParameterSpec> parameters) {
- return parameters.stream()
- .map(param -> param.toBuilder().addModifiers(FINAL).build())
- .collect(toImmutableList());
- }
-
- /**
- * Returns the parameters for the constructor as a map from the requirement the parameter fulfills
- * to the spec for the parameter.
- */
- private final ImmutableMap<ComponentRequirement, ParameterSpec> initializationParameters() {
- Map<ComponentRequirement, ParameterSpec> parameters;
- if (componentImplementation.componentDescriptor().hasCreator()) {
- parameters = Maps.toMap(graph.componentRequirements(), ComponentRequirement::toParameterSpec);
- } else if (graph.factoryMethod().isPresent()) {
- parameters = getFactoryMethodParameters(graph);
- } else {
- throw new AssertionError(
- "Expected either a component creator or factory method but found neither.");
- }
-
- return renameParameters(parameters);
- }
-
- /**
- * Renames the given parameters to guarantee their names do not conflict with fields in the
- * component to ensure that a parameter is never referenced where a reference to a field was
- * intended.
- */
- // TODO(cgdecker): This is a bit kludgy; it would be preferable to either qualify the field
- // references with "this." or "super." when needed to disambiguate between field and parameter,
- // but that would require more context than is currently available when the code referencing a
- // field is generated.
- private ImmutableMap<ComponentRequirement, ParameterSpec> renameParameters(
- Map<ComponentRequirement, ParameterSpec> parameters) {
- return ImmutableMap.copyOf(
- Maps.transformEntries(
- parameters,
- (requirement, parameter) ->
- renameParameter(
- parameter,
- componentImplementation.getParameterName(requirement, parameter.name))));
- }
-
- private ParameterSpec renameParameter(ParameterSpec parameter, String newName) {
- return ParameterSpec.builder(parameter.type, newName)
- .addAnnotations(parameter.annotations)
- .addModifiers(parameter.modifiers)
- .build();
- }
-
- private void createRootComponentFactoryMethod() {
- checkState(!parent.isPresent());
- // Top-level components have a static method that returns a builder or factory for the
- // component. If the user defined a @Component.Builder or @Component.Factory, an
- // implementation of their type is returned. Otherwise, an autogenerated Builder type is
- // returned.
- // TODO(cgdecker): Replace this abomination with a small class?
- // Better yet, change things so that an autogenerated builder type has a descriptor of sorts
- // just like a user-defined creator type.
- ComponentCreatorKind creatorKind;
- ClassName creatorType;
- String factoryMethodName;
- boolean noArgFactoryMethod;
- Optional<ComponentCreatorDescriptor> creatorDescriptor =
- graph.componentDescriptor().creatorDescriptor();
- if (creatorDescriptor.isPresent()) {
- ComponentCreatorDescriptor descriptor = creatorDescriptor.get();
- creatorKind = descriptor.kind();
- creatorType = ClassName.get(descriptor.typeElement());
- factoryMethodName = descriptor.factoryMethod().getSimpleName().toString();
- noArgFactoryMethod = descriptor.factoryParameters().isEmpty();
- } else {
- creatorKind = BUILDER;
- creatorType = componentImplementation.getCreatorName();
- factoryMethodName = "build";
- noArgFactoryMethod = true;
- }
-
- MethodSpec creatorFactoryMethod =
- methodBuilder(creatorKind.methodName())
- .addModifiers(PUBLIC, STATIC)
- .returns(creatorType)
- .addStatement("return new $T()", componentImplementation.getCreatorName())
- .build();
- componentImplementation.addMethod(BUILDER_METHOD, creatorFactoryMethod);
- if (noArgFactoryMethod && canInstantiateAllRequirements()) {
- componentImplementation.addMethod(
- BUILDER_METHOD,
- methodBuilder("create")
- .returns(ClassName.get(graph.componentTypeElement()))
- .addModifiers(PUBLIC, STATIC)
- .addStatement("return new $L().$L()", creatorKind.typeName(), factoryMethodName)
- .build());
- }
- }
-
- /** {@code true} if all of the graph's required dependencies can be automatically constructed */
- private boolean canInstantiateAllRequirements() {
- return !Iterables.any(
- graph.componentRequirements(),
- dependency -> dependency.requiresAPassedInstance(elements, types, metadataUtil));
- }
-
- private void createSubcomponentFactoryMethod(ExecutableElement factoryMethod) {
- checkState(parent.isPresent());
- Collection<ParameterSpec> params = getFactoryMethodParameters(graph).values();
- MethodSpec.Builder method = MethodSpec.overriding(factoryMethod, parentType(), types);
- params.forEach(
- param -> method.addStatement("$T.checkNotNull($N)", Preconditions.class, param));
- method.addStatement(
- "return new $T($L)", componentImplementation.name(), parameterNames(params));
-
- parent.get().componentImplementation.addMethod(COMPONENT_METHOD, method.build());
- }
-
- private DeclaredType parentType() {
- return asDeclared(parent.get().graph.componentTypeElement().asType());
- }
- /**
- * Returns the map of {@link ComponentRequirement}s to {@link ParameterSpec}s for the given
- * graph's factory method.
- */
- private static Map<ComponentRequirement, ParameterSpec> getFactoryMethodParameters(
- BindingGraph graph) {
- return Maps.transformValues(graph.factoryMethodParameters(), ParameterSpec::get);
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java b/java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java
deleted file mode 100644
index fdfcc9d..0000000
--- a/java/dagger/internal/codegen/componentgenerator/ComponentImplementationFactory.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.componentgenerator;
-
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.componentgenerator.ComponentGenerator.componentName;
-
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.SubcomponentNames;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.element.TypeElement;
-
-/** Factory for {@link ComponentImplementation}s. */
-@Singleton
-final class ComponentImplementationFactory implements ClearableCache {
- private final Map<TypeElement, ComponentImplementation> topLevelComponentCache = new HashMap<>();
- private final KeyFactory keyFactory;
- private final CompilerOptions compilerOptions;
- private final TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder;
-
- @Inject
- ComponentImplementationFactory(
- KeyFactory keyFactory,
- CompilerOptions compilerOptions,
- TopLevelImplementationComponent.Builder topLevelImplementationComponentBuilder) {
- this.keyFactory = keyFactory;
- this.compilerOptions = compilerOptions;
- this.topLevelImplementationComponentBuilder = topLevelImplementationComponentBuilder;
- }
-
- /**
- * Returns a top-level (non-nested) component implementation for a binding graph.
- */
- ComponentImplementation createComponentImplementation(BindingGraph bindingGraph) {
- return reentrantComputeIfAbsent(
- topLevelComponentCache,
- bindingGraph.componentTypeElement(),
- component -> createComponentImplementationUncached(bindingGraph));
- }
-
- private ComponentImplementation createComponentImplementationUncached(BindingGraph bindingGraph) {
- ComponentImplementation componentImplementation =
- ComponentImplementation.topLevelComponentImplementation(
- bindingGraph,
- componentName(bindingGraph.componentTypeElement()),
- new SubcomponentNames(bindingGraph, keyFactory),
- compilerOptions);
-
- // TODO(dpb): explore using optional bindings for the "parent" bindings
- return topLevelImplementationComponentBuilder
- .topLevelComponent(componentImplementation)
- .build()
- .currentImplementationSubcomponentBuilder()
- .componentImplementation(componentImplementation)
- .bindingGraph(bindingGraph)
- .parentBuilder(Optional.empty())
- .parentBindingExpressions(Optional.empty())
- .parentRequirementExpressions(Optional.empty())
- .build()
- .componentImplementationBuilder()
- .build();
- }
-
- @Override
- public void clearCache() {
- topLevelComponentCache.clear();
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java b/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java
deleted file mode 100644
index 5584372..0000000
--- a/java/dagger/internal/codegen/componentgenerator/CurrentImplementationSubcomponent.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 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.componentgenerator;
-
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.writing.ComponentBindingExpressions;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.ComponentRequirementExpressions;
-import dagger.internal.codegen.writing.ParentComponent;
-import dagger.internal.codegen.writing.PerComponentImplementation;
-import java.util.Optional;
-
-/**
- * A subcomponent that injects all objects that are responsible for creating a single {@link
- * ComponentImplementation} instance. Each child {@link ComponentImplementation} will have its own
- * instance of {@link CurrentImplementationSubcomponent}.
- */
-@Subcomponent
-@PerComponentImplementation
-// This only needs to be public because the type is referenced by generated component.
-public interface CurrentImplementationSubcomponent {
- ComponentImplementationBuilder componentImplementationBuilder();
-
- /** Returns the builder for {@link CurrentImplementationSubcomponent}. */
- @Subcomponent.Builder
- interface Builder {
- @BindsInstance
- Builder componentImplementation(ComponentImplementation componentImplementation);
-
- @BindsInstance
- Builder bindingGraph(BindingGraph bindingGraph);
-
- @BindsInstance
- Builder parentBuilder(@ParentComponent Optional<ComponentImplementationBuilder> parentBuilder);
-
- @BindsInstance
- Builder parentBindingExpressions(
- @ParentComponent Optional<ComponentBindingExpressions> parentBindingExpressions);
-
- @BindsInstance
- Builder parentRequirementExpressions(
- @ParentComponent Optional<ComponentRequirementExpressions> parentRequirementExpressions);
-
- CurrentImplementationSubcomponent build();
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/MethodSignature.java b/java/dagger/internal/codegen/componentgenerator/MethodSignature.java
deleted file mode 100644
index 99b05a4..0000000
--- a/java/dagger/internal/codegen/componentgenerator/MethodSignature.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 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.componentgenerator;
-
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Equivalence;
-import com.google.common.collect.ImmutableList;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.List;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-
-/** A class that defines proper {@code equals} and {@code hashcode} for a method signature. */
-@AutoValue
-abstract class MethodSignature {
-
- abstract String name();
-
- abstract ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>> parameterTypes();
-
- abstract ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>> thrownTypes();
-
- static MethodSignature forComponentMethod(
- ComponentMethodDescriptor componentMethod, DeclaredType componentType, DaggerTypes types) {
- ExecutableType methodType =
- MoreTypes.asExecutable(types.asMemberOf(componentType, componentMethod.methodElement()));
- return new AutoValue_MethodSignature(
- componentMethod.methodElement().getSimpleName().toString(),
- wrapInEquivalence(methodType.getParameterTypes()),
- wrapInEquivalence(methodType.getThrownTypes()));
- }
-
- private static ImmutableList<? extends Equivalence.Wrapper<? extends TypeMirror>>
- wrapInEquivalence(List<? extends TypeMirror> types) {
- return types.stream().map(MoreTypes.equivalence()::wrap).collect(toImmutableList());
- }
-}
diff --git a/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java b/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java
deleted file mode 100644
index 7919e47..0000000
--- a/java/dagger/internal/codegen/componentgenerator/TopLevelImplementationComponent.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 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.componentgenerator;
-
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-import dagger.internal.codegen.writing.ComponentImplementation;
-import dagger.internal.codegen.writing.PerGeneratedFile;
-import dagger.internal.codegen.writing.TopLevel;
-
-/**
- * A shared subcomponent for a top-level {@link ComponentImplementation} and any nested child
- * implementations.
- */
-@PerGeneratedFile
-@Subcomponent
-// This only needs to be public because the type is referenced by generated component.
-public interface TopLevelImplementationComponent {
- CurrentImplementationSubcomponent.Builder currentImplementationSubcomponentBuilder();
-
- /** Returns the builder for {@link TopLevelImplementationComponent}. */
- @Subcomponent.Builder
- interface Builder {
- @BindsInstance
- Builder topLevelComponent(@TopLevel ComponentImplementation topLevelImplementation);
- TopLevelImplementationComponent build();
- }
-}
diff --git a/java/dagger/internal/codegen/dagger_statistics.proto b/java/dagger/internal/codegen/dagger_statistics.proto
new file mode 100644
index 0000000..273e472
--- /dev/null
+++ b/java/dagger/internal/codegen/dagger_statistics.proto
@@ -0,0 +1,25 @@
+syntax = "proto2";
+
+package dagger.internal.codegen.proto;
+option java_package = "dagger.internal.codegen.proto";
+
+import "google/protobuf/duration.proto";
+
+message DaggerBuildStatistics {
+ optional google.protobuf.Duration total_processing_time = 1;
+ repeated DaggerRound rounds = 2;
+}
+
+// Duration of each Dagger ProcessingStep for a single annotation processing
+// round.
+message DaggerRound {
+ optional google.protobuf.Duration map_key_step_time = 1;
+ optional google.protobuf.Duration inject_step_time = 2;
+ optional google.protobuf.Duration monitoring_module_step_time = 3;
+ optional google.protobuf.Duration multibinding_annotations_step_time = 4;
+ optional google.protobuf.Duration binds_instance_step_time = 5;
+ optional google.protobuf.Duration module_step_time = 6;
+ optional google.protobuf.Duration component_step_time = 7;
+ optional google.protobuf.Duration component_hjar_step_time = 8;
+ optional google.protobuf.Duration binding_method_step_time = 9;
+}
diff --git a/java/dagger/internal/codegen/extension/BUILD b/java/dagger/internal/codegen/extension/BUILD
deleted file mode 100644
index 468a685..0000000
--- a/java/dagger/internal/codegen/extension/BUILD
+++ /dev/null
@@ -1,33 +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.
-
-# Description:
-# Extra features for the JDK and Guava. This code is merged into both
-# the dagger-compiler and dagger-spi artifacts that are sent to Maven
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "extension",
- srcs = glob(["*.java"]),
- tags = ["maven:merged"],
- deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- ],
-)
diff --git a/java/dagger/internal/codegen/extension/DaggerCollectors.java b/java/dagger/internal/codegen/extension/DaggerCollectors.java
deleted file mode 100644
index 7b01676..0000000
--- a/java/dagger/internal/codegen/extension/DaggerCollectors.java
+++ /dev/null
@@ -1,155 +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.internal.codegen.extension;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Optional;
-import java.util.stream.Collector;
-import javax.annotation.Nullable;
-
-/**
- * A copy of {@link com.google.common.collect.MoreCollectors} to avoid issues with the '-android'
- * variant of Guava. See b/68008628
- */
-public final class DaggerCollectors {
-
- private static final Collector<Object, ?, Optional<Object>> TO_OPTIONAL =
- Collector.of(
- ToOptionalState::new,
- ToOptionalState::add,
- ToOptionalState::combine,
- ToOptionalState::getOptional,
- Collector.Characteristics.UNORDERED);
-
- /**
- * A collector that converts a stream of zero or one elements to an {@code Optional}. The returned
- * collector throws an {@code IllegalArgumentException} if the stream consists of two or more
- * elements, and a {@code NullPointerException} if the stream consists of exactly one element,
- * which is null.
- */
- @SuppressWarnings("unchecked")
- public static <T> Collector<T, ?, Optional<T>> toOptional() {
- return (Collector) TO_OPTIONAL;
- }
-
- private static final Object NULL_PLACEHOLDER = new Object();
-
- private static final Collector<Object, ?, Object> ONLY_ELEMENT =
- Collector.of(
- ToOptionalState::new,
- (state, o) -> state.add((o == null) ? NULL_PLACEHOLDER : o),
- ToOptionalState::combine,
- state -> {
- Object result = state.getElement();
- return (result == NULL_PLACEHOLDER) ? null : result;
- },
- Collector.Characteristics.UNORDERED);
-
- /**
- * A collector that takes a stream containing exactly one element and returns that element. The
- * returned collector throws an {@code IllegalArgumentException} if the stream consists of two or
- * more elements, and a {@code NoSuchElementException} if the stream is empty.
- */
- @SuppressWarnings("unchecked")
- public static <T> Collector<T, ?, T> onlyElement() {
- return (Collector) ONLY_ELEMENT;
- }
-
- private static final class ToOptionalState {
- static final int MAX_EXTRAS = 4;
-
- @Nullable Object element;
- @Nullable List<Object> extras;
-
- ToOptionalState() {
- element = null;
- extras = null;
- }
-
- IllegalArgumentException multiples(boolean overflow) {
- StringBuilder sb =
- new StringBuilder().append("expected one element but was: <").append(element);
- for (Object o : extras) {
- sb.append(", ").append(o);
- }
- if (overflow) {
- sb.append(", ...");
- }
- sb.append('>');
- throw new IllegalArgumentException(sb.toString());
- }
-
- void add(Object o) {
- checkNotNull(o);
- if (element == null) {
- this.element = o;
- } else if (extras == null) {
- extras = new ArrayList<>(MAX_EXTRAS);
- extras.add(o);
- } else if (extras.size() < MAX_EXTRAS) {
- extras.add(o);
- } else {
- throw multiples(true);
- }
- }
-
- ToOptionalState combine(ToOptionalState other) {
- if (element == null) {
- return other;
- } else if (other.element == null) {
- return this;
- } else {
- if (extras == null) {
- extras = new ArrayList<>();
- }
- extras.add(other.element);
- if (other.extras != null) {
- this.extras.addAll(other.extras);
- }
- if (extras.size() > MAX_EXTRAS) {
- extras.subList(MAX_EXTRAS, extras.size()).clear();
- throw multiples(true);
- }
- return this;
- }
- }
-
- Optional<Object> getOptional() {
- if (extras == null) {
- return Optional.ofNullable(element);
- } else {
- throw multiples(false);
- }
- }
-
- Object getElement() {
- if (element == null) {
- throw new NoSuchElementException();
- } else if (extras == null) {
- return element;
- } else {
- throw multiples(false);
- }
- }
- }
-
- private DaggerCollectors() {}
-}
diff --git a/java/dagger/internal/codegen/extension/DaggerGraphs.java b/java/dagger/internal/codegen/extension/DaggerGraphs.java
deleted file mode 100644
index 587445b..0000000
--- a/java/dagger/internal/codegen/extension/DaggerGraphs.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2018 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.extension;
-
-import static com.google.common.collect.Sets.difference;
-import static com.google.common.graph.Graphs.reachableNodes;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.graph.Graph;
-import com.google.common.graph.SuccessorsFunction;
-import java.util.ArrayDeque;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Queue;
-import java.util.Set;
-
-/** Utility methods for {@link com.google.common.graph} types. */
-public final class DaggerGraphs {
- /**
- * Returns a shortest path from {@code nodeU} to {@code nodeV} in {@code graph} as a list of the
- * nodes visited in sequence, including both {@code nodeU} and {@code nodeV}. (Note that there may
- * be many possible shortest paths.)
- *
- * <p>If {@code nodeV} is not {@link
- * com.google.common.graph.Graphs#reachableNodes(com.google.common.graph.Graph, Object) reachable}
- * from {@code nodeU}, the list returned is empty.
- *
- * @throws IllegalArgumentException if {@code nodeU} or {@code nodeV} is not present in {@code
- * graph}
- */
- public static <N> ImmutableList<N> shortestPath(SuccessorsFunction<N> graph, N nodeU, N nodeV) {
- if (nodeU.equals(nodeV)) {
- return ImmutableList.of(nodeU);
- }
- Set<N> successors = ImmutableSet.copyOf(graph.successors(nodeU));
- if (successors.contains(nodeV)) {
- return ImmutableList.of(nodeU, nodeV);
- }
-
- Map<N, N> visitedNodeToPathPredecessor = new HashMap<>(); // encodes shortest path tree
- for (N node : successors) {
- visitedNodeToPathPredecessor.put(node, nodeU);
- }
- Queue<N> currentNodes = new ArrayDeque<N>(successors);
- Queue<N> nextNodes = new ArrayDeque<N>();
-
- // Perform a breadth-first traversal starting with the successors of nodeU.
- while (!currentNodes.isEmpty()) {
- while (!currentNodes.isEmpty()) {
- N currentNode = currentNodes.remove();
- for (N nextNode : graph.successors(currentNode)) {
- if (visitedNodeToPathPredecessor.containsKey(nextNode)) {
- continue; // we already have a shortest path to nextNode
- }
- visitedNodeToPathPredecessor.put(nextNode, currentNode);
- if (nextNode.equals(nodeV)) {
- ImmutableList.Builder<N> builder = ImmutableList.builder();
- N node = nodeV;
- builder.add(node);
- while (!node.equals(nodeU)) {
- node = visitedNodeToPathPredecessor.get(node);
- builder.add(node);
- }
- return builder.build().reverse();
- }
- nextNodes.add(nextNode);
- }
- }
- Queue<N> emptyQueue = currentNodes;
- currentNodes = nextNodes;
- nextNodes = emptyQueue; // reusing empty queue faster than allocating new one
- }
-
- return ImmutableList.of();
- }
-
- /** Returns the nodes in a graph that are not reachable from a node. */
- public static <N> ImmutableSet<N> unreachableNodes(Graph<N> graph, N node) {
- return ImmutableSet.copyOf(difference(graph.nodes(), reachableNodes(graph, node)));
- }
-
- private DaggerGraphs() {}
-}
diff --git a/java/dagger/internal/codegen/extension/DaggerStreams.java b/java/dagger/internal/codegen/extension/DaggerStreams.java
deleted file mode 100644
index 136280d..0000000
--- a/java/dagger/internal/codegen/extension/DaggerStreams.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2013 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.extension;
-
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toList;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Maps;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Collector;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-/** Utilities for streams. */
-public final class DaggerStreams {
-
- /**
- * Returns a {@link Collector} that accumulates the input elements into a new {@link
- * ImmutableList}, in encounter order.
- */
- // TODO(b/68008628): Use ImmutableList.toImmutableList().
- public static <T> Collector<T, ?, ImmutableList<T>> toImmutableList() {
- return collectingAndThen(toList(), ImmutableList::copyOf);
- }
-
- /**
- * Returns a {@link Collector} that accumulates the input elements into a new {@link
- * ImmutableSet}, in encounter order.
- */
- // TODO(b/68008628): Use ImmutableSet.toImmutableSet().
- public static <T> Collector<T, ?, ImmutableSet<T>> toImmutableSet() {
- return collectingAndThen(toList(), ImmutableSet::copyOf);
- }
-
- /**
- * Returns a {@link Collector} that accumulates elements into an {@code ImmutableMap} whose keys
- * and values are the result of applying the provided mapping functions to the input elements.
- * Entries appear in the result {@code ImmutableMap} in encounter order.
- */
- // TODO(b/68008628): Use ImmutableMap.toImmutableMap().
- public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap(
- Function<? super T, K> keyMapper, Function<? super T, V> valueMapper) {
- return Collectors.mapping(
- value -> Maps.immutableEntry(keyMapper.apply(value), valueMapper.apply(value)),
- Collector.of(
- ImmutableMap::builder,
- (ImmutableMap.Builder<K, V> builder, Map.Entry<K, V> entry) -> builder.put(entry),
- (left, right) -> left.putAll(right.build()),
- ImmutableMap.Builder::build));
- }
-
- /**
- * Returns a {@link Collector} that accumulates elements into an {@code ImmutableSetMultimap}
- * whose keys and values are the result of applying the provided mapping functions to the input
- * elements. Entries appear in the result {@code ImmutableSetMultimap} in encounter order.
- */
- // TODO(b/68008628): Use ImmutableSetMultimap.toImmutableSetMultimap().
- public static <T, K, V> Collector<T, ?, ImmutableSetMultimap<K, V>> toImmutableSetMultimap(
- Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends V> valueMapper) {
- return Collectors.mapping(
- value -> Maps.immutableEntry(keyMapper.apply(value), valueMapper.apply(value)),
- Collector.of(
- ImmutableSetMultimap::builder,
- (ImmutableSetMultimap.Builder<K, V> builder, Map.Entry<K, V> entry) ->
- builder.put(entry),
- (left, right) -> left.putAll(right.build()),
- ImmutableSetMultimap.Builder::build));
- }
-
- /**
- * Returns a function from {@link Object} to {@code Stream<T>}, which returns a stream containing
- * its input if its input is an instance of {@code T}.
- *
- * <p>Use as an argument to {@link Stream#flatMap(Function)}:
- *
- * <pre>{@code Stream<Bar>} barStream = fooStream.flatMap(instancesOf(Bar.class));</pre>
- */
- public static <T> Function<Object, Stream<T>> instancesOf(Class<T> to) {
- return f -> to.isInstance(f) ? Stream.of(to.cast(f)) : Stream.empty();
- }
-
- /** Returns a stream of all values of the given {@code enumType}. */
- public static <E extends Enum<E>> Stream<E> valuesOf(Class<E> enumType) {
- return EnumSet.allOf(enumType).stream();
- }
-
- /**
- * A function that you can use to extract the present values from a stream of {@link Optional}s.
- *
- * <pre>{@code
- * Set<Foo> foos =
- * optionalFoos()
- * .flatMap(DaggerStreams.presentValues())
- * .collect(toSet());
- * }</pre>
- */
- public static <T> Function<Optional<T>, Stream<T>> presentValues() {
- return optional -> optional.map(Stream::of).orElse(Stream.empty());
- }
-
- /**
- * Returns a sequential {@link Stream} of the contents of {@code iterable}, delegating to {@link
- * Collection#stream} if possible.
- */
- public static <T> Stream<T> stream(Iterable<T> iterable) {
- return (iterable instanceof Collection)
- ? ((Collection<T>) iterable).stream()
- : StreamSupport.stream(iterable.spliterator(), false);
- }
-
- private DaggerStreams() {}
-}
diff --git a/java/dagger/internal/codegen/extension/Optionals.java b/java/dagger/internal/codegen/extension/Optionals.java
deleted file mode 100644
index 57494a2..0000000
--- a/java/dagger/internal/codegen/extension/Optionals.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 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.extension;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Lists.asList;
-
-import java.util.Comparator;
-import java.util.Optional;
-import java.util.function.Function;
-
-/** Utilities for {@link Optional}s. */
-public final class Optionals {
- /**
- * A {@link Comparator} that puts empty {@link Optional}s before present ones, and compares
- * present {@link Optional}s by their values.
- */
- public static <C extends Comparable<C>> Comparator<Optional<C>> optionalComparator() {
- return Comparator.comparing((Optional<C> optional) -> optional.isPresent())
- .thenComparing(Optional::get);
- }
-
- public static <T> Comparator<Optional<T>> emptiesLast(Comparator<? super T> valueComparator) {
- checkNotNull(valueComparator);
- return Comparator.comparing(o -> o.orElse(null), Comparator.nullsLast(valueComparator));
- }
-
- /** Returns the first argument that is present, or empty if none are. */
- @SafeVarargs
- public static <T> Optional<T> firstPresent(
- Optional<T> first, Optional<T> second, Optional<T>... rest) {
- return asList(first, second, rest).stream()
- .filter(Optional::isPresent)
- .findFirst()
- .orElse(Optional.empty());
- }
-
- /**
- * Walks a chain of present optionals as defined by successive calls to {@code nextFunction},
- * returning the value of the final optional that is present. The first optional in the chain is
- * the result of {@code nextFunction(start)}.
- */
- public static <T> T rootmostValue(T start, Function<T, Optional<T>> nextFunction) {
- T current = start;
- for (Optional<T> next = nextFunction.apply(start);
- next.isPresent();
- next = nextFunction.apply(current)) {
- current = next.get();
- }
- return current;
- }
-
- private Optionals() {}
-}
diff --git a/java/dagger/internal/codegen/javac/BUILD b/java/dagger/internal/codegen/javac/BUILD
deleted file mode 100644
index b8cb37c..0000000
--- a/java/dagger/internal/codegen/javac/BUILD
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2017 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A library for javac the javac plugin module.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "javac",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen:component-codegen"],
- exports = [
- ":javac-import",
- ],
- deps = [
- ":javac-import",
- "//java/dagger:core",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/langmodel",
- ],
-)
-
-load("@rules_java//java:defs.bzl", "java_import")
-
-# Replacement for @bazel_tools//third_party/java/jdk/langtools:javac, which seems to have gone away?
-java_import(
- name = "javac-import",
- jars = ["@bazel_tools//third_party/java/jdk/langtools:javac_jar"],
-)
diff --git a/java/dagger/internal/codegen/javac/JavacPluginModule.java b/java/dagger/internal/codegen/javac/JavacPluginModule.java
deleted file mode 100644
index 214191a..0000000
--- a/java/dagger/internal/codegen/javac/JavacPluginModule.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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.javac;
-
-import com.sun.tools.javac.model.JavacElements;
-import com.sun.tools.javac.model.JavacTypes;
-import com.sun.tools.javac.util.Context;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.binding.BindingGraphFactory;
-import dagger.internal.codegen.binding.ComponentDescriptorFactory;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.compileroption.JavacPluginCompilerOptions;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic;
-
-/**
- * A module that provides a {@link BindingGraphFactory} and {@link ComponentDescriptorFactory} for
- * use in {@code javac} plugins. Requires a binding for the {@code javac} {@link Context}.
- */
-@Module
-public abstract class JavacPluginModule {
- @Binds
- abstract CompilerOptions compilerOptions(JavacPluginCompilerOptions compilerOptions);
-
- @Binds
- abstract Messager messager(NullMessager nullMessager);
-
- static final class NullMessager implements Messager {
-
- @Inject
- NullMessager() {}
-
- @Override
- public void printMessage(Diagnostic.Kind kind, CharSequence charSequence) {}
-
- @Override
- public void printMessage(Diagnostic.Kind kind, CharSequence charSequence, Element element) {}
-
- @Override
- public void printMessage(
- Diagnostic.Kind kind,
- CharSequence charSequence,
- Element element,
- AnnotationMirror annotationMirror) {}
-
- @Override
- public void printMessage(
- Diagnostic.Kind kind,
- CharSequence charSequence,
- Element element,
- AnnotationMirror annotationMirror,
- AnnotationValue annotationValue) {}
- }
-
- @Provides
- static DaggerElements daggerElements(Context javaContext) {
- return new DaggerElements(
- JavacElements.instance(javaContext), JavacTypes.instance(javaContext));
- }
-
- @Provides
- static DaggerTypes daggerTypes(Context javaContext, DaggerElements elements) {
- return new DaggerTypes(JavacTypes.instance(javaContext), elements);
- }
-
- @Binds abstract Types types(DaggerTypes daggerTypes);
-
- private JavacPluginModule() {}
-}
diff --git a/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java b/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
index b66d266..cc0d7de 100644
--- a/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
+++ b/java/dagger/internal/codegen/javapoet/AnnotationSpecs.java
@@ -16,38 +16,34 @@
package dagger.internal.codegen.javapoet;
-import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Ascii;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.squareup.javapoet.AnnotationSpec;
+import java.util.Arrays;
/** Static factories to create {@link AnnotationSpec}s. */
public final class AnnotationSpecs {
/** Values for an {@link SuppressWarnings} annotation. */
public enum Suppression {
- RAWTYPES("rawtypes"),
- UNCHECKED("unchecked"),
- FUTURE_RETURN_VALUE_IGNORED("FutureReturnValueIgnored"),
+ RAWTYPES,
+ UNCHECKED,
;
- private final String value;
-
- Suppression(String value) {
- this.value = value;
+ @Override
+ public String toString() {
+ return Ascii.toLowerCase(name());
}
}
/** Creates an {@link AnnotationSpec} for {@link SuppressWarnings}. */
public static AnnotationSpec suppressWarnings(Suppression first, Suppression... rest) {
- return suppressWarnings(ImmutableSet.copyOf(Lists.asList(first, rest)));
- }
-
- /** Creates an {@link AnnotationSpec} for {@link SuppressWarnings}. */
- public static AnnotationSpec suppressWarnings(ImmutableSet<Suppression> suppressions) {
- checkArgument(!suppressions.isEmpty());
+ checkNotNull(first);
+ Arrays.stream(rest).forEach(Preconditions::checkNotNull);
AnnotationSpec.Builder builder = AnnotationSpec.builder(SuppressWarnings.class);
- suppressions.forEach(suppression -> builder.addMember("value", "$S", suppression.value));
+ Lists.asList(first, rest).forEach(suppression -> builder.addMember("value", "$S", suppression));
return builder.build();
}
diff --git a/java/dagger/internal/codegen/javapoet/BUILD b/java/dagger/internal/codegen/javapoet/BUILD
index ddb9f88..f829d49 100644
--- a/java/dagger/internal/codegen/javapoet/BUILD
+++ b/java/dagger/internal/codegen/javapoet/BUILD
@@ -15,22 +15,20 @@
# Description:
# JavaPoet extensions for use in Dagger
-load("@rules_java//java:defs.bzl", "java_library")
-
package(default_visibility = ["//:src"])
java_library(
name = "javapoet",
srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
+ plugins = ["//java/dagger/internal/codegen:bootstrap_compiler_plugin"],
tags = ["maven:merged"],
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:collect",
"//java/dagger/producers",
+ "@google_bazel_common//third_party/java/auto:common",
"@google_bazel_common//third_party/java/error_prone:annotations",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
],
)
diff --git a/java/dagger/internal/codegen/javapoet/TypeNames.java b/java/dagger/internal/codegen/javapoet/TypeNames.java
index 71f03f0..9301dbc 100644
--- a/java/dagger/internal/codegen/javapoet/TypeNames.java
+++ b/java/dagger/internal/codegen/javapoet/TypeNames.java
@@ -25,7 +25,6 @@
import dagger.MembersInjector;
import dagger.internal.DoubleCheck;
import dagger.internal.Factory;
-import dagger.internal.InjectedFieldSignature;
import dagger.internal.InstanceFactory;
import dagger.internal.MapFactory;
import dagger.internal.MapProviderFactory;
@@ -35,7 +34,6 @@
import dagger.internal.SingleCheck;
import dagger.producers.Produced;
import dagger.producers.Producer;
-import dagger.producers.ProducerModule;
import dagger.producers.internal.AbstractProducer;
import dagger.producers.internal.DependencyMethodProducer;
import dagger.producers.internal.MapOfProducedProducer;
@@ -59,8 +57,6 @@
public static final ClassName DOUBLE_CHECK = ClassName.get(DoubleCheck.class);
public static final ClassName FACTORY = ClassName.get(Factory.class);
public static final ClassName FUTURES = ClassName.get(Futures.class);
- public static final ClassName INJECTED_FIELD_SIGNATURE =
- ClassName.get(InjectedFieldSignature.class);
public static final ClassName INSTANCE_FACTORY = ClassName.get(InstanceFactory.class);
public static final ClassName LAZY = ClassName.get(Lazy.class);
public static final ClassName LIST = ClassName.get(List.class);
@@ -78,7 +74,6 @@
public static final ClassName PRODUCED = ClassName.get(Produced.class);
public static final ClassName PRODUCER = ClassName.get(Producer.class);
public static final ClassName PRODUCERS = ClassName.get(Producers.class);
- public static final ClassName PRODUCER_MODULE = ClassName.get(ProducerModule.class);
public static final ClassName PRODUCTION_COMPONENT_MONITOR_FACTORY =
ClassName.get(ProductionComponentMonitor.Factory.class);
public static final ClassName PROVIDER = ClassName.get(Provider.class);
diff --git a/java/dagger/internal/codegen/kotlin/BUILD b/java/dagger/internal/codegen/kotlin/BUILD
deleted file mode 100644
index d1c5458..0000000
--- a/java/dagger/internal/codegen/kotlin/BUILD
+++ /dev/null
@@ -1,41 +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.
-
-# Description:
-# Sources related to Kotlin metadata.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "kotlin",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base:shared",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr305_annotations",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
- "@maven//:org_jetbrains_kotlinx_kotlinx_metadata_jvm",
- ],
-)
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java b/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
deleted file mode 100644
index 296da44..0000000
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadata.java
+++ /dev/null
@@ -1,472 +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.internal.codegen.kotlin;
-
-import static dagger.internal.codegen.base.MoreAnnotationValues.getIntArrayValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getIntValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getOptionalIntValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getOptionalStringValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getStringArrayValue;
-import static dagger.internal.codegen.base.MoreAnnotationValues.getStringValue;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static dagger.internal.codegen.langmodel.DaggerElements.getFieldDescriptor;
-import static dagger.internal.codegen.langmodel.DaggerElements.getMethodDescriptor;
-import static kotlinx.metadata.Flag.ValueParameter.DECLARES_DEFAULT_VALUE;
-
-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.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.extension.DaggerCollectors;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.HashMap;
-import java.util.Map;
-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.KmClassVisitor;
-import kotlinx.metadata.KmConstructorExtensionVisitor;
-import kotlinx.metadata.KmConstructorVisitor;
-import kotlinx.metadata.KmExtensionType;
-import kotlinx.metadata.KmFunctionExtensionVisitor;
-import kotlinx.metadata.KmFunctionVisitor;
-import kotlinx.metadata.KmPropertyExtensionVisitor;
-import kotlinx.metadata.KmPropertyVisitor;
-import kotlinx.metadata.KmValueParameterVisitor;
-import kotlinx.metadata.jvm.JvmConstructorExtensionVisitor;
-import kotlinx.metadata.jvm.JvmFieldSignature;
-import kotlinx.metadata.jvm.JvmFunctionExtensionVisitor;
-import kotlinx.metadata.jvm.JvmMethodSignature;
-import kotlinx.metadata.jvm.JvmPropertyExtensionVisitor;
-import kotlinx.metadata.jvm.KotlinClassHeader;
-import kotlinx.metadata.jvm.KotlinClassMetadata;
-
-/** Data class of a TypeElement and its Kotlin metadata. */
-@AutoValue
-abstract class KotlinMetadata {
- // Kotlin suffix for fields that are for a delegated property.
- // See:
- // https://github.com/JetBrains/kotlin/blob/master/core/compiler.common.jvm/src/org/jetbrains/kotlin/load/java/JvmAbi.kt#L32
- 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 =
- new HashMap<>();
-
- abstract TypeElement typeElement();
-
- abstract ClassMetadata classMetadata();
-
- @Memoized
- ImmutableMap<String, ExecutableElement> methodDescriptors() {
- return ElementFilter.methodsIn(typeElement().getEnclosedElements()).stream()
- .collect(toImmutableMap(DaggerElements::getMethodDescriptor, Function.identity()));
- }
-
- /** Returns true if any constructor of the defined a default parameter. */
- @Memoized
- boolean containsConstructorWithDefaultParam() {
- return classMetadata().constructors().stream()
- .flatMap(constructor -> constructor.parameters().stream())
- .anyMatch(parameter -> parameter.flags(DECLARES_DEFAULT_VALUE));
- }
-
- /** Gets the synthetic method for annotations of a given field element. */
- Optional<ExecutableElement> getSyntheticAnnotationMethod(VariableElement fieldElement) {
- return getAnnotationMethod(fieldElement)
- .map(
- methodForAnnotations -> {
- if (methodForAnnotations == MethodForAnnotations.MISSING) {
- throw new IllegalStateException(
- "Method for annotations is missing for " + fieldElement);
- }
- return 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) {
- return elementFieldAnnotationMethodMap.computeIfAbsent(
- fieldElement, this::getAnnotationMethodUncached);
- }
-
- private Optional<MethodForAnnotations> getAnnotationMethodUncached(VariableElement fieldElement) {
- return findProperty(fieldElement)
- .methodForAnnotationsSignature()
- .map(
- signature ->
- Optional.ofNullable(methodDescriptors().get(signature))
- .map(MethodForAnnotations::create)
- // The method may be missing across different compilations.
- // See https://youtrack.jetbrains.com/issue/KT-34684
- .orElse(MethodForAnnotations.MISSING));
- }
-
- /** Gets the getter method of a given field element corresponding to a property. */
- Optional<ExecutableElement> getPropertyGetter(VariableElement fieldElement) {
- return elementFieldGetterMethodMap.computeIfAbsent(
- fieldElement, this::getPropertyGetterUncached);
- }
-
- private Optional<ExecutableElement> getPropertyGetterUncached(VariableElement fieldElement) {
- return findProperty(fieldElement)
- .getterSignature()
- .flatMap(signature -> Optional.ofNullable(methodDescriptors().get(signature)));
- }
-
- private PropertyMetadata findProperty(VariableElement field) {
- String fieldDescriptor = getFieldDescriptor(field);
- if (classMetadata().propertiesByFieldSignature().containsKey(fieldDescriptor)) {
- return classMetadata().propertiesByFieldSignature().get(fieldDescriptor);
- } else {
- // Fallback to finding property by name, see: https://youtrack.jetbrains.com/issue/KT-35124
- final String propertyName = getPropertyNameFromField(field);
- return classMetadata().propertiesByFieldSignature().values().stream()
- .filter(property -> propertyName.contentEquals(property.name()))
- .collect(DaggerCollectors.onlyElement());
- }
- }
-
- private static String getPropertyNameFromField(VariableElement field) {
- String name = field.getSimpleName().toString();
- if (name.endsWith(DELEGATED_PROPERTY_NAME_SUFFIX)) {
- return name.substring(0, name.length() - DELEGATED_PROPERTY_NAME_SUFFIX.length());
- } else {
- return name;
- }
- }
-
- FunctionMetadata getFunctionMetadata(ExecutableElement method) {
- return classMetadata().functionsBySignature().get(getMethodDescriptor(method));
- }
-
- /** Parse Kotlin class metadata from a given type element * */
- static KotlinMetadata from(TypeElement typeElement) {
- return new AutoValue_KotlinMetadata(
- typeElement, ClassVisitor.createClassMetadata(metadataOf(typeElement)));
- }
-
- private static KotlinClassMetadata.Class metadataOf(TypeElement typeElement) {
- Optional<AnnotationMirror> metadataAnnotation =
- getAnnotationMirror(typeElement, Metadata.class);
- Preconditions.checkState(metadataAnnotation.isPresent());
- KotlinClassHeader header =
- new KotlinClassHeader(
- getIntValue(metadataAnnotation.get(), "k"),
- getIntArrayValue(metadataAnnotation.get(), "mv"),
- getIntArrayValue(metadataAnnotation.get(), "bv"),
- getStringArrayValue(metadataAnnotation.get(), "d1"),
- getStringArrayValue(metadataAnnotation.get(), "d2"),
- getStringValue(metadataAnnotation.get(), "xs"),
- getOptionalStringValue(metadataAnnotation.get(), "pn").orElse(null),
- getOptionalIntValue(metadataAnnotation.get(), "xi").orElse(null));
- KotlinClassMetadata metadata = KotlinClassMetadata.read(header);
- if (metadata == null) {
- // Should only happen on Kotlin < 1.0 (i.e. metadata version < 1.1)
- throw new IllegalStateException(
- "Unsupported metadata version. Check that your Kotlin version is >= 1.0");
- }
- if (metadata instanceof KotlinClassMetadata.Class) {
- // TODO(danysantiago): If when we need other types of metadata then move to right method.
- return (KotlinClassMetadata.Class) metadata;
- } else {
- throw new IllegalStateException("Unsupported metadata type: " + metadata);
- }
- }
-
- private static final class ClassVisitor extends KmClassVisitor {
- static ClassMetadata createClassMetadata(KotlinClassMetadata.Class data) {
- ClassVisitor visitor = new ClassVisitor();
- data.accept(visitor);
- return visitor.classMetadata.build();
- }
-
- private final ClassMetadata.Builder classMetadata = ClassMetadata.builder();
-
- @Override
- public void visit(int flags, String name) {
- classMetadata.flags(flags).name(name);
- }
-
- @Override
- public KmConstructorVisitor visitConstructor(int flags) {
- return new KmConstructorVisitor() {
- private final FunctionMetadata.Builder constructor =
- FunctionMetadata.builder(flags, "<init>");
-
- @Override
- public KmValueParameterVisitor visitValueParameter(int flags, String name) {
- constructor.addParameter(ValueParameterMetadata.create(flags, name));
- return super.visitValueParameter(flags, name);
- }
-
- @Override
- public KmConstructorExtensionVisitor visitExtensions(KmExtensionType kmExtensionType) {
- return kmExtensionType.equals(JvmConstructorExtensionVisitor.TYPE)
- ? new JvmConstructorExtensionVisitor() {
- @Override
- public void visit(JvmMethodSignature jvmMethodSignature) {
- constructor.signature(jvmMethodSignature.asString());
- }
- }
- : null;
- }
-
- @Override
- public void visitEnd() {
- classMetadata.addConstructor(constructor.build());
- }
- };
- }
-
- @Override
- public KmFunctionVisitor visitFunction(int flags, String name) {
- return new KmFunctionVisitor() {
- private final FunctionMetadata.Builder function = FunctionMetadata.builder(flags, name);
-
- @Override
- public KmValueParameterVisitor visitValueParameter(int flags, String name) {
- function.addParameter(ValueParameterMetadata.create(flags, name));
- return super.visitValueParameter(flags, name);
- }
-
- @Override
- public KmFunctionExtensionVisitor visitExtensions(KmExtensionType kmExtensionType) {
- return kmExtensionType.equals(JvmFunctionExtensionVisitor.TYPE)
- ? new JvmFunctionExtensionVisitor() {
- @Override
- public void visit(JvmMethodSignature jvmMethodSignature) {
- function.signature(jvmMethodSignature.asString());
- }
- }
- : null;
- }
-
- @Override
- public void visitEnd() {
- classMetadata.addFunction(function.build());
- }
- };
- }
-
- @Override
- public void visitCompanionObject(String companionObjectName) {
- classMetadata.companionObjectName(companionObjectName);
- }
-
- @Override
- public KmPropertyVisitor visitProperty(
- int flags, String name, int getterFlags, int setterFlags) {
- return new KmPropertyVisitor() {
- private final PropertyMetadata.Builder property = PropertyMetadata.builder(flags, name);
-
- @Override
- public KmPropertyExtensionVisitor visitExtensions(KmExtensionType kmExtensionType) {
- if (!kmExtensionType.equals(JvmPropertyExtensionVisitor.TYPE)) {
- return null;
- }
-
- return new JvmPropertyExtensionVisitor() {
- @Override
- public void visit(
- int jvmFlags,
- @Nullable JvmFieldSignature jvmFieldSignature,
- @Nullable JvmMethodSignature jvmGetterSignature,
- @Nullable JvmMethodSignature jvmSetterSignature) {
- property.fieldSignature(
- Optional.ofNullable(jvmFieldSignature).map(JvmFieldSignature::asString));
- property.getterSignature(
- Optional.ofNullable(jvmGetterSignature).map(JvmMethodSignature::asString));
- }
-
- @Override
- public void visitSyntheticMethodForAnnotations(
- @Nullable JvmMethodSignature methodSignature) {
- property.methodForAnnotationsSignature(
- Optional.ofNullable(methodSignature).map(JvmMethodSignature::asString));
- }
- };
- }
-
- @Override
- public void visitEnd() {
- classMetadata.addProperty(property.build());
- }
- };
- }
- }
-
- @AutoValue
- abstract static class ClassMetadata extends BaseMetadata {
- abstract Optional<String> companionObjectName();
-
- abstract ImmutableSet<FunctionMetadata> constructors();
-
- abstract ImmutableMap<String, FunctionMetadata> functionsBySignature();
-
- abstract ImmutableMap<String, PropertyMetadata> propertiesByFieldSignature();
-
- static Builder builder() {
- return new AutoValue_KotlinMetadata_ClassMetadata.Builder();
- }
-
- @AutoValue.Builder
- abstract static class Builder implements BaseMetadata.Builder<Builder> {
- abstract Builder companionObjectName(String companionObjectName);
-
- abstract ImmutableSet.Builder<FunctionMetadata> constructorsBuilder();
-
- abstract ImmutableMap.Builder<String, FunctionMetadata> functionsBySignatureBuilder();
-
- abstract ImmutableMap.Builder<String, PropertyMetadata> propertiesByFieldSignatureBuilder();
-
- Builder addConstructor(FunctionMetadata constructor) {
- constructorsBuilder().add(constructor);
- return this;
- }
-
- Builder addFunction(FunctionMetadata function) {
- functionsBySignatureBuilder().put(function.signature(), function);
- return this;
- }
-
- Builder addProperty(PropertyMetadata property) {
- if (property.fieldSignature().isPresent()) {
- propertiesByFieldSignatureBuilder().put(property.fieldSignature().get(), property);
- }
- return this;
- }
-
- abstract ClassMetadata build();
- }
- }
-
- @AutoValue
- abstract static class FunctionMetadata extends BaseMetadata {
- abstract String signature();
-
- abstract ImmutableList<ValueParameterMetadata> parameters();
-
- static Builder builder(int flags, String name) {
- return new AutoValue_KotlinMetadata_FunctionMetadata.Builder().flags(flags).name(name);
- }
-
- @AutoValue.Builder
- abstract static class Builder implements BaseMetadata.Builder<Builder> {
- abstract Builder signature(String signature);
-
- abstract ImmutableList.Builder<ValueParameterMetadata> parametersBuilder();
-
- Builder addParameter(ValueParameterMetadata parameter) {
- parametersBuilder().add(parameter);
- return this;
- }
-
- abstract FunctionMetadata build();
- }
- }
-
- @AutoValue
- abstract static class PropertyMetadata extends BaseMetadata {
- /** Returns the JVM field descriptor of the backing field of this property. */
- abstract Optional<String> fieldSignature();
-
- abstract Optional<String> getterSignature();
-
- /** Returns JVM method descriptor of the synthetic method for property annotations. */
- abstract Optional<String> methodForAnnotationsSignature();
-
- static Builder builder(int flags, String name) {
- return new AutoValue_KotlinMetadata_PropertyMetadata.Builder().flags(flags).name(name);
- }
-
- @AutoValue.Builder
- interface Builder extends BaseMetadata.Builder<Builder> {
- Builder fieldSignature(Optional<String> signature);
-
- Builder getterSignature(Optional<String> signature);
-
- Builder methodForAnnotationsSignature(Optional<String> signature);
-
- PropertyMetadata build();
- }
- }
-
- @AutoValue
- abstract static class ValueParameterMetadata extends BaseMetadata {
- private static ValueParameterMetadata create(int flags, String name) {
- return new AutoValue_KotlinMetadata_ValueParameterMetadata(flags, name);
- }
- }
-
- abstract static class BaseMetadata {
- /** Returns the Kotlin metadata flags for this property. */
- abstract int flags();
-
- /** returns {@code true} if the given flag (e.g. {@link Flag.IS_PRIVATE}) applies. */
- boolean flags(Flag flag) {
- return flag.invoke(flags());
- }
-
- /** Returns the simple name of this property. */
- abstract String name();
-
- interface Builder<BuilderT> {
- BuilderT flags(int flags);
-
- BuilderT name(String name);
- }
- }
-
- @AutoValue
- abstract static class MethodForAnnotations {
- static MethodForAnnotations create(ExecutableElement method) {
- return new AutoValue_KotlinMetadata_MethodForAnnotations(method);
- }
-
- static final MethodForAnnotations MISSING = MethodForAnnotations.create(null);
-
- @Nullable
- abstract ExecutableElement method();
- }
-}
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataFactory.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataFactory.java
deleted file mode 100644
index 1515469..0000000
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadataFactory.java
+++ /dev/null
@@ -1,63 +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.internal.codegen.kotlin;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-
-import dagger.internal.codegen.base.ClearableCache;
-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;
-import kotlin.Metadata;
-
-/**
- * Factory creating Kotlin metadata data objects.
- *
- * <p>The metadata is cache since it can be expensive to parse the information stored in a proto
- * binary string format in the metadata annotation values.
- */
-@Singleton
-public final class KotlinMetadataFactory implements ClearableCache {
- private final Map<TypeElement, KotlinMetadata> metadataCache = new HashMap<>();
-
- @Inject
- KotlinMetadataFactory() {}
-
- /**
- * Parses and returns the {@link KotlinMetadata} out of a given element.
- *
- * @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)}
- */
- public KotlinMetadata create(Element element) {
- TypeElement enclosingElement = closestEnclosingTypeElement(element);
- if (!isAnnotationPresent(enclosingElement, Metadata.class)) {
- throw new IllegalStateException("Missing @Metadata for: " + enclosingElement);
- }
- return metadataCache.computeIfAbsent(enclosingElement, KotlinMetadata::from);
- }
-
- @Override
- public void clearCache() {
- metadataCache.clear();
- }
-}
diff --git a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java b/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
deleted file mode 100644
index 76d28f0..0000000
--- a/java/dagger/internal/codegen/kotlin/KotlinMetadataUtil.java
+++ /dev/null
@@ -1,157 +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.internal.codegen.kotlin;
-
-import static com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-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 com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import dagger.internal.codegen.extension.DaggerCollectors;
-import java.lang.annotation.Annotation;
-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 kotlin.jvm.JvmStatic;
-import kotlinx.metadata.Flag;
-
-/** Utility class for interacting with Kotlin Metadata. */
-public final class KotlinMetadataUtil {
-
- private final KotlinMetadataFactory metadataFactory;
-
- @Inject
- KotlinMetadataUtil(KotlinMetadataFactory metadataFactory) {
- this.metadataFactory = metadataFactory;
- }
-
- /**
- * 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);
- }
-
- /**
- * Returns the synthetic annotations of a Kotlin property.
- *
- * <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 ImmutableCollection<? extends AnnotationMirror> getSyntheticPropertyAnnotations(
- VariableElement fieldElement, Class<? extends Annotation> annotationType) {
- return metadataFactory
- .create(fieldElement)
- .getSyntheticAnnotationMethod(fieldElement)
- .map(methodElement -> getAnnotatedAnnotations(methodElement, annotationType).asList())
- .orElse(ImmutableList.of());
- }
-
- /**
- * 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 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 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) {
- return metadataFactory.create(fieldElement).getPropertyGetter(fieldElement);
- }
-
- public boolean containsConstructorWithDefaultParam(TypeElement typeElement) {
- return hasMetadata(typeElement)
- && metadataFactory.create(typeElement).containsConstructorWithDefaultParam();
- }
-
- /**
- * Returns {@code true} if the <code>@JvmStatic</code> annotation is present in the given element.
- */
- public static boolean isJvmStaticPresent(ExecutableElement element) {
- return isAnnotationPresent(element, JvmStatic.class);
- }
-}
diff --git a/java/dagger/internal/codegen/kythe/BUILD b/java/dagger/internal/codegen/kythe/BUILD
deleted file mode 100644
index 9e8dea1..0000000
--- a/java/dagger/internal/codegen/kythe/BUILD
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2017 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# A library for the kythe plugin.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "kythe",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen:component-codegen"],
- deps = [
- ":kythe_plugin",
- "//java/dagger:core",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/javac",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:service",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-load("@rules_java//java:defs.bzl", "java_import")
-
-# A _deploy.jar consisting of the java_librarys in https://github.com/kythe/kythe needed to build a
-# Kythe plugin
-# TODO(ronshapiro): replace this with a http_archive of the next release in
-# https://github.com/kythe/kythe/releases
-java_import(
- name = "kythe_plugin",
- jars = ["kythe_plugin_deploy.jar"],
- neverlink = 1,
-)
diff --git a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java b/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
deleted file mode 100644
index 4c6f85e..0000000
--- a/java/dagger/internal/codegen/kythe/DaggerKythePlugin.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-// This must be in the dagger.internal.codegen package since Dagger doesn't expose its APIs publicly
-// https://github.com/google/dagger/issues/773 could present an opportunity to put this somewhere in
-// the regular kythe/java tree.
-package dagger.internal.codegen.kythe;
-
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-
-import com.google.auto.service.AutoService;
-import com.google.common.collect.Iterables;
-import com.google.devtools.kythe.analyzers.base.EntrySet;
-import com.google.devtools.kythe.analyzers.base.FactEmitter;
-import com.google.devtools.kythe.analyzers.base.KytheEntrySets;
-import com.google.devtools.kythe.analyzers.java.Plugin;
-import com.google.devtools.kythe.proto.Storage.VName;
-import com.sun.tools.javac.code.Symbol;
-import com.sun.tools.javac.tree.JCTree.JCClassDecl;
-import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
-import com.sun.tools.javac.util.Context;
-import dagger.BindsInstance;
-import dagger.Component;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingDeclaration;
-import dagger.internal.codegen.binding.BindingGraphFactory;
-import dagger.internal.codegen.binding.BindingNode;
-import dagger.internal.codegen.binding.ComponentDescriptorFactory;
-import dagger.internal.codegen.binding.ModuleDescriptor;
-import dagger.internal.codegen.javac.JavacPluginModule;
-import dagger.internal.codegen.validation.InjectBindingRegistryModule;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.Node;
-import dagger.model.DependencyRequest;
-import dagger.producers.ProductionComponent;
-import java.util.Optional;
-import java.util.logging.Logger;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.element.Element;
-
-/**
- * A plugin which emits nodes and edges for <a href="https://github.com/google/dagger">Dagger</a>
- * specific code.
- */
-@AutoService(Plugin.class)
-public class DaggerKythePlugin extends Plugin.Scanner<Void, Void> {
- // TODO(ronshapiro): use flogger
- private static final Logger logger = Logger.getLogger(DaggerKythePlugin.class.getCanonicalName());
- private FactEmitter emitter;
- @Inject ComponentDescriptorFactory componentDescriptorFactory;
- @Inject BindingGraphFactory bindingGraphFactory;
-
- @Override
- public Void visitClassDef(JCClassDecl tree, Void p) {
- if (tree.sym != null
- && isAnyAnnotationPresent(tree.sym, Component.class, ProductionComponent.class)) {
- addNodesForGraph(
- bindingGraphFactory.create(
- componentDescriptorFactory.rootComponentDescriptor(tree.sym), false));
- }
- return super.visitClassDef(tree, p);
- }
-
- private void addNodesForGraph(dagger.internal.codegen.binding.BindingGraph graph) {
- addDependencyEdges(graph.topLevelBindingGraph());
-
- // TODO(bcorso): Convert these to use the new BindingGraph
- addModuleEdges(graph);
- addChildComponentEdges(graph);
- }
-
- private void addDependencyEdges(BindingGraph graph) {
- for (DependencyEdge dependencyEdge : graph.dependencyEdges()) {
- DependencyRequest dependency = dependencyEdge.dependencyRequest();
- Node node = graph.network().incidentNodes(dependencyEdge).target();
- addEdgesForDependencyRequest(dependency, (BindingNode) node, graph);
- }
- }
-
- /**
- * Add {@code /inject/satisfiedby} edges from {@code dependency}'s {@link
- * DependencyRequest#requestElement()} to any {@link BindingDeclaration#bindingElement() binding
- * elements} that satisfy the request.
- *
- * <p>This collapses requests for synthetic bindings so that a request for a multibound key
- * points to all of the contributions for the multibound object. It does so by recursively calling
- * this method, with each dependency's key as the {@code targetKey}.
- */
- private void addEdgesForDependencyRequest(
- DependencyRequest dependency, BindingNode bindingNode, BindingGraph graph) {
- if (!dependency.requestElement().isPresent()) {
- return;
- }
- Binding binding = bindingNode.delegate();
- if (binding.bindingElement().isPresent()) {
- addDependencyEdge(dependency, binding);
- } else {
- for (Edge outEdge : graph.network().outEdges(bindingNode)) {
- if (outEdge instanceof DependencyEdge) {
- Node outNode = graph.network().incidentNodes(outEdge).target();
- addEdgesForDependencyRequest(dependency, (BindingNode) outNode, graph);
- }
- }
- }
- for (BindingDeclaration bindingDeclaration :
- Iterables.concat(
- bindingNode.multibindingDeclarations(),
- bindingNode.optionalBindingDeclarations())) {
- addDependencyEdge(dependency, bindingDeclaration);
- }
- }
-
- private void addDependencyEdge(
- DependencyRequest dependency, BindingDeclaration bindingDeclaration) {
- Element requestElement = dependency.requestElement().get();
- Element bindingElement = bindingDeclaration.bindingElement().get();
- Optional<VName> requestElementNode = jvmNode(requestElement, "request element");
- Optional<VName> bindingElementNode = jvmNode(bindingElement, "binding element");
- emitEdge(requestElementNode, "/inject/satisfiedby", bindingElementNode);
- // TODO(ronshapiro): emit facts about the component that satisfies the edge
- }
-
- private void addModuleEdges(dagger.internal.codegen.binding.BindingGraph graph) {
- Optional<VName> componentNode = jvmNode(graph.componentTypeElement(), "component");
- for (ModuleDescriptor module : graph.componentDescriptor().modules()) {
- Optional<VName> moduleNode = jvmNode(module.moduleElement(), "module");
- emitEdge(componentNode, "/inject/installsmodule", moduleNode);
- }
- graph.subgraphs().forEach(this::addModuleEdges);
- }
-
- private void addChildComponentEdges(dagger.internal.codegen.binding.BindingGraph graph) {
- Optional<VName> componentNode = jvmNode(graph.componentTypeElement(), "component");
- for (dagger.internal.codegen.binding.BindingGraph subgraph : graph.subgraphs()) {
- Optional<VName> subcomponentNode =
- jvmNode(subgraph.componentTypeElement(), "child component");
- emitEdge(componentNode, "/inject/childcomponent", subcomponentNode);
- }
- graph.subgraphs().forEach(this::addChildComponentEdges);
- }
-
- private Optional<VName> jvmNode(Element element, String name) {
- Optional<VName> jvmNode = kytheGraph.getJvmNode((Symbol) element).map(KytheNode::getVName);
- if (!jvmNode.isPresent()) {
- logger.warning(String.format("Missing JVM node for %s: %s", name, element));
- }
- return jvmNode;
- }
-
- private void emitEdge(Optional<VName> source, String edgeName, Optional<VName> target) {
- source.ifPresent(
- s -> target.ifPresent(t -> new EntrySet.Builder(s, edgeName, t).build().emit(emitter)));
- }
-
- @Override
- public void run(
- JCCompilationUnit compilationUnit, KytheEntrySets entrySets, KytheGraph kytheGraph) {
- if (bindingGraphFactory == null) {
- emitter = entrySets.getEmitter();
- DaggerDaggerKythePlugin_PluginComponent.builder()
- .context(kytheGraph.getJavaContext())
- .build()
- .inject(this);
- }
- super.run(compilationUnit, entrySets, kytheGraph);
- }
-
- @Singleton
- @Component(modules = {InjectBindingRegistryModule.class, JavacPluginModule.class})
- interface PluginComponent {
- void inject(DaggerKythePlugin plugin);
-
- @Component.Builder
- interface Builder {
- @BindsInstance
- Builder context(Context context);
-
- PluginComponent build();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/kythe/kythe_plugin_deploy.jar b/java/dagger/internal/codegen/kythe_plugin_deploy.jar
similarity index 100%
rename from java/dagger/internal/codegen/kythe/kythe_plugin_deploy.jar
rename to java/dagger/internal/codegen/kythe_plugin_deploy.jar
Binary files differ
diff --git a/java/dagger/internal/codegen/langmodel/BUILD b/java/dagger/internal/codegen/langmodel/BUILD
index 670f4aa..16fa5d8 100644
--- a/java/dagger/internal/codegen/langmodel/BUILD
+++ b/java/dagger/internal/codegen/langmodel/BUILD
@@ -15,22 +15,17 @@
# Description:
# Dagger-specific extensions to the javax.lang.model APIs
-load("@rules_java//java:defs.bzl", "java_library")
-
package(default_visibility = ["//:src"])
java_library(
name = "langmodel",
srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
+ plugins = ["//java/dagger/internal/codegen:bootstrap_compiler_plugin"],
tags = ["maven:merged"],
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/internal/guava:graph",
+ "@google_bazel_common//third_party/java/auto:common",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
- "@maven//:com_google_auto_auto_common",
],
)
diff --git a/java/dagger/internal/codegen/langmodel/DaggerElements.java b/java/dagger/internal/codegen/langmodel/DaggerElements.java
index 12cec31..873ad3d 100644
--- a/java/dagger/internal/codegen/langmodel/DaggerElements.java
+++ b/java/dagger/internal/codegen/langmodel/DaggerElements.java
@@ -28,7 +28,6 @@
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.graph.Traverser;
@@ -43,7 +42,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
@@ -53,22 +51,8 @@
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.QualifiedNameable;
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.NullType;
-import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.UnionType;
-import javax.lang.model.type.WildcardType;
-import javax.lang.model.util.AbstractTypeVisitor8;
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleElementVisitor8;
import javax.lang.model.util.Types;
@@ -247,161 +231,6 @@
}
/**
- * 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 AbstractTypeVisitor8<String, Void> JVM_DESCRIPTOR_TYPE_VISITOR =
- new AbstractTypeVisitor8<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(DaggerElements::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 visitNull(NullType nullType, Void v) {
- return visitUnknown(nullType, null);
- }
-
- @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 visitUnion(UnionType unionType, Void v) {
- return visitUnknown(unionType, null);
- }
-
- @Override
- public String visitUnknown(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) {
- try {
- TypeElement typeElement = MoreElements.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.");
- }
- } catch (IllegalArgumentException e) {
- // Not a TypeElement, try something else...
- }
-
- if (element instanceof QualifiedNameable) {
- QualifiedNameable qualifiedNameElement = (QualifiedNameable) element;
- return qualifiedNameElement.getQualifiedName().toString().replace('.', '/');
- }
-
- return element.getSimpleName().toString();
- }
- };
-
- /**
* Invokes {@link Elements#getTypeElement(CharSequence)}, throwing {@link TypeNotPresentException}
* if it is not accessible in the current compilation.
*/
@@ -424,14 +253,6 @@
return elements.getElementValuesWithDefaults(a);
}
- /** Returns a map of annotation values keyed by attribute name. */
- public Map<String, ? extends AnnotationValue> getElementValuesWithDefaultsByName(
- AnnotationMirror a) {
- ImmutableMap.Builder<String, AnnotationValue> builder = ImmutableMap.builder();
- getElementValuesWithDefaults(a).forEach((k, v) -> builder.put(k.getSimpleName().toString(), v));
- return builder.build();
- }
-
@Override
public String getDocComment(Element e) {
return elements.getDocComment(e);
diff --git a/java/dagger/internal/codegen/langmodel/DaggerTypes.java b/java/dagger/internal/codegen/langmodel/DaggerTypes.java
index fb291db..e588fbd 100644
--- a/java/dagger/internal/codegen/langmodel/DaggerTypes.java
+++ b/java/dagger/internal/codegen/langmodel/DaggerTypes.java
@@ -83,7 +83,7 @@
* @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more
* than one type arguments.
*/
- public static TypeMirror unwrapType(TypeMirror type) {
+ public TypeMirror unwrapType(TypeMirror type) {
TypeMirror unwrapped = unwrapTypeOrDefault(type, null);
checkArgument(unwrapped != null, "%s is a raw type", type);
return unwrapped;
@@ -101,7 +101,7 @@
return unwrapTypeOrDefault(type, elements.getTypeElement(Object.class).asType());
}
- private static TypeMirror unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType) {
+ private TypeMirror unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType) {
DeclaredType declaredType = MoreTypes.asDeclared(type);
TypeElement typeElement = MoreElements.asType(declaredType.asElement());
checkArgument(
diff --git a/java/dagger/internal/codegen/package-info.java b/java/dagger/internal/codegen/package-info.java
index 4c478d6..c8cc404 100644
--- a/java/dagger/internal/codegen/package-info.java
+++ b/java/dagger/internal/codegen/package-info.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-/** Apply {@link CheckReturnValue} by default to every method in this package. */
@CheckReturnValue
package dagger.internal.codegen;
diff --git a/java/dagger/internal/codegen/serialization/BUILD b/java/dagger/internal/codegen/serialization/BUILD
new file mode 100644
index 0000000..2bc02b4
--- /dev/null
+++ b/java/dagger/internal/codegen/serialization/BUILD
@@ -0,0 +1,41 @@
+# 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.
+
+# Description:
+# Serialized forms of types used in the Dagger processor.
+
+package(default_visibility = ["//:src"])
+
+proto_library(
+ name = "serialization_proto",
+ srcs = ["serialization.proto"],
+ visibility = ["//visibility:private"],
+)
+
+java_proto_library(
+ name = "serialization_java_proto",
+ visibility = ["//visibility:private"],
+ deps = [":serialization_proto"],
+)
+
+java_library(
+ name = "serialization",
+ srcs = glob(["*.java"]),
+ exports = [":serialization_java_proto"],
+ deps = [
+ "@google_bazel_common//third_party/java/guava",
+ "@google_bazel_common//third_party/java/javapoet",
+ "@google_bazel_common//third_party/java/protobuf",
+ ],
+)
diff --git a/java/dagger/internal/codegen/serialization/ProtoSerialization.java b/java/dagger/internal/codegen/serialization/ProtoSerialization.java
new file mode 100644
index 0000000..1449e9d
--- /dev/null
+++ b/java/dagger/internal/codegen/serialization/ProtoSerialization.java
@@ -0,0 +1,81 @@
+/*
+ * 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.internal.codegen.serialization;
+
+import static com.google.common.io.BaseEncoding.base64;
+
+import com.google.common.io.BaseEncoding;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Message;
+import com.squareup.javapoet.CodeBlock;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.AnnotationValueVisitor;
+import javax.lang.model.util.SimpleAnnotationValueVisitor8;
+
+/**
+ * Serializes and deserializes {@link Message}s using {@link BaseEncoding#base64()} for use in
+ * annotation values.
+ */
+public final class ProtoSerialization {
+ /** Returns a {@link CodeBlock} of {@code message} serialized as a String. */
+ public static CodeBlock toAnnotationValue(Message message) {
+ return CodeBlock.of("$S", base64().encode(message.toByteArray()));
+ }
+
+ /**
+ * Returns a {@link Message T} from the deserialized the String {@code value}.
+ *
+ * @throws IllegalArgumentException if {@code value} represents an {@link AnnotationValue} who's
+ * type is not {@link String}
+ */
+ public static <T extends Message> T fromAnnotationValue(
+ AnnotationValue value, T defaultInstance) {
+ byte[] bytes = base64().decode(value.accept(STRING_VALUE, null));
+ Message message;
+ try {
+ message = defaultInstance.getParserForType().parseFrom(bytes);
+ } catch (InvalidProtocolBufferException e) {
+ throw new InconsistentSerializedProtoException(e);
+ }
+ @SuppressWarnings("unchecked") // guaranteed by proto API
+ T t = (T) message;
+ return t;
+ }
+
+ private static final AnnotationValueVisitor<String, Void> STRING_VALUE =
+ new SimpleAnnotationValueVisitor8<String, Void>() {
+ @Override
+ public String visitString(String s, Void ignored) {
+ return s;
+ }
+
+ @Override
+ protected String defaultAction(Object o, Void ignored) {
+ throw new IllegalArgumentException(o + " is not a String");
+ }
+ };
+
+ /**
+ * An exception thrown when the proto that's serialized in a compiled subcomponent implementation
+ * is from a different version than the current compiler's.
+ */
+ public static final class InconsistentSerializedProtoException extends RuntimeException {
+ InconsistentSerializedProtoException(Throwable cause) {
+ super(cause);
+ }
+ }
+}
diff --git a/java/dagger/internal/codegen/serialization/serialization.proto b/java/dagger/internal/codegen/serialization/serialization.proto
new file mode 100644
index 0000000..e6c9577
--- /dev/null
+++ b/java/dagger/internal/codegen/serialization/serialization.proto
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+// Serialized forms of types used in the Dagger processor. The wire format of
+// these types is not guaranteed to remain compatible over time; serialization
+// is only expected to function correctly within an individual version of the
+// Dagger processor.
+
+syntax = "proto3";
+
+package dagger.internal.codegen.serialization;
+option java_package = "dagger.internal.codegen.serialization";
+option java_multiple_files = true;
+
+// TODO(ronshapiro): consider exposing some of these in
+// dagger.model.serialization
+
+// Serialized form of `dagger.internal.codegen.BindingRequest`
+message BindingRequestProto {
+ KeyProto key = 1;
+ RequestKindWrapper.RequestKind request_kind = 2;
+ FrameworkTypeWrapper.FrameworkType framework_type = 3;
+}
+
+message RequestKindWrapper {
+ // Serialized form of `dagger.model.RequestKind`
+ enum RequestKind {
+ UNKNOWN = 0;
+ INSTANCE = 1;
+ PROVIDER = 2;
+ LAZY = 3;
+ PROVIDER_OF_LAZY = 4;
+ MEMBERS_INJECTION = 5;
+ PRODUCER = 6;
+ PRODUCED = 7;
+ FUTURE = 8;
+ }
+}
+
+message FrameworkTypeWrapper {
+ // Serialized form of `dagger.internal.codegen.FrameworkType`
+ enum FrameworkType {
+ UNKNOWN = 0;
+ PROVIDER = 1;
+ PRODUCER_NODE = 2;
+ }
+}
+
+// Serialized form of `dagger.model.Key`
+message KeyProto {
+ TypeProto type = 1;
+ AnnotationProto qualifier = 2;
+ MultibindingContributionIdentifier multibinding_contribution_identifier =
+ 3;
+
+ // Serialized form of `dagger.model.Key.MultibindingContributionIdentifier`
+ message MultibindingContributionIdentifier {
+ string module = 1;
+ string binding_element = 2;
+ }
+}
+
+// Serialized form of `javax.lang.model.type.TypeMirror`
+message TypeProto {
+ PrimitiveKind primitive_kind = 1;
+
+ // The qualified name of the type. Absent if this is an inner type.
+ string qualified_name = 2;
+
+ // The enclosing type if this is an inner type, otherwise absent.
+ TypeProto enclosing_type = 3;
+
+ // Simple name of the type if this is an inner type, otherwise absent.
+ string simple_name = 4;
+
+ repeated TypeProto type_arguments = 5;
+
+ message Wildcard {
+ TypeProto extends_bound = 1;
+ TypeProto super_bound = 2;
+ }
+ Wildcard wildcard = 6;
+
+ int32 array_dimensions = 7;
+
+ // Kinds of primitive types
+ enum PrimitiveKind {
+ UNKNOWN = 0;
+ BOOLEAN = 1;
+ BYTE = 2;
+ SHORT = 3;
+ CHAR = 4;
+ INT = 5;
+ FLOAT = 6;
+ LONG = 7;
+ DOUBLE = 8;
+ }
+}
+
+// Serialized form of `javax.lang.model.element.AnnotationMirror`
+message AnnotationProto {
+ TypeProto annotation_type = 1;
+ map<string, AnnotationValueProto> values = 2;
+}
+
+// Serialized form of `javax.lang.model.element.AnnotationValue`
+message AnnotationValueProto {
+ Kind kind = 1;
+ bool boolean_value = 2;
+ int32 int_value = 3;
+ int64 long_value = 4;
+ float float_value = 5;
+ double double_value = 6;
+ string string_value = 7;
+ TypeProto class_literal = 8;
+ TypeProto enum_type = 9;
+ string enum_name = 10;
+ AnnotationProto nested_annotation = 11;
+
+ repeated AnnotationValueProto array_values = 12;
+
+ // The type of annotation value
+ enum Kind {
+ UNKNOWN = 0;
+ BOOLEAN = 1;
+ BYTE = 2;
+ SHORT = 3;
+ CHAR = 4;
+ INT = 5;
+ FLOAT = 6;
+ LONG = 7;
+ DOUBLE = 8;
+ STRING = 9;
+ CLASS_LITERAL = 10;
+ ENUM = 11;
+ ANNOTATION = 12;
+ ARRAY = 13;
+ }
+}
+
+// Serialized form of `dagger.internal.codegen.ComponentRequirement`
+message ComponentRequirementProto {
+ oneof requirement {
+ TypeProto dependency = 1;
+ TypeProto module = 2;
+ BoundInstanceRequirement bound_instance = 3;
+ }
+
+ message BoundInstanceRequirement {
+ KeyProto key = 1;
+ bool nullable = 2;
+ string variable_name = 3;
+ }
+}
diff --git a/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java b/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java
deleted file mode 100644
index 140afd2..0000000
--- a/java/dagger/internal/codegen/validation/AnyBindingMethodValidator.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static java.util.stream.Collectors.joining;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.base.ClearableCache;
-import java.lang.annotation.Annotation;
-import java.util.HashMap;
-import java.util.Map;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-
-/** Validates any binding method. */
-@Singleton
-public final class AnyBindingMethodValidator implements ClearableCache {
- private final ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> validators;
- private final Map<ExecutableElement, ValidationReport<ExecutableElement>> reports =
- new HashMap<>();
-
- @Inject
- AnyBindingMethodValidator(
- ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> validators) {
- this.validators = validators;
- }
-
- @Override
- public void clearCache() {
- reports.clear();
- }
-
- /** Returns the binding method annotations considered by this validator. */
- ImmutableSet<Class<? extends Annotation>> methodAnnotations() {
- return validators.keySet();
- }
-
- /**
- * Returns {@code true} if {@code method} is annotated with at least one of {@link
- * #methodAnnotations()}.
- */
- boolean isBindingMethod(ExecutableElement method) {
- return isAnyAnnotationPresent(method, methodAnnotations());
- }
-
- /**
- * Returns a validation report for a method.
- *
- * <ul>
- * <li>Reports an error if {@code method} is annotated with more than one {@linkplain
- * #methodAnnotations() binding method annotation}.
- * <li>Validates {@code method} with the {@link BindingMethodValidator} for the single
- * {@linkplain #methodAnnotations() binding method annotation}.
- * </ul>
- *
- * @throws IllegalArgumentException if {@code method} is not annotated by any {@linkplain
- * #methodAnnotations() binding method annotation}
- */
- ValidationReport<ExecutableElement> validate(ExecutableElement method) {
- return reentrantComputeIfAbsent(reports, method, this::validateUncached);
- }
-
- /**
- * Returns {@code true} if {@code method} was already {@linkplain #validate(ExecutableElement)
- * validated}.
- */
- boolean wasAlreadyValidated(ExecutableElement method) {
- return reports.containsKey(method);
- }
-
- private ValidationReport<ExecutableElement> validateUncached(ExecutableElement method) {
- ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(method);
- ImmutableSet<? extends Class<? extends Annotation>> bindingMethodAnnotations =
- methodAnnotations()
- .stream()
- .filter(annotation -> isAnnotationPresent(method, annotation))
- .collect(toImmutableSet());
- switch (bindingMethodAnnotations.size()) {
- case 0:
- throw new IllegalArgumentException(
- String.format("%s has no binding method annotation", method));
-
- case 1:
- report.addSubreport(
- validators.get(getOnlyElement(bindingMethodAnnotations)).validate(method));
- break;
-
- default:
- report.addError(
- String.format(
- "%s is annotated with more than one of (%s)",
- method.getSimpleName(),
- methodAnnotations().stream().map(Class::getCanonicalName).collect(joining(", "))),
- method);
- break;
- }
- return report.build();
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BUILD b/java/dagger/internal/codegen/validation/BUILD
deleted file mode 100644
index 602157b..0000000
--- a/java/dagger/internal/codegen/validation/BUILD
+++ /dev/null
@@ -1,50 +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.
-
-# Description:
-# Code related to validating the user-written Dagger code
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "validation",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:cache",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/internal/guava:graph",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/checker_framework_annotations",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/validation/BindingElementValidator.java b/java/dagger/internal/codegen/validation/BindingElementValidator.java
deleted file mode 100644
index 4557745..0000000
--- a/java/dagger/internal/codegen/validation/BindingElementValidator.java
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Verify.verifyNotNull;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedInjectionType;
-import static dagger.internal.codegen.binding.MapKeys.getMapKeys;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static javax.lang.model.type.TypeKind.ARRAY;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.TYPEVAR;
-import static javax.lang.model.type.TypeKind.VOID;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.MapKey;
-import dagger.Provides;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.FrameworkTypes;
-import dagger.internal.codegen.base.MultibindingAnnotations;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.model.Key;
-import dagger.model.Scope;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.producers.Produces;
-import java.lang.annotation.Annotation;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.inject.Qualifier;
-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.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/** A validator for elements that represent binding declarations. */
-public abstract class BindingElementValidator<E extends Element> {
- private final Class<? extends Annotation> bindingAnnotation;
- private final AllowsMultibindings allowsMultibindings;
- private final AllowsScoping allowsScoping;
- private final Map<E, ValidationReport<E>> cache = new HashMap<>();
- private final InjectionAnnotations injectionAnnotations;
-
- /**
- * Creates a validator object.
- *
- * @param bindingAnnotation the annotation on an element that identifies it as a binding element
- */
- protected BindingElementValidator(
- Class<? extends Annotation> bindingAnnotation,
- AllowsMultibindings allowsMultibindings,
- AllowsScoping allowsScoping,
- InjectionAnnotations injectionAnnotations) {
- this.bindingAnnotation = bindingAnnotation;
- this.allowsMultibindings = allowsMultibindings;
- this.allowsScoping = allowsScoping;
- this.injectionAnnotations = injectionAnnotations;
- }
-
- /** Returns a {@link ValidationReport} for {@code element}. */
- final ValidationReport<E> validate(E element) {
- return reentrantComputeIfAbsent(cache, element, this::validateUncached);
- }
-
- private ValidationReport<E> validateUncached(E element) {
- return elementValidator(element).validate();
- }
-
- /**
- * Returns an error message of the form "<{@link #bindingElements()}> <i>rule</i>", where
- * <i>rule</i> comes from calling {@link String#format(String, Object...)} on {@code ruleFormat}
- * and the other arguments.
- */
- @FormatMethod
- protected final String bindingElements(String ruleFormat, Object... args) {
- return new Formatter().format("%s ", bindingElements()).format(ruleFormat, args).toString();
- }
-
- /**
- * The kind of elements that this validator validates. Should be plural. Used for error reporting.
- */
- protected abstract String bindingElements();
-
- /** The verb describing the {@link ElementValidator#bindingElementType()} in error messages. */
- // TODO(ronshapiro,dpb): improve the name of this method and it's documentation.
- protected abstract String bindingElementTypeVerb();
-
- /** The error message when a binding element has a bad type. */
- protected String badTypeMessage() {
- return bindingElements(
- "must %s a primitive, an array, a type variable, or a declared type",
- bindingElementTypeVerb());
- }
-
- /**
- * The error message when a the type for a binding element with {@link
- * ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a not set type.
- */
- protected String elementsIntoSetNotASetMessage() {
- return bindingElements(
- "annotated with @ElementsIntoSet must %s a Set", bindingElementTypeVerb());
- }
-
- /**
- * The error message when a the type for a binding element with {@link
- * ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} is a raw set.
- */
- protected String elementsIntoSetRawSetMessage() {
- return bindingElements(
- "annotated with @ElementsIntoSet cannot %s a raw Set", bindingElementTypeVerb());
- }
-
- /*** Returns an {@link ElementValidator} for validating the given {@code element}. */
- protected abstract ElementValidator elementValidator(E element);
-
- /** Validator for a single binding element. */
- protected abstract class ElementValidator {
- protected final E element;
- protected final ValidationReport.Builder<E> report;
-
- protected ElementValidator(E element) {
- this.element = element;
- this.report = ValidationReport.about(element);
- }
-
- /** Checks the element for validity. */
- private ValidationReport<E> validate() {
- checkType();
- checkQualifiers();
- checkMapKeys();
- checkMultibindings();
- checkScopes();
- checkAdditionalProperties();
- return report.build();
- }
-
- /** Check any additional properties of the element. Does nothing by default. */
- protected void checkAdditionalProperties() {}
-
- /**
- * The type declared by this binding element. This may differ from a binding's {@link
- * Key#type()}, for example in multibindings. An {@link Optional#empty()} return value indicates
- * that the contributed type is ambiguous or missing, i.e. a {@code @BindsInstance} method with
- * zero or many parameters.
- */
- // TODO(dpb): should this be an ImmutableList<TypeMirror>, with this class checking the size?
- protected abstract Optional<TypeMirror> bindingElementType();
-
- /**
- * Adds an error if the {@link #bindingElementType() binding element type} is not appropriate.
- *
- * <p>Adds an error if the type is not a primitive, array, declared type, or type variable.
- *
- * <p>If the binding is not a multibinding contribution, adds an error if the type is a
- * framework type.
- *
- * <p>If the element has {@link ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES}, adds an
- * error if the type is not a {@code Set<T>} for some {@code T}
- */
- protected void checkType() {
- switch (ContributionType.fromBindingElement(element)) {
- case UNIQUE:
- /* Validate that a unique binding is not attempting to bind a framework type. This
- * validation is only appropriate for unique bindings because multibindings may collect
- * framework types. E.g. Set<Provider<Foo>> is perfectly reasonable. */
- checkFrameworkType();
- // fall through
-
- case SET:
- case MAP:
- bindingElementType().ifPresent(type -> checkKeyType(type));
- break;
-
- case SET_VALUES:
- checkSetValuesType();
- }
- }
-
- /**
- * Adds an error if {@code keyType} is not a primitive, declared type, array, or type variable.
- */
- protected void checkKeyType(TypeMirror keyType) {
- TypeKind kind = keyType.getKind();
- if (kind.equals(VOID)) {
- report.addError(bindingElements("must %s a value (not void)", bindingElementTypeVerb()));
- } else if (kind == DECLARED) {
- checkNotAssistedInject(keyType);
- } else if (!(kind.isPrimitive() || kind.equals(ARRAY) || kind.equals(TYPEVAR))) {
- report.addError(badTypeMessage());
- }
- }
-
- /** Adds errors for a method return type. */
- private void checkNotAssistedInject(TypeMirror keyType) {
- checkState(keyType.getKind() == TypeKind.DECLARED);
- TypeElement keyElement = asTypeElement(keyType);
- if (isAssistedInjectionType(keyElement)) {
- report.addError("Dagger does not support providing @AssistedInject types.", keyElement);
- }
- if (isAssistedFactoryType(keyElement)) {
- report.addError("Dagger does not support providing @AssistedFactory types.", keyElement);
- }
- }
-
- /**
- * Adds an error if the type for an element with {@link ElementsIntoSet @ElementsIntoSet} or
- * {@code SET_VALUES} is not a a {@code Set<T>} for a reasonable {@code T}.
- */
- // TODO(gak): should we allow "covariant return" for set values?
- protected void checkSetValuesType() {
- bindingElementType().ifPresent(keyType -> checkSetValuesType(keyType));
- }
-
- /** Adds an error if {@code type} is not a {@code Set<T>} for a reasonable {@code T}. */
- protected final void checkSetValuesType(TypeMirror type) {
- if (!SetType.isSet(type)) {
- report.addError(elementsIntoSetNotASetMessage());
- } else {
- SetType setType = SetType.from(type);
- if (setType.isRawType()) {
- report.addError(elementsIntoSetRawSetMessage());
- } else {
- checkKeyType(setType.elementType());
- }
- }
- }
-
- /**
- * Adds an error if the element has more than one {@linkplain Qualifier qualifier} annotation.
- */
- private void checkQualifiers() {
- ImmutableCollection<? extends AnnotationMirror> qualifiers =
- injectionAnnotations.getQualifiers(element);
- if (qualifiers.size() > 1) {
- for (AnnotationMirror qualifier : qualifiers) {
- report.addError(
- bindingElements("may not use more than one @Qualifier"),
- element,
- qualifier);
- }
- }
- }
-
- /**
- * Adds an error if an {@link IntoMap @IntoMap} element doesn't have exactly one {@link
- * MapKey @MapKey} annotation, or if an element that is {@link IntoMap @IntoMap} has any.
- */
- private void checkMapKeys() {
- if (!allowsMultibindings.allowsMultibindings()) {
- return;
- }
- ImmutableSet<? extends AnnotationMirror> mapKeys = getMapKeys(element);
- if (ContributionType.fromBindingElement(element).equals(ContributionType.MAP)) {
- switch (mapKeys.size()) {
- case 0:
- report.addError(bindingElements("of type map must declare a map key"));
- break;
- case 1:
- break;
- default:
- report.addError(bindingElements("may not have more than one map key"));
- break;
- }
- } else if (!mapKeys.isEmpty()) {
- report.addError(bindingElements("of non map type cannot declare a map key"));
- }
- }
-
- /**
- * Adds errors if:
- *
- * <ul>
- * <li>the element doesn't allow {@linkplain MultibindingAnnotations multibinding annotations}
- * and has any
- * <li>the element does allow them but has more than one
- * <li>the element has a multibinding annotation and its {@link Provides} or {@link Produces}
- * annotation has a {@code type} parameter.
- * </ul>
- */
- private void checkMultibindings() {
- ImmutableSet<AnnotationMirror> multibindingAnnotations =
- MultibindingAnnotations.forElement(element);
-
- switch (allowsMultibindings) {
- case NO_MULTIBINDINGS:
- for (AnnotationMirror annotation : multibindingAnnotations) {
- report.addError(
- bindingElements("cannot have multibinding annotations"),
- element,
- annotation);
- }
- break;
-
- case ALLOWS_MULTIBINDINGS:
- if (multibindingAnnotations.size() > 1) {
- for (AnnotationMirror annotation : multibindingAnnotations) {
- report.addError(
- bindingElements("cannot have more than one multibinding annotation"),
- element,
- annotation);
- }
- }
- break;
- }
-
- // TODO(ronshapiro): move this into ProvidesMethodValidator
- if (bindingAnnotation.equals(Provides.class)) {
- AnnotationMirror bindingAnnotationMirror =
- getAnnotationMirror(element, bindingAnnotation).get();
- boolean usesProvidesType = false;
- for (ExecutableElement member : bindingAnnotationMirror.getElementValues().keySet()) {
- usesProvidesType |= member.getSimpleName().contentEquals("type");
- }
- if (usesProvidesType && !multibindingAnnotations.isEmpty()) {
- report.addError(
- "@Provides.type cannot be used with multibinding annotations", element);
- }
- }
- }
-
- /**
- * Adds an error if the element has a scope but doesn't allow scoping, or if it has more than
- * one {@linkplain Scope scope} annotation.
- */
- private void checkScopes() {
- ImmutableSet<Scope> scopes = scopesOf(element);
- String error = null;
- switch (allowsScoping) {
- case ALLOWS_SCOPING:
- if (scopes.size() <= 1) {
- return;
- }
- error = bindingElements("cannot use more than one @Scope");
- break;
- case NO_SCOPING:
- error = bindingElements("cannot be scoped");
- break;
- }
- verifyNotNull(error);
- for (Scope scope : scopes) {
- report.addError(error, element, scope.scopeAnnotation());
- }
- }
-
- /**
- * Adds an error if the {@link #bindingElementType() type} is a {@linkplain FrameworkTypes
- * framework type}.
- */
- private void checkFrameworkType() {
- if (bindingElementType().filter(FrameworkTypes::isFrameworkType).isPresent()) {
- report.addError(bindingElements("must not %s framework types", bindingElementTypeVerb()));
- }
- }
- }
-
- /** Whether to check multibinding annotations. */
- enum AllowsMultibindings {
- /**
- * This element disallows multibinding annotations, so don't bother checking for their validity.
- * {@link MultibindingAnnotationsProcessingStep} will add errors if the element has any
- * multibinding annotations.
- */
- NO_MULTIBINDINGS,
-
- /** This element allows multibinding annotations, so validate them. */
- ALLOWS_MULTIBINDINGS,
- ;
-
- private boolean allowsMultibindings() {
- return this == ALLOWS_MULTIBINDINGS;
- }
- }
-
- /** How to check scoping annotations. */
- enum AllowsScoping {
- /** This element disallows scoping, so check that no scope annotations are present. */
- NO_SCOPING,
-
- /** This element allows scoping, so validate that there's at most one scope annotation. */
- ALLOWS_SCOPING,
- ;
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindingGraphPlugins.java b/java/dagger/internal/codegen/validation/BindingGraphPlugins.java
deleted file mode 100644
index 16ef78f..0000000
--- a/java/dagger/internal/codegen/validation/BindingGraphPlugins.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2018 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.toImmutableSet;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import dagger.internal.codegen.compileroption.ProcessingOptions;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.spi.BindingGraphPlugin;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-
-/** Initializes {@link BindingGraphPlugin}s. */
-public final class BindingGraphPlugins {
- private final ImmutableSet<BindingGraphPlugin> plugins;
- private final Filer filer;
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final Map<String, String> processingOptions;
-
- @Inject
- BindingGraphPlugins(
- @Validation ImmutableSet<BindingGraphPlugin> validationPlugins,
- ImmutableSet<BindingGraphPlugin> externalPlugins,
- Filer filer,
- DaggerTypes types,
- DaggerElements elements,
- @ProcessingOptions Map<String, String> processingOptions) {
- this.plugins = Sets.union(validationPlugins, externalPlugins).immutableCopy();
- this.filer = filer;
- this.types = types;
- this.elements = elements;
- this.processingOptions = processingOptions;
- }
-
- /** Returns {@link BindingGraphPlugin#supportedOptions()} from all the plugins. */
- public ImmutableSet<String> allSupportedOptions() {
- return plugins.stream()
- .flatMap(plugin -> plugin.supportedOptions().stream())
- .collect(toImmutableSet());
- }
-
- /** Initializes the plugins. */
- // TODO(ronshapiro): Should we validate the uniqueness of plugin names?
- public void initializePlugins() {
- plugins.forEach(this::initializePlugin);
- }
-
- private void initializePlugin(BindingGraphPlugin plugin) {
- plugin.initFiler(filer);
- plugin.initTypes(types);
- plugin.initElements(elements);
- Set<String> supportedOptions = plugin.supportedOptions();
- if (!supportedOptions.isEmpty()) {
- plugin.initOptions(Maps.filterKeys(processingOptions, supportedOptions::contains));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindingGraphValidator.java b/java/dagger/internal/codegen/validation/BindingGraphValidator.java
deleted file mode 100644
index 99e86e7..0000000
--- a/java/dagger/internal/codegen/validation/BindingGraphValidator.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkNotNull;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.compileroption.ValidationType;
-import dagger.internal.codegen.validation.DiagnosticReporterFactory.DiagnosticReporterImpl;
-import dagger.model.BindingGraph;
-import dagger.spi.BindingGraphPlugin;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import javax.lang.model.element.TypeElement;
-
-/** Validates a {@link BindingGraph}. */
-@Singleton
-public final class BindingGraphValidator {
- private final ImmutableSet<BindingGraphPlugin> validationPlugins;
- private final ImmutableSet<BindingGraphPlugin> externalPlugins;
- private final DiagnosticReporterFactory diagnosticReporterFactory;
- private final CompilerOptions compilerOptions;
-
- @Inject
- BindingGraphValidator(
- @Validation ImmutableSet<BindingGraphPlugin> validationPlugins,
- ImmutableSet<BindingGraphPlugin> externalPlugins,
- DiagnosticReporterFactory diagnosticReporterFactory,
- CompilerOptions compilerOptions) {
- this.validationPlugins = validationPlugins;
- this.externalPlugins = externalPlugins;
- this.diagnosticReporterFactory = checkNotNull(diagnosticReporterFactory);
- this.compilerOptions = compilerOptions;
- }
-
- /** Returns {@code true} if validation or analysis is required on the full binding graph. */
- public boolean shouldDoFullBindingGraphValidation(TypeElement component) {
- return requiresFullBindingGraphValidation()
- || compilerOptions.pluginsVisitFullBindingGraphs(component);
- }
-
- private boolean requiresFullBindingGraphValidation() {
- return !compilerOptions.fullBindingGraphValidationType().equals(ValidationType.NONE);
- }
-
- /** Returns {@code true} if no errors are reported for {@code graph}. */
- public boolean isValid(BindingGraph graph) {
- return validate(graph) && visitPlugins(graph);
- }
-
- /** Returns {@code true} if validation plugins report no errors. */
- private boolean validate(BindingGraph graph) {
- if (graph.isFullBindingGraph() && !requiresFullBindingGraphValidation()) {
- return true;
- }
-
- boolean errorsAsWarnings =
- graph.isFullBindingGraph()
- && compilerOptions.fullBindingGraphValidationType().equals(ValidationType.WARNING);
-
- return runPlugins(validationPlugins, graph, errorsAsWarnings);
- }
-
- /** Returns {@code true} if external plugins report no errors. */
- private boolean visitPlugins(BindingGraph graph) {
- TypeElement component = graph.rootComponentNode().componentPath().currentComponent();
- if (graph.isFullBindingGraph()
- // TODO(b/135938915): Consider not visiting plugins if only
- // fullBindingGraphValidation is enabled.
- && !requiresFullBindingGraphValidation()
- && !compilerOptions.pluginsVisitFullBindingGraphs(component)) {
- return true;
- }
- return runPlugins(externalPlugins, graph, /*errorsAsWarnings=*/ false);
- }
-
- /** Returns {@code false} if any of the plugins reported an error. */
- private boolean runPlugins(
- ImmutableSet<BindingGraphPlugin> plugins, BindingGraph graph, boolean errorsAsWarnings) {
- boolean isClean = true;
- for (BindingGraphPlugin plugin : plugins) {
- DiagnosticReporterImpl reporter =
- diagnosticReporterFactory.reporter(graph, plugin, errorsAsWarnings);
- plugin.visitGraph(graph, reporter);
- if (reporter.reportedDiagnosticKinds().contains(ERROR)) {
- isClean = false;
- }
- }
- return isClean;
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java b/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java
deleted file mode 100644
index 10aec06..0000000
--- a/java/dagger/internal/codegen/validation/BindingMethodProcessingStep.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-
-/** A step that validates all binding methods that were not validated while processing modules. */
-public final class BindingMethodProcessingStep
- extends TypeCheckingProcessingStep<ExecutableElement> {
-
- private final Messager messager;
- private final AnyBindingMethodValidator anyBindingMethodValidator;
-
- @Inject
- BindingMethodProcessingStep(
- Messager messager, AnyBindingMethodValidator anyBindingMethodValidator) {
- super(MoreElements::asExecutable);
- this.messager = messager;
- this.anyBindingMethodValidator = anyBindingMethodValidator;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return anyBindingMethodValidator.methodAnnotations();
- }
-
- @Override
- protected void process(
- ExecutableElement method, ImmutableSet<Class<? extends Annotation>> annotations) {
- checkArgument(
- anyBindingMethodValidator.isBindingMethod(method),
- "%s is not annotated with any of %s",
- method,
- annotations());
- if (!anyBindingMethodValidator.wasAlreadyValidated(method)) {
- anyBindingMethodValidator.validate(method).printMessagesTo(messager);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindingMethodValidator.java b/java/dagger/internal/codegen/validation/BindingMethodValidator.java
deleted file mode 100644
index 81349b9..0000000
--- a/java/dagger/internal/codegen/validation/BindingMethodValidator.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreElements.asType;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.lang.annotation.Annotation;
-import java.util.Optional;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A validator for methods that represent binding declarations. */
-abstract class BindingMethodValidator extends BindingElementValidator<ExecutableElement> {
-
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
- private final DependencyRequestValidator dependencyRequestValidator;
- private final Class<? extends Annotation> methodAnnotation;
- private final ImmutableSet<? extends Class<? extends Annotation>> enclosingElementAnnotations;
- private final Abstractness abstractness;
- private final ExceptionSuperclass exceptionSuperclass;
-
- /**
- * Creates a validator object.
- *
- * @param methodAnnotation the annotation on a method that identifies it as a binding method
- * @param enclosingElementAnnotation the method must be declared in a class or interface annotated
- * with this annotation
- */
- protected BindingMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil metadataUtil,
- DependencyRequestValidator dependencyRequestValidator,
- Class<? extends Annotation> methodAnnotation,
- Class<? extends Annotation> enclosingElementAnnotation,
- Abstractness abstractness,
- ExceptionSuperclass exceptionSuperclass,
- AllowsMultibindings allowsMultibindings,
- AllowsScoping allowsScoping,
- InjectionAnnotations injectionAnnotations) {
- this(
- elements,
- types,
- metadataUtil,
- methodAnnotation,
- ImmutableSet.of(enclosingElementAnnotation),
- dependencyRequestValidator,
- abstractness,
- exceptionSuperclass,
- allowsMultibindings,
- allowsScoping,
- injectionAnnotations);
- }
-
- /**
- * Creates a validator object.
- *
- * @param methodAnnotation the annotation on a method that identifies it as a binding method
- * @param enclosingElementAnnotations the method must be declared in a class or interface
- * annotated with one of these annotations
- */
- protected BindingMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil metadataUtil,
- Class<? extends Annotation> methodAnnotation,
- Iterable<? extends Class<? extends Annotation>> enclosingElementAnnotations,
- DependencyRequestValidator dependencyRequestValidator,
- Abstractness abstractness,
- ExceptionSuperclass exceptionSuperclass,
- AllowsMultibindings allowsMultibindings,
- AllowsScoping allowsScoping,
- InjectionAnnotations injectionAnnotations) {
- super(methodAnnotation, allowsMultibindings, allowsScoping, injectionAnnotations);
- this.elements = elements;
- this.types = types;
- this.metadataUtil = metadataUtil;
- this.methodAnnotation = methodAnnotation;
- this.enclosingElementAnnotations = ImmutableSet.copyOf(enclosingElementAnnotations);
- this.dependencyRequestValidator = dependencyRequestValidator;
- this.abstractness = abstractness;
- this.exceptionSuperclass = exceptionSuperclass;
- }
-
- /** The annotation that identifies binding methods validated by this object. */
- final Class<? extends Annotation> methodAnnotation() {
- return methodAnnotation;
- }
-
- /**
- * Returns an error message of the form "@<i>annotation</i> methods <i>rule</i>", where
- * <i>rule</i> comes from calling {@link String#format(String, Object...)} on {@code ruleFormat}
- * and the other arguments.
- */
- @FormatMethod
- protected final String bindingMethods(String ruleFormat, Object... args) {
- return bindingElements(ruleFormat, args);
- }
-
- @Override
- protected final String bindingElements() {
- return String.format("@%s methods", methodAnnotation.getSimpleName());
- }
-
- @Override
- protected final String bindingElementTypeVerb() {
- return "return";
- }
-
- /** Abstract validator for individual binding method elements. */
- protected abstract class MethodValidator extends ElementValidator {
- protected MethodValidator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected final Optional<TypeMirror> bindingElementType() {
- return Optional.of(element.getReturnType());
- }
-
- @Override
- protected final void checkAdditionalProperties() {
- checkEnclosingElement();
- checkTypeParameters();
- checkNotPrivate();
- checkAbstractness();
- checkThrows();
- checkParameters();
- checkAdditionalMethodProperties();
- }
-
- /** Checks additional properties of the binding method. */
- protected void checkAdditionalMethodProperties() {}
-
- /**
- * Adds an error if the method is not declared in a class or interface annotated with one of the
- * {@link #enclosingElementAnnotations}.
- */
- private void checkEnclosingElement() {
- TypeElement enclosingElement = asType(element.getEnclosingElement());
- if (metadataUtil.isCompanionObjectClass(enclosingElement)) {
- // Binding method is in companion object, use companion object's enclosing class instead.
- enclosingElement = asType(enclosingElement.getEnclosingElement());
- }
- if (!isAnyAnnotationPresent(enclosingElement, enclosingElementAnnotations)) {
- report.addError(
- bindingMethods(
- "can only be present within a @%s",
- enclosingElementAnnotations.stream()
- .map(Class::getSimpleName)
- .collect(joining(" or @"))));
- }
- }
-
- /** Adds an error if the method is generic. */
- private void checkTypeParameters() {
- if (!element.getTypeParameters().isEmpty()) {
- report.addError(bindingMethods("may not have type parameters"));
- }
- }
-
- /** Adds an error if the method is private. */
- private void checkNotPrivate() {
- if (element.getModifiers().contains(PRIVATE)) {
- report.addError(bindingMethods("cannot be private"));
- }
- }
-
- /** Adds an error if the method is abstract but must not be, or is not and must be. */
- private void checkAbstractness() {
- boolean isAbstract = element.getModifiers().contains(ABSTRACT);
- switch (abstractness) {
- case MUST_BE_ABSTRACT:
- if (!isAbstract) {
- report.addError(bindingMethods("must be abstract"));
- }
- break;
-
- case MUST_BE_CONCRETE:
- if (isAbstract) {
- report.addError(bindingMethods("cannot be abstract"));
- }
- }
- }
-
- /**
- * Adds an error if the method declares throws anything but an {@link Error} or an appropriate
- * subtype of {@link Exception}.
- */
- private void checkThrows() {
- exceptionSuperclass.checkThrows(BindingMethodValidator.this, element, report);
- }
-
- /** Adds errors for the method parameters. */
- protected void checkParameters() {
- for (VariableElement parameter : element.getParameters()) {
- checkParameter(parameter);
- }
- }
-
- /**
- * Adds errors for a method parameter. This implementation reports an error if the parameter has
- * more than one qualifier.
- */
- protected void checkParameter(VariableElement parameter) {
- dependencyRequestValidator.validateDependencyRequest(report, parameter, parameter.asType());
- }
- }
-
- /** An abstract/concrete restriction on methods. */
- protected enum Abstractness {
- MUST_BE_ABSTRACT,
- MUST_BE_CONCRETE
- }
-
- /**
- * The exception class that all {@code throws}-declared throwables must extend, other than {@link
- * Error}.
- */
- protected enum ExceptionSuperclass {
- /** Methods may not declare any throwable types. */
- NO_EXCEPTIONS {
- @Override
- protected String errorMessage(BindingMethodValidator validator) {
- return validator.bindingMethods("may not throw");
- }
-
- @Override
- protected void checkThrows(
- BindingMethodValidator validator,
- ExecutableElement element,
- ValidationReport.Builder<ExecutableElement> report) {
- if (!element.getThrownTypes().isEmpty()) {
- report.addError(validator.bindingMethods("may not throw"));
- return;
- }
- }
- },
-
- /** Methods may throw checked or unchecked exceptions or errors. */
- EXCEPTION(Exception.class) {
- @Override
- protected String errorMessage(BindingMethodValidator validator) {
- return validator.bindingMethods(
- "may only throw unchecked exceptions or exceptions subclassing Exception");
- }
- },
-
- /** Methods may throw unchecked exceptions or errors. */
- RUNTIME_EXCEPTION(RuntimeException.class) {
- @Override
- protected String errorMessage(BindingMethodValidator validator) {
- return validator.bindingMethods("may only throw unchecked exceptions");
- }
- },
- ;
-
- private final Class<? extends Exception> superclass;
-
- ExceptionSuperclass() {
- this(null);
- }
-
- ExceptionSuperclass(Class<? extends Exception> superclass) {
- this.superclass = superclass;
- }
-
- /**
- * Adds an error if the method declares throws anything but an {@link Error} or an appropriate
- * subtype of {@link Exception}.
- *
- * <p>This method is overridden in {@link #NO_EXCEPTIONS}.
- */
- protected void checkThrows(
- BindingMethodValidator validator,
- ExecutableElement element,
- ValidationReport.Builder<ExecutableElement> report) {
- TypeMirror exceptionSupertype = validator.elements.getTypeElement(superclass).asType();
- TypeMirror errorType = validator.elements.getTypeElement(Error.class).asType();
- for (TypeMirror thrownType : element.getThrownTypes()) {
- if (!validator.types.isSubtype(thrownType, exceptionSupertype)
- && !validator.types.isSubtype(thrownType, errorType)) {
- report.addError(errorMessage(validator));
- break;
- }
- }
- }
-
- protected abstract String errorMessage(BindingMethodValidator validator);
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java b/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java
deleted file mode 100644
index 08afbc8..0000000
--- a/java/dagger/internal/codegen/validation/BindingMethodValidatorsModule.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.collect.Maps.uniqueIndex;
-
-import com.google.common.collect.ImmutableMap;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-
-/**
- * Binds each {@link BindingMethodValidator} into a map, keyed by {@link
- * BindingMethodValidator#methodAnnotation()}.
- */
-@Module
-public interface BindingMethodValidatorsModule {
- @Provides
- static ImmutableMap<Class<? extends Annotation>, BindingMethodValidator> indexValidators(
- Set<BindingMethodValidator> validators) {
- return uniqueIndex(validators, BindingMethodValidator::methodAnnotation);
- }
-
- @Binds
- @IntoSet
- BindingMethodValidator provides(ProvidesMethodValidator validator);
-
- @Binds
- @IntoSet
- BindingMethodValidator produces(ProducesMethodValidator validator);
-
- @Binds
- @IntoSet
- BindingMethodValidator binds(BindsMethodValidator validator);
-
- @Binds
- @IntoSet
- BindingMethodValidator multibinds(MultibindsMethodValidator validator);
-
- @Binds
- @IntoSet
- BindingMethodValidator bindsOptionalOf(BindsOptionalOfMethodValidator validator);
-}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java b/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java
deleted file mode 100644
index 283af7d..0000000
--- a/java/dagger/internal/codegen/validation/BindsInstanceElementValidator.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 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 dagger.BindsInstance;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import javax.lang.model.element.Element;
-
-abstract class BindsInstanceElementValidator<E extends Element> extends BindingElementValidator<E> {
- BindsInstanceElementValidator(InjectionAnnotations injectionAnnotations) {
- super(
- BindsInstance.class,
- AllowsMultibindings.NO_MULTIBINDINGS,
- AllowsScoping.NO_SCOPING,
- injectionAnnotations);
- }
-
- @Override
- protected final String bindingElements() {
- // Even though @BindsInstance may be placed on methods, the subject of errors is the
- // parameter
- return "@BindsInstance parameters";
- }
-
- @Override
- protected final String bindingElementTypeVerb() {
- return "be";
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java b/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java
deleted file mode 100644
index 6d144bd..0000000
--- a/java/dagger/internal/codegen/validation/BindsInstanceMethodValidator.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.ComponentAnnotation.anyComponentAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-
-import com.google.auto.common.MoreElements;
-import dagger.internal.codegen.base.ModuleAnnotation;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import java.util.List;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-
-final class BindsInstanceMethodValidator extends BindsInstanceElementValidator<ExecutableElement> {
- @Inject
- BindsInstanceMethodValidator(InjectionAnnotations injectionAnnotations) {
- super(injectionAnnotations);
- }
-
- @Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends ElementValidator {
- Validator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected void checkAdditionalProperties() {
- if (!element.getModifiers().contains(ABSTRACT)) {
- report.addError("@BindsInstance methods must be abstract");
- }
- if (element.getParameters().size() != 1) {
- report.addError(
- "@BindsInstance methods should have exactly one parameter for the bound type");
- }
- TypeElement enclosingType = MoreElements.asType(element.getEnclosingElement());
- moduleAnnotation(enclosingType)
- .ifPresent(moduleAnnotation -> report.addError(didYouMeanBinds(moduleAnnotation)));
- anyComponentAnnotation(enclosingType)
- .ifPresent(
- componentAnnotation ->
- report.addError(
- String.format(
- "@BindsInstance methods should not be included in @%1$ss. "
- + "Did you mean to put it in a @%1$s.Builder?",
- componentAnnotation.simpleName())));
- }
-
- @Override
- protected Optional<TypeMirror> bindingElementType() {
- List<? extends VariableElement> parameters =
- MoreElements.asExecutable(element).getParameters();
- return parameters.size() == 1
- ? Optional.of(getOnlyElement(parameters).asType())
- : Optional.empty();
- }
- }
-
- private static String didYouMeanBinds(ModuleAnnotation moduleAnnotation) {
- return String.format(
- "@BindsInstance methods should not be included in @%ss. Did you mean @Binds?",
- moduleAnnotation.annotationName());
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java b/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java
deleted file mode 100644
index 24d65a9..0000000
--- a/java/dagger/internal/codegen/validation/BindsInstanceParameterValidator.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 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 javax.lang.model.element.ElementKind.METHOD;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.type.TypeKind.DECLARED;
-import static javax.lang.model.type.TypeKind.TYPEVAR;
-
-import com.google.auto.common.MoreElements;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-final class BindsInstanceParameterValidator extends BindsInstanceElementValidator<VariableElement> {
- @Inject
- BindsInstanceParameterValidator(InjectionAnnotations injectionAnnotations) {
- super(injectionAnnotations);
- }
-
- @Override
- protected ElementValidator elementValidator(VariableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends ElementValidator {
- Validator(VariableElement element) {
- super(element);
- }
-
- @Override
- protected void checkAdditionalProperties() {
- Element enclosing = element.getEnclosingElement();
- if (!enclosing.getKind().equals(METHOD)) {
- report.addError(
- "@BindsInstance should only be applied to methods or parameters of methods");
- return;
- }
-
- ExecutableElement method = MoreElements.asExecutable(enclosing);
- if (!method.getModifiers().contains(ABSTRACT)) {
- report.addError("@BindsInstance parameters may only be used in abstract methods");
- }
-
- TypeKind returnKind = method.getReturnType().getKind();
- if (!(returnKind.equals(DECLARED) || returnKind.equals(TYPEVAR))) {
- report.addError(
- "@BindsInstance parameters may not be used in methods with a void, array or primitive "
- + "return type");
- }
- }
-
- @Override
- protected Optional<TypeMirror> bindingElementType() {
- return Optional.of(element.asType());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java b/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java
deleted file mode 100644
index 0e79b91..0000000
--- a/java/dagger/internal/codegen/validation/BindsInstanceProcessingStep.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import dagger.BindsInstance;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-
-/**
- * Processing step that validates that the {@code BindsInstance} annotation is applied to the
- * correct elements.
- */
-public final class BindsInstanceProcessingStep extends TypeCheckingProcessingStep<Element> {
- private final BindsInstanceMethodValidator methodValidator;
- private final BindsInstanceParameterValidator parameterValidator;
- private final Messager messager;
-
- @Inject
- BindsInstanceProcessingStep(
- BindsInstanceMethodValidator methodValidator,
- BindsInstanceParameterValidator parameterValidator,
- Messager messager) {
- super(element -> element);
- this.methodValidator = methodValidator;
- this.parameterValidator = parameterValidator;
- this.messager = messager;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(BindsInstance.class);
- }
-
- @Override
- protected void process(Element element, ImmutableSet<Class<? extends Annotation>> annotations) {
- switch (element.getKind()) {
- case PARAMETER:
- parameterValidator.validate(MoreElements.asVariable(element)).printMessagesTo(messager);
- break;
- case METHOD:
- methodValidator.validate(MoreElements.asExecutable(element)).printMessagesTo(messager);
- break;
- default:
- throw new AssertionError(element);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindsMethodValidator.java b/java/dagger/internal/codegen/validation/BindsMethodValidator.java
deleted file mode 100644
index 6d2dd18..0000000
--- a/java/dagger/internal/codegen/validation/BindsMethodValidator.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2016 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.validation.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
-import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.ALLOWS_SCOPING;
-import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
-import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
-import static dagger.internal.codegen.validation.TypeHierarchyValidator.validateTypeHierarchy;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.Binds;
-import dagger.Module;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.BindsTypeChecker;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.ProducerModule;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A validator for {@link Binds} methods. */
-final class BindsMethodValidator extends BindingMethodValidator {
- private final DaggerTypes types;
- private final BindsTypeChecker bindsTypeChecker;
-
- @Inject
- BindsMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
- BindsTypeChecker bindsTypeChecker,
- DependencyRequestValidator dependencyRequestValidator,
- InjectionAnnotations injectionAnnotations) {
- super(
- elements,
- types,
- kotlinMetadataUtil,
- Binds.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
- dependencyRequestValidator,
- MUST_BE_ABSTRACT,
- NO_EXCEPTIONS,
- ALLOWS_MULTIBINDINGS,
- ALLOWS_SCOPING,
- injectionAnnotations);
- this.types = types;
- this.bindsTypeChecker = bindsTypeChecker;
- }
-
- @Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected void checkParameters() {
- if (element.getParameters().size() != 1) {
- report.addError(
- bindingMethods(
- "must have exactly one parameter, whose type is assignable to the return type"));
- } else {
- super.checkParameters();
- }
- }
-
- @Override
- protected void checkParameter(VariableElement parameter) {
- super.checkParameter(parameter);
- TypeMirror leftHandSide = boxIfNecessary(element.getReturnType());
- TypeMirror rightHandSide = parameter.asType();
- ContributionType contributionType = ContributionType.fromBindingElement(element);
- if (contributionType.equals(ContributionType.SET_VALUES) && !SetType.isSet(leftHandSide)) {
- report.addError(
- "@Binds @ElementsIntoSet methods must return a Set and take a Set parameter");
- }
-
- if (!bindsTypeChecker.isAssignable(rightHandSide, leftHandSide, contributionType)) {
- // Validate the type hierarchy of both sides to make sure they're both valid.
- // If one of the types isn't valid it means we need to delay validation to the next round.
- // Note: BasicAnnotationProcessor only performs superficial validation on the referenced
- // types within the module. Thus, we're guaranteed that the types in the @Binds method are
- // valid, but it says nothing about their supertypes, which are needed for isAssignable.
- validateTypeHierarchy(leftHandSide, types);
- validateTypeHierarchy(rightHandSide, types);
- // TODO(ronshapiro): clarify this error message for @ElementsIntoSet cases, where the
- // right-hand-side might not be assignable to the left-hand-side, but still compatible with
- // Set.addAll(Collection<? extends E>)
- report.addError("@Binds methods' parameter type must be assignable to the return type");
- }
- }
-
- private TypeMirror boxIfNecessary(TypeMirror maybePrimitive) {
- if (maybePrimitive.getKind().isPrimitive()) {
- return types.boxedClass(MoreTypes.asPrimitiveType(maybePrimitive)).asType();
- }
- return maybePrimitive;
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java b/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java
deleted file mode 100644
index cb776e1..0000000
--- a/java/dagger/internal/codegen/validation/BindsOptionalOfMethodValidator.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 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 com.google.auto.common.MoreTypes.asTypeElement;
-import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
-import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
-import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS;
-import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING;
-import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
-import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.BindsOptionalOf;
-import dagger.Module;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.ProducerModule;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A validator for {@link BindsOptionalOf} methods. */
-final class BindsOptionalOfMethodValidator extends BindingMethodValidator {
-
- private final DaggerTypes types;
- private final InjectionAnnotations injectionAnnotations;
-
- @Inject
- BindsOptionalOfMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
- DependencyRequestValidator dependencyRequestValidator,
- InjectionAnnotations injectionAnnotations) {
- super(
- elements,
- types,
- kotlinMetadataUtil,
- BindsOptionalOf.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
- dependencyRequestValidator,
- MUST_BE_ABSTRACT,
- NO_EXCEPTIONS,
- NO_MULTIBINDINGS,
- NO_SCOPING,
- injectionAnnotations);
- this.types = types;
- this.injectionAnnotations = injectionAnnotations;
- }
-
-
- @Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected void checkKeyType(TypeMirror keyType) {
- super.checkKeyType(keyType);
- if (isValidImplicitProvisionKey(
- injectionAnnotations.getQualifiers(element).stream().findFirst(), keyType, types)
- && !injectedConstructors(asTypeElement(keyType)).isEmpty()) {
- report.addError(
- "@BindsOptionalOf methods cannot return unqualified types that have an @Inject-"
- + "annotated constructor because those are always present");
- }
- }
-
- @Override
- protected void checkParameters() {
- if (!element.getParameters().isEmpty()) {
- report.addError("@BindsOptionalOf methods cannot have parameters");
- }
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java b/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java
deleted file mode 100644
index a6d9a3f..0000000
--- a/java/dagger/internal/codegen/validation/ComponentCreatorValidator.java
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.validation;
-
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
-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 static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ObjectArrays;
-import dagger.BindsInstance;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
-import dagger.internal.codegen.binding.ErrorMessages;
-import dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-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.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-
-/** Validates types annotated with component creator annotations. */
-@Singleton
-public final class ComponentCreatorValidator implements ClearableCache {
-
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final Map<TypeElement, ValidationReport<TypeElement>> reports = new HashMap<>();
-
- @Inject
- ComponentCreatorValidator(DaggerElements elements, DaggerTypes types) {
- this.elements = elements;
- this.types = types;
- }
-
- @Override
- public void clearCache() {
- reports.clear();
- }
-
- /** Validates that the given {@code type} is potentially a valid component creator type. */
- public ValidationReport<TypeElement> validate(TypeElement type) {
- return reentrantComputeIfAbsent(reports, type, this::validateUncached);
- }
-
- private ValidationReport<TypeElement> validateUncached(TypeElement type) {
- ValidationReport.Builder<TypeElement> report = ValidationReport.about(type);
-
- ImmutableSet<ComponentCreatorAnnotation> creatorAnnotations = getCreatorAnnotations(type);
- if (!validateOnlyOneCreatorAnnotation(creatorAnnotations, report)) {
- return report.build();
- }
-
- // Note: there's more validation in ComponentDescriptorValidator:
- // - to make sure the setter methods/factory parameters mirror the deps
- // - to make sure each type or key is set by only one method or parameter
- ElementValidator validator =
- new ElementValidator(type, report, getOnlyElement(creatorAnnotations));
- return validator.validate();
- }
-
- private boolean validateOnlyOneCreatorAnnotation(
- ImmutableSet<ComponentCreatorAnnotation> creatorAnnotations,
- ValidationReport.Builder<?> report) {
- // creatorAnnotations should never be empty because this should only ever be called for
- // types that have been found to have some creator annotation
- if (creatorAnnotations.size() > 1) {
- String error =
- "May not have more than one component Factory or Builder annotation on a type"
- + ": found "
- + creatorAnnotations;
- report.addError(error);
- return false;
- }
-
- return true;
- }
-
- /**
- * Validator for a single {@link TypeElement} that is annotated with a {@code Builder} or {@code
- * Factory} annotation.
- */
- private final class ElementValidator {
- private final TypeElement type;
- private final Element component;
- private final ValidationReport.Builder<TypeElement> report;
- private final ComponentCreatorAnnotation annotation;
- private final ComponentCreatorMessages messages;
-
- private ElementValidator(
- TypeElement type,
- ValidationReport.Builder<TypeElement> report,
- ComponentCreatorAnnotation annotation) {
- this.type = type;
- this.component = type.getEnclosingElement();
- this.report = report;
- this.annotation = annotation;
- this.messages = ErrorMessages.creatorMessagesFor(annotation);
- }
-
- /** Validates the creator type. */
- final ValidationReport<TypeElement> validate() {
- if (!isAnnotationPresent(component, annotation.componentAnnotation())) {
- report.addError(messages.mustBeInComponent());
- }
-
- // If the type isn't a class or interface, don't validate anything else since the rest of the
- // messages will be bogus.
- if (!validateIsClassOrInterface()) {
- return report.build();
- }
-
- validateTypeRequirements();
- switch (annotation.creatorKind()) {
- case FACTORY:
- validateFactory();
- break;
- case BUILDER:
- validateBuilder();
- }
-
- return report.build();
- }
-
- /** Validates that the type is a class or interface type and returns true if it is. */
- private boolean validateIsClassOrInterface() {
- switch (type.getKind()) {
- case CLASS:
- validateConstructor();
- return true;
- case INTERFACE:
- return true;
- default:
- report.addError(messages.mustBeClassOrInterface());
- }
- return false;
- }
-
- private void validateConstructor() {
- List<? extends Element> allElements = type.getEnclosedElements();
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(allElements);
-
- boolean valid = true;
- if (constructors.size() != 1) {
- valid = false;
- } else {
- ExecutableElement constructor = getOnlyElement(constructors);
- valid =
- constructor.getParameters().isEmpty() && !constructor.getModifiers().contains(PRIVATE);
- }
-
- if (!valid) {
- report.addError(messages.invalidConstructor());
- }
- }
-
- /** Validates basic requirements about the type that are common to both creator kinds. */
- private void validateTypeRequirements() {
- if (!type.getTypeParameters().isEmpty()) {
- report.addError(messages.generics());
- }
-
- Set<Modifier> modifiers = type.getModifiers();
- if (modifiers.contains(PRIVATE)) {
- report.addError(messages.isPrivate());
- }
- if (!modifiers.contains(STATIC)) {
- report.addError(messages.mustBeStatic());
- }
- // Note: Must be abstract, so no need to check for final.
- if (!modifiers.contains(ABSTRACT)) {
- report.addError(messages.mustBeAbstract());
- }
- }
-
- private void validateBuilder() {
- ExecutableElement buildMethod = null;
- for (ExecutableElement method : elements.getUnimplementedMethods(type)) {
- switch (method.getParameters().size()) {
- case 0: // If this is potentially a build() method, validate it returns the correct type.
- if (validateFactoryMethodReturnType(method)) {
- if (buildMethod != null) {
- // If we found more than one build-like method, fail.
- error(
- method,
- messages.twoFactoryMethods(),
- messages.inheritedTwoFactoryMethods(),
- buildMethod);
- }
- }
- // We set the buildMethod regardless of the return type to reduce error spam.
- buildMethod = method;
- break;
-
- case 1: // If this correctly had one parameter, make sure the return types are valid.
- validateSetterMethod(method);
- break;
-
- default: // more than one parameter
- error(
- method,
- messages.setterMethodsMustTakeOneArg(),
- messages.inheritedSetterMethodsMustTakeOneArg());
- break;
- }
- }
-
- if (buildMethod == null) {
- report.addError(messages.missingFactoryMethod());
- } else {
- validateNotGeneric(buildMethod);
- }
- }
-
- private void validateSetterMethod(ExecutableElement method) {
- TypeMirror returnType = types.resolveExecutableType(method, type.asType()).getReturnType();
- if (returnType.getKind() != TypeKind.VOID && !types.isSubtype(type.asType(), returnType)) {
- error(
- method,
- messages.setterMethodsMustReturnVoidOrBuilder(),
- messages.inheritedSetterMethodsMustReturnVoidOrBuilder());
- }
-
- validateNotGeneric(method);
-
- VariableElement parameter = method.getParameters().get(0);
-
- boolean methodIsBindsInstance = isAnnotationPresent(method, BindsInstance.class);
- boolean parameterIsBindsInstance = isAnnotationPresent(parameter, BindsInstance.class);
- boolean bindsInstance = methodIsBindsInstance || parameterIsBindsInstance;
-
- if (methodIsBindsInstance && parameterIsBindsInstance) {
- error(
- method,
- messages.bindsInstanceNotAllowedOnBothSetterMethodAndParameter(),
- messages.inheritedBindsInstanceNotAllowedOnBothSetterMethodAndParameter());
- }
-
- if (!bindsInstance && parameter.asType().getKind().isPrimitive()) {
- error(
- method,
- messages.nonBindsInstanceParametersMayNotBePrimitives(),
- messages.inheritedNonBindsInstanceParametersMayNotBePrimitives());
- }
- }
-
- private void validateFactory() {
- ImmutableList<ExecutableElement> abstractMethods =
- elements.getUnimplementedMethods(type).asList();
- switch (abstractMethods.size()) {
- case 0:
- report.addError(messages.missingFactoryMethod());
- return;
- case 1:
- break; // good
- default:
- error(
- abstractMethods.get(1),
- messages.twoFactoryMethods(),
- messages.inheritedTwoFactoryMethods(),
- abstractMethods.get(0));
- return;
- }
-
- validateFactoryMethod(getOnlyElement(abstractMethods));
- }
-
- /** Validates that the given {@code method} is a valid component factory method. */
- private void validateFactoryMethod(ExecutableElement method) {
- validateNotGeneric(method);
-
- if (!validateFactoryMethodReturnType(method)) {
- // If we can't determine that the single method is a valid factory method, don't bother
- // validating its parameters.
- return;
- }
-
- for (VariableElement parameter : method.getParameters()) {
- if (!isAnnotationPresent(parameter, BindsInstance.class)
- && parameter.asType().getKind().isPrimitive()) {
- error(
- method,
- messages.nonBindsInstanceParametersMayNotBePrimitives(),
- messages.inheritedNonBindsInstanceParametersMayNotBePrimitives());
- }
- }
- }
-
- /**
- * Validates that the factory method that actually returns a new component instance. Returns
- * true if the return type was valid.
- */
- private boolean validateFactoryMethodReturnType(ExecutableElement method) {
- TypeMirror returnType = types.resolveExecutableType(method, type.asType()).getReturnType();
-
- if (!types.isSubtype(component.asType(), returnType)) {
- error(
- method,
- messages.factoryMethodMustReturnComponentType(),
- messages.inheritedFactoryMethodMustReturnComponentType());
- return false;
- }
-
- if (isAnnotationPresent(method, BindsInstance.class)) {
- error(
- method,
- messages.factoryMethodMayNotBeAnnotatedWithBindsInstance(),
- messages.inheritedFactoryMethodMayNotBeAnnotatedWithBindsInstance());
- return false;
- }
-
- TypeElement componentType = MoreElements.asType(component);
- if (!types.isSameType(componentType.asType(), returnType)) {
- ImmutableSet<ExecutableElement> methodsOnlyInComponent =
- methodsOnlyInComponent(componentType);
- if (!methodsOnlyInComponent.isEmpty()) {
- report.addWarning(
- messages.factoryMethodReturnsSupertypeWithMissingMethods(
- componentType, type, returnType, method, methodsOnlyInComponent),
- method);
- }
- }
- return true;
- }
-
- /**
- * Generates one of two error messages. If the method is enclosed in the subject, we target the
- * error to the method itself. Otherwise we target the error to the subject and list the method
- * as an argument. (Otherwise we have no way of knowing if the method is being compiled in this
- * pass too, so javac might not be able to pinpoint it's line of code.)
- */
- /*
- * For Component.Builder, the prototypical example would be if someone had:
- * libfoo: interface SharedBuilder { void badSetter(A a, B b); }
- * libbar: BarComponent { BarBuilder extends SharedBuilder } }
- * ... the compiler only validates BarBuilder when compiling libbar, but it fails because
- * of libfoo's SharedBuilder (which could have been compiled in a previous pass).
- * So we can't point to SharedBuilder#badSetter as the subject of the BarBuilder validation
- * failure.
- *
- * This check is a little more strict than necessary -- ideally we'd check if method's enclosing
- * class was included in this compile run. But that's hard, and this is close enough.
- */
- private void error(
- ExecutableElement method,
- String enclosedError,
- String inheritedError,
- Object... extraArgs) {
- if (method.getEnclosingElement().equals(type)) {
- report.addError(String.format(enclosedError, extraArgs), method);
- } else {
- report.addError(String.format(inheritedError, ObjectArrays.concat(extraArgs, method)));
- }
- }
-
- /** Validates that the given {@code method} is not generic. * */
- private void validateNotGeneric(ExecutableElement method) {
- if (!method.getTypeParameters().isEmpty()) {
- error(
- method,
- messages.methodsMayNotHaveTypeParameters(),
- messages.inheritedMethodsMayNotHaveTypeParameters());
- }
- }
-
- /**
- * Returns all methods defind in {@code componentType} which are not inherited from a supertype.
- */
- private ImmutableSet<ExecutableElement> methodsOnlyInComponent(TypeElement componentType) {
- // TODO(ronshapiro): Ideally this shouldn't return methods which are redeclared from a
- // supertype, but do not change the return type. We don't have a good/simple way of checking
- // that, and it doesn't seem likely, so the warning won't be too bad.
- return ImmutableSet.copyOf(methodsIn(componentType.getEnclosedElements()));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java b/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
deleted file mode 100644
index aa20232..0000000
--- a/java/dagger/internal/codegen/validation/ComponentDescriptorValidator.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Predicates.in;
-import static com.google.common.collect.Collections2.transform;
-import static dagger.internal.codegen.base.ComponentAnnotation.rootComponentAnnotation;
-import static dagger.internal.codegen.base.DiagnosticFormatting.stripCommonTypePrefixes;
-import static dagger.internal.codegen.base.Formatter.INDENT;
-import static dagger.internal.codegen.base.Scopes.getReadableSource;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
-import static dagger.internal.codegen.base.Scopes.singletonScope;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSetMultimap;
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.Sets;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ComponentRequirement.NullPolicy;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.ErrorMessages;
-import dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages;
-import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.binding.ModuleDescriptor;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.compileroption.ValidationType;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Scope;
-import java.util.ArrayDeque;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.StringJoiner;
-import javax.inject.Inject;
-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.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-import javax.tools.Diagnostic;
-
-/**
- * Reports errors in the component hierarchy.
- *
- * <ul>
- * <li>Validates scope hierarchy of component dependencies and subcomponents.
- * <li>Reports errors if there are component dependency cycles.
- * <li>Reports errors if any abstract modules have non-abstract instance binding methods.
- * <li>Validates component creator types.
- * </ul>
- */
-// TODO(dpb): Combine with ComponentHierarchyValidator.
-public final class ComponentDescriptorValidator {
-
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final CompilerOptions compilerOptions;
- private final MethodSignatureFormatter methodSignatureFormatter;
- private final ComponentHierarchyValidator componentHierarchyValidator;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- ComponentDescriptorValidator(
- DaggerElements elements,
- DaggerTypes types,
- CompilerOptions compilerOptions,
- MethodSignatureFormatter methodSignatureFormatter,
- ComponentHierarchyValidator componentHierarchyValidator,
- KotlinMetadataUtil metadataUtil) {
- this.elements = elements;
- this.types = types;
- this.compilerOptions = compilerOptions;
- this.methodSignatureFormatter = methodSignatureFormatter;
- this.componentHierarchyValidator = componentHierarchyValidator;
- this.metadataUtil = metadataUtil;
- }
-
- public ValidationReport<TypeElement> validate(ComponentDescriptor component) {
- ComponentValidation validation = new ComponentValidation(component);
- validation.visitComponent(component);
- validation.report(component).addSubreport(componentHierarchyValidator.validate(component));
- return validation.buildReport();
- }
-
- private final class ComponentValidation {
- final ComponentDescriptor rootComponent;
- final Map<ComponentDescriptor, ValidationReport.Builder<TypeElement>> reports =
- new LinkedHashMap<>();
-
- ComponentValidation(ComponentDescriptor rootComponent) {
- this.rootComponent = checkNotNull(rootComponent);
- }
-
- /** Returns a report that contains all validation messages found during traversal. */
- ValidationReport<TypeElement> buildReport() {
- ValidationReport.Builder<TypeElement> report =
- ValidationReport.about(rootComponent.typeElement());
- reports.values().forEach(subreport -> report.addSubreport(subreport.build()));
- return report.build();
- }
-
- /** Returns the report builder for a (sub)component. */
- private ValidationReport.Builder<TypeElement> report(ComponentDescriptor component) {
- return reentrantComputeIfAbsent(
- reports, component, descriptor -> ValidationReport.about(descriptor.typeElement()));
- }
-
- private void reportComponentItem(
- Diagnostic.Kind kind, ComponentDescriptor component, String message) {
- report(component)
- .addItem(message, kind, component.typeElement(), component.annotation().annotation());
- }
-
- private void reportComponentError(ComponentDescriptor component, String error) {
- reportComponentItem(ERROR, component, error);
- }
-
- void visitComponent(ComponentDescriptor component) {
- validateDependencyScopes(component);
- validateComponentDependencyHierarchy(component);
- validateModules(component);
- validateCreators(component);
- component.childComponents().forEach(this::visitComponent);
- }
-
- /** Validates that component dependencies do not form a cycle. */
- private void validateComponentDependencyHierarchy(ComponentDescriptor component) {
- validateComponentDependencyHierarchy(component, component.typeElement(), new ArrayDeque<>());
- }
-
- /** Recursive method to validate that component dependencies do not form a cycle. */
- private void validateComponentDependencyHierarchy(
- ComponentDescriptor component, TypeElement dependency, Deque<TypeElement> dependencyStack) {
- if (dependencyStack.contains(dependency)) {
- // Current component has already appeared in the component chain.
- StringBuilder message = new StringBuilder();
- message.append(component.typeElement().getQualifiedName());
- message.append(" contains a cycle in its component dependencies:\n");
- dependencyStack.push(dependency);
- appendIndentedComponentsList(message, dependencyStack);
- dependencyStack.pop();
- reportComponentItem(
- compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
- component,
- message.toString());
- } else if (compilerOptions.validateTransitiveComponentDependencies()
- // Always validate direct component dependencies referenced by this component regardless
- // of the flag value
- || dependencyStack.isEmpty()) {
- rootComponentAnnotation(dependency)
- .ifPresent(
- componentAnnotation -> {
- dependencyStack.push(dependency);
-
- for (TypeElement nextDependency : componentAnnotation.dependencies()) {
- validateComponentDependencyHierarchy(
- component, nextDependency, dependencyStack);
- }
-
- dependencyStack.pop();
- });
- }
- }
-
- /**
- * Validates that among the dependencies there are no cycles within the scoping chain, and that
- * singleton components have no scoped dependencies.
- */
- private void validateDependencyScopes(ComponentDescriptor component) {
- ImmutableSet<Scope> scopes = component.scopes();
- ImmutableSet<TypeElement> scopedDependencies =
- scopedTypesIn(
- component
- .dependencies()
- .stream()
- .map(ComponentRequirement::typeElement)
- .collect(toImmutableSet()));
- if (!scopes.isEmpty()) {
- Scope singletonScope = singletonScope(elements);
- // Dagger 1.x scope compatibility requires this be suppress-able.
- if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()
- && scopes.contains(singletonScope)) {
- // Singleton is a special-case representing the longest lifetime, and therefore
- // @Singleton components may not depend on scoped components
- if (!scopedDependencies.isEmpty()) {
- StringBuilder message =
- new StringBuilder(
- "This @Singleton component cannot depend on scoped components:\n");
- appendIndentedComponentsList(message, scopedDependencies);
- reportComponentItem(
- compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
- component,
- message.toString());
- }
- } else {
- // Dagger 1.x scope compatibility requires this be suppress-able.
- if (!compilerOptions.scopeCycleValidationType().equals(ValidationType.NONE)) {
- validateDependencyScopeHierarchy(
- component, component.typeElement(), new ArrayDeque<>(), new ArrayDeque<>());
- }
- }
- } else {
- // Scopeless components may not depend on scoped components.
- if (!scopedDependencies.isEmpty()) {
- StringBuilder message =
- new StringBuilder(component.typeElement().getQualifiedName())
- .append(" (unscoped) cannot depend on scoped components:\n");
- appendIndentedComponentsList(message, scopedDependencies);
- reportComponentError(component, message.toString());
- }
- }
- }
-
- private void validateModules(ComponentDescriptor component) {
- for (ModuleDescriptor module : component.modules()) {
- if (module.moduleElement().getModifiers().contains(Modifier.ABSTRACT)) {
- for (ContributionBinding binding : module.bindings()) {
- if (binding.requiresModuleInstance()) {
- report(component).addError(abstractModuleHasInstanceBindingMethodsError(module));
- break;
- }
- }
- }
- }
- }
-
- private String abstractModuleHasInstanceBindingMethodsError(ModuleDescriptor module) {
- String methodAnnotations;
- switch (module.kind()) {
- case MODULE:
- methodAnnotations = "@Provides";
- break;
- case PRODUCER_MODULE:
- methodAnnotations = "@Provides or @Produces";
- break;
- default:
- throw new AssertionError(module.kind());
- }
- return String.format(
- "%s is abstract and has instance %s methods. Consider making the methods static or "
- + "including a non-abstract subclass of the module instead.",
- module.moduleElement(), methodAnnotations);
- }
-
- private void validateCreators(ComponentDescriptor component) {
- if (!component.creatorDescriptor().isPresent()) {
- // If no builder, nothing to validate.
- return;
- }
-
- ComponentCreatorDescriptor creator = component.creatorDescriptor().get();
- ComponentCreatorMessages messages = ErrorMessages.creatorMessagesFor(creator.annotation());
-
- // Requirements for modules and dependencies that the creator can set
- Set<ComponentRequirement> creatorModuleAndDependencyRequirements =
- creator.moduleAndDependencyRequirements();
- // Modules and dependencies the component requires
- Set<ComponentRequirement> componentModuleAndDependencyRequirements =
- component.dependenciesAndConcreteModules();
-
- // Requirements that the creator can set that don't match any requirements that the component
- // actually has.
- Set<ComponentRequirement> inapplicableRequirementsOnCreator =
- Sets.difference(
- creatorModuleAndDependencyRequirements, componentModuleAndDependencyRequirements);
-
- DeclaredType container = asDeclared(creator.typeElement().asType());
- if (!inapplicableRequirementsOnCreator.isEmpty()) {
- Collection<Element> excessElements =
- Multimaps.filterKeys(
- creator.unvalidatedRequirementElements(), in(inapplicableRequirementsOnCreator))
- .values();
- String formatted =
- excessElements.stream()
- .map(element -> formatElement(element, container))
- .collect(joining(", ", "[", "]"));
- report(component)
- .addError(String.format(messages.extraSetters(), formatted), creator.typeElement());
- }
-
- // Component requirements that the creator must be able to set
- Set<ComponentRequirement> mustBePassed =
- Sets.filter(
- componentModuleAndDependencyRequirements,
- input -> input.nullPolicy(elements, types, metadataUtil).equals(NullPolicy.THROW));
- // Component requirements that the creator must be able to set, but can't
- Set<ComponentRequirement> missingRequirements =
- Sets.difference(mustBePassed, creatorModuleAndDependencyRequirements);
-
- if (!missingRequirements.isEmpty()) {
- report(component)
- .addError(
- String.format(
- messages.missingSetters(),
- missingRequirements.stream().map(ComponentRequirement::type).collect(toList())),
- creator.typeElement());
- }
-
- // Validate that declared creator requirements (modules, dependencies) have unique types.
- ImmutableSetMultimap<Wrapper<TypeMirror>, Element> declaredRequirementsByType =
- Multimaps.filterKeys(
- creator.unvalidatedRequirementElements(),
- creatorModuleAndDependencyRequirements::contains)
- .entries().stream()
- .collect(
- toImmutableSetMultimap(entry -> entry.getKey().wrappedType(), Entry::getValue));
- declaredRequirementsByType
- .asMap()
- .forEach(
- (typeWrapper, elementsForType) -> {
- if (elementsForType.size() > 1) {
- TypeMirror type = typeWrapper.get();
- // TODO(cgdecker): Attach this error message to the factory method rather than
- // the component type if the elements are factory method parameters AND the
- // factory method is defined by the factory type itself and not by a supertype.
- report(component)
- .addError(
- String.format(
- messages.multipleSettersForModuleOrDependencyType(),
- type,
- transform(
- elementsForType, element -> formatElement(element, container))),
- creator.typeElement());
- }
- });
-
- // TODO(cgdecker): Duplicate binding validation should handle the case of multiple elements
- // that set the same bound-instance Key, but validating that here would make it fail faster
- // for subcomponents.
- }
-
- private String formatElement(Element element, DeclaredType container) {
- // TODO(cgdecker): Extract some or all of this to another class?
- // But note that it does different formatting for parameters than
- // DaggerElements.elementToString(Element).
- switch (element.getKind()) {
- case METHOD:
- return methodSignatureFormatter.format(
- MoreElements.asExecutable(element), Optional.of(container));
- case PARAMETER:
- return formatParameter(MoreElements.asVariable(element), container);
- default:
- // This method shouldn't be called with any other type of element.
- throw new AssertionError();
- }
- }
-
- private String formatParameter(VariableElement parameter, DeclaredType container) {
- // TODO(cgdecker): Possibly leave the type (and annotations?) off of the parameters here and
- // just use their names, since the type will be redundant in the context of the error message.
- StringJoiner joiner = new StringJoiner(" ");
- parameter.getAnnotationMirrors().stream().map(Object::toString).forEach(joiner::add);
- TypeMirror parameterType = resolveParameterType(parameter, container);
- return joiner
- .add(stripCommonTypePrefixes(parameterType.toString()))
- .add(parameter.getSimpleName())
- .toString();
- }
-
- private TypeMirror resolveParameterType(VariableElement parameter, DeclaredType container) {
- ExecutableElement method =
- MoreElements.asExecutable(parameter.getEnclosingElement());
- int parameterIndex = method.getParameters().indexOf(parameter);
-
- ExecutableType methodType = MoreTypes.asExecutable(types.asMemberOf(container, method));
- return methodType.getParameterTypes().get(parameterIndex);
- }
-
- /**
- * Validates that scopes do not participate in a scoping cycle - that is to say, scoped
- * components are in a hierarchical relationship terminating with Singleton.
- *
- * <p>As a side-effect, this means scoped components cannot have a dependency cycle between
- * themselves, since a component's presence within its own dependency path implies a cyclical
- * relationship between scopes. However, cycles in component dependencies are explicitly checked
- * in {@link #validateComponentDependencyHierarchy(ComponentDescriptor)}.
- */
- private void validateDependencyScopeHierarchy(
- ComponentDescriptor component,
- TypeElement dependency,
- Deque<ImmutableSet<Scope>> scopeStack,
- Deque<TypeElement> scopedDependencyStack) {
- ImmutableSet<Scope> scopes = scopesOf(dependency);
- if (stackOverlaps(scopeStack, scopes)) {
- scopedDependencyStack.push(dependency);
- // Current scope has already appeared in the component chain.
- StringBuilder message = new StringBuilder();
- message.append(component.typeElement().getQualifiedName());
- message.append(" depends on scoped components in a non-hierarchical scope ordering:\n");
- appendIndentedComponentsList(message, scopedDependencyStack);
- if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()) {
- reportComponentItem(
- compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
- component,
- message.toString());
- }
- scopedDependencyStack.pop();
- } else if (compilerOptions.validateTransitiveComponentDependencies()
- // Always validate direct component dependencies referenced by this component regardless
- // of the flag value
- || scopedDependencyStack.isEmpty()) {
- // TODO(beder): transitively check scopes of production components too.
- rootComponentAnnotation(dependency)
- .filter(componentAnnotation -> !componentAnnotation.isProduction())
- .ifPresent(
- componentAnnotation -> {
- ImmutableSet<TypeElement> scopedDependencies =
- scopedTypesIn(componentAnnotation.dependencies());
- if (!scopedDependencies.isEmpty()) {
- // empty can be ignored (base-case)
- scopeStack.push(scopes);
- scopedDependencyStack.push(dependency);
- for (TypeElement scopedDependency : scopedDependencies) {
- validateDependencyScopeHierarchy(
- component,
- scopedDependency,
- scopeStack,
- scopedDependencyStack);
- }
- scopedDependencyStack.pop();
- scopeStack.pop();
- }
- }); // else: we skip component dependencies which are not components
- }
- }
-
- private <T> boolean stackOverlaps(Deque<ImmutableSet<T>> stack, ImmutableSet<T> set) {
- for (ImmutableSet<T> entry : stack) {
- if (!Sets.intersection(entry, set).isEmpty()) {
- return true;
- }
- }
- return false;
- }
-
- /** Appends and formats a list of indented component types (with their scope annotations). */
- private void appendIndentedComponentsList(StringBuilder message, Iterable<TypeElement> types) {
- for (TypeElement scopedComponent : types) {
- message.append(INDENT);
- for (Scope scope : scopesOf(scopedComponent)) {
- message.append(getReadableSource(scope)).append(' ');
- }
- message
- .append(stripCommonTypePrefixes(scopedComponent.getQualifiedName().toString()))
- .append('\n');
- }
- }
-
- /**
- * Returns a set of type elements containing only those found in the input set that have a
- * scoping annotation.
- */
- private ImmutableSet<TypeElement> scopedTypesIn(Collection<TypeElement> types) {
- return types.stream().filter(type -> !scopesOf(type).isEmpty()).collect(toImmutableSet());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java b/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
deleted file mode 100644
index 1861636..0000000
--- a/java/dagger/internal/codegen/validation/ComponentHierarchyValidator.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.validation;
-
-import static com.google.common.base.Functions.constant;
-import static com.google.common.base.Predicates.and;
-import static com.google.common.base.Predicates.in;
-import static com.google.common.base.Predicates.not;
-import static dagger.internal.codegen.base.Scopes.getReadableSource;
-import static dagger.internal.codegen.base.Scopes.uniqueScopeOf;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ModuleDescriptor;
-import dagger.internal.codegen.binding.ModuleKind;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.model.Scope;
-import java.util.Collection;
-import java.util.Formatter;
-import java.util.Map;
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-
-/** Validates the relationships between parent components and subcomponents. */
-final class ComponentHierarchyValidator {
- private static final Joiner COMMA_SEPARATED_JOINER = Joiner.on(", ");
- private final CompilerOptions compilerOptions;
-
- @Inject
- ComponentHierarchyValidator(CompilerOptions compilerOptions) {
- this.compilerOptions = compilerOptions;
- }
-
- ValidationReport<TypeElement> validate(ComponentDescriptor componentDescriptor) {
- ValidationReport.Builder<TypeElement> report =
- ValidationReport.about(componentDescriptor.typeElement());
- validateSubcomponentMethods(
- report,
- componentDescriptor,
- Maps.toMap(componentDescriptor.moduleTypes(), constant(componentDescriptor.typeElement())));
- validateRepeatedScopedDeclarations(report, componentDescriptor, LinkedHashMultimap.create());
-
- if (compilerOptions.scopeCycleValidationType().diagnosticKind().isPresent()) {
- validateScopeHierarchy(
- report, componentDescriptor, LinkedHashMultimap.<ComponentDescriptor, Scope>create());
- }
- validateProductionModuleUniqueness(report, componentDescriptor, LinkedHashMultimap.create());
- return report.build();
- }
-
- private void validateSubcomponentMethods(
- ValidationReport.Builder<?> report,
- ComponentDescriptor componentDescriptor,
- ImmutableMap<TypeElement, TypeElement> existingModuleToOwners) {
- componentDescriptor
- .childComponentsDeclaredByFactoryMethods()
- .forEach(
- (method, childComponent) -> {
- if (childComponent.hasCreator()) {
- report.addError(
- "Components may not have factory methods for subcomponents that define a "
- + "builder.",
- method.methodElement());
- } else {
- validateFactoryMethodParameters(report, method, existingModuleToOwners);
- }
-
- validateSubcomponentMethods(
- report,
- childComponent,
- new ImmutableMap.Builder<TypeElement, TypeElement>()
- .putAll(existingModuleToOwners)
- .putAll(
- Maps.toMap(
- Sets.difference(
- childComponent.moduleTypes(), existingModuleToOwners.keySet()),
- constant(childComponent.typeElement())))
- .build());
- });
- }
-
- private void validateFactoryMethodParameters(
- ValidationReport.Builder<?> report,
- ComponentMethodDescriptor subcomponentMethodDescriptor,
- ImmutableMap<TypeElement, TypeElement> existingModuleToOwners) {
- for (VariableElement factoryMethodParameter :
- subcomponentMethodDescriptor.methodElement().getParameters()) {
- TypeElement moduleType = MoreTypes.asTypeElement(factoryMethodParameter.asType());
- TypeElement originatingComponent = existingModuleToOwners.get(moduleType);
- if (originatingComponent != null) {
- /* Factory method tries to pass a module that is already present in the parent.
- * This is an error. */
- report.addError(
- String.format(
- "%s is present in %s. A subcomponent cannot use an instance of a "
- + "module that differs from its parent.",
- moduleType.getSimpleName(), originatingComponent.getQualifiedName()),
- factoryMethodParameter);
- }
- }
- }
-
- /**
- * Checks that components do not have any scopes that are also applied on any of their ancestors.
- */
- private void validateScopeHierarchy(
- ValidationReport.Builder<TypeElement> report,
- ComponentDescriptor subject,
- SetMultimap<ComponentDescriptor, Scope> scopesByComponent) {
- scopesByComponent.putAll(subject, subject.scopes());
-
- for (ComponentDescriptor childComponent : subject.childComponents()) {
- validateScopeHierarchy(report, childComponent, scopesByComponent);
- }
-
- scopesByComponent.removeAll(subject);
-
- Predicate<Scope> subjectScopes =
- subject.isProduction()
- // TODO(beder): validate that @ProductionScope is only applied on production components
- ? and(in(subject.scopes()), not(Scope::isProductionScope))
- : in(subject.scopes());
- SetMultimap<ComponentDescriptor, Scope> overlappingScopes =
- Multimaps.filterValues(scopesByComponent, subjectScopes);
- if (!overlappingScopes.isEmpty()) {
- StringBuilder error =
- new StringBuilder()
- .append(subject.typeElement().getQualifiedName())
- .append(" has conflicting scopes:");
- for (Map.Entry<ComponentDescriptor, Scope> entry : overlappingScopes.entries()) {
- Scope scope = entry.getValue();
- error
- .append("\n ")
- .append(entry.getKey().typeElement().getQualifiedName())
- .append(" also has ")
- .append(getReadableSource(scope));
- }
- report.addItem(
- error.toString(),
- compilerOptions.scopeCycleValidationType().diagnosticKind().get(),
- subject.typeElement());
- }
- }
-
- private void validateProductionModuleUniqueness(
- ValidationReport.Builder<TypeElement> report,
- ComponentDescriptor componentDescriptor,
- SetMultimap<ComponentDescriptor, ModuleDescriptor> producerModulesByComponent) {
- ImmutableSet<ModuleDescriptor> producerModules =
- componentDescriptor.modules().stream()
- .filter(module -> module.kind().equals(ModuleKind.PRODUCER_MODULE))
- .collect(toImmutableSet());
-
- producerModulesByComponent.putAll(componentDescriptor, producerModules);
- for (ComponentDescriptor childComponent : componentDescriptor.childComponents()) {
- validateProductionModuleUniqueness(report, childComponent, producerModulesByComponent);
- }
- producerModulesByComponent.removeAll(componentDescriptor);
-
-
- SetMultimap<ComponentDescriptor, ModuleDescriptor> repeatedModules =
- Multimaps.filterValues(producerModulesByComponent, producerModules::contains);
- if (repeatedModules.isEmpty()) {
- return;
- }
-
- StringBuilder error = new StringBuilder();
- Formatter formatter = new Formatter(error);
-
- formatter.format("%s repeats @ProducerModules:", componentDescriptor.typeElement());
-
- for (Map.Entry<ComponentDescriptor, Collection<ModuleDescriptor>> entry :
- repeatedModules.asMap().entrySet()) {
- formatter.format("\n %s also installs: ", entry.getKey().typeElement());
- COMMA_SEPARATED_JOINER
- .appendTo(error, Iterables.transform(entry.getValue(), m -> m.moduleElement()));
- }
-
- report.addError(error.toString());
- }
-
- private void validateRepeatedScopedDeclarations(
- ValidationReport.Builder<TypeElement> report,
- ComponentDescriptor component,
- // TODO(ronshapiro): optimize ModuleDescriptor.hashCode()/equals. Otherwise this could be
- // quite costly
- SetMultimap<ComponentDescriptor, ModuleDescriptor> modulesWithScopes) {
- ImmutableSet<ModuleDescriptor> modules =
- component.modules().stream().filter(this::hasScopedDeclarations).collect(toImmutableSet());
- modulesWithScopes.putAll(component, modules);
- for (ComponentDescriptor childComponent : component.childComponents()) {
- validateRepeatedScopedDeclarations(report, childComponent, modulesWithScopes);
- }
- modulesWithScopes.removeAll(component);
-
- SetMultimap<ComponentDescriptor, ModuleDescriptor> repeatedModules =
- Multimaps.filterValues(modulesWithScopes, modules::contains);
- if (repeatedModules.isEmpty()) {
- return;
- }
-
- report.addError(
- repeatedModulesWithScopeError(component, ImmutableSetMultimap.copyOf(repeatedModules)));
- }
-
- private boolean hasScopedDeclarations(ModuleDescriptor module) {
- return !moduleScopes(module).isEmpty();
- }
-
- private String repeatedModulesWithScopeError(
- ComponentDescriptor component,
- ImmutableSetMultimap<ComponentDescriptor, ModuleDescriptor> repeatedModules) {
- StringBuilder error =
- new StringBuilder()
- .append(component.typeElement().getQualifiedName())
- .append(" repeats modules with scoped bindings or declarations:");
-
- repeatedModules
- .asMap()
- .forEach(
- (conflictingComponent, conflictingModules) -> {
- error
- .append("\n - ")
- .append(conflictingComponent.typeElement().getQualifiedName())
- .append(" also includes:");
- for (ModuleDescriptor conflictingModule : conflictingModules) {
- error
- .append("\n - ")
- .append(conflictingModule.moduleElement().getQualifiedName())
- .append(" with scopes: ")
- .append(COMMA_SEPARATED_JOINER.join(moduleScopes(conflictingModule)));
- }
- });
- return error.toString();
- }
-
- private ImmutableSet<Scope> moduleScopes(ModuleDescriptor module) {
- return FluentIterable.concat(module.allBindingDeclarations())
- .transform(declaration -> uniqueScopeOf(declaration.bindingElement().get()))
- .filter(scope -> scope.isPresent() && !scope.get().isReusable())
- .transform(scope -> scope.get())
- .toSet();
- }
-}
diff --git a/java/dagger/internal/codegen/validation/ComponentValidator.java b/java/dagger/internal/codegen/validation/ComponentValidator.java
deleted file mode 100644
index b3322e5..0000000
--- a/java/dagger/internal/codegen/validation/ComponentValidator.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.auto.common.MoreTypes.asExecutable;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.google.common.collect.Multimaps.asMap;
-import static com.google.common.collect.Sets.intersection;
-import static dagger.internal.codegen.base.ComponentAnnotation.anyComponentAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.creatorAnnotationsFor;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.productionCreatorAnnotations;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.subcomponentCreatorAnnotations;
-import static dagger.internal.codegen.binding.ComponentKind.annotationsFor;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.enclosedAnnotatedTypes;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getTransitiveModules;
-import static dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages.builderMethodRequiresNoArgs;
-import static dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages.moreThanOneRefToSubcomponent;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnyAnnotation;
-import static java.util.Comparator.comparing;
-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.type.TypeKind.VOID;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
-import dagger.Component;
-import dagger.Reusable;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.base.ComponentAnnotation;
-import dagger.internal.codegen.binding.ComponentKind;
-import dagger.internal.codegen.binding.DependencyRequestFactory;
-import dagger.internal.codegen.binding.ErrorMessages;
-import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.binding.ModuleKind;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.producers.CancellationPolicy;
-import dagger.producers.ProductionComponent;
-import java.lang.annotation.Annotation;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-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.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/**
- * Performs superficial validation of the contract of the {@link Component} and {@link
- * ProductionComponent} annotations.
- */
-@Singleton
-public final class ComponentValidator implements ClearableCache {
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final ModuleValidator moduleValidator;
- private final ComponentCreatorValidator creatorValidator;
- private final DependencyRequestValidator dependencyRequestValidator;
- private final MembersInjectionValidator membersInjectionValidator;
- private final MethodSignatureFormatter methodSignatureFormatter;
- private final DependencyRequestFactory dependencyRequestFactory;
- private final Map<TypeElement, ValidationReport<TypeElement>> reports = new HashMap<>();
-
- @Inject
- ComponentValidator(
- DaggerElements elements,
- DaggerTypes types,
- ModuleValidator moduleValidator,
- ComponentCreatorValidator creatorValidator,
- DependencyRequestValidator dependencyRequestValidator,
- MembersInjectionValidator membersInjectionValidator,
- MethodSignatureFormatter methodSignatureFormatter,
- DependencyRequestFactory dependencyRequestFactory) {
- this.elements = elements;
- this.types = types;
- this.moduleValidator = moduleValidator;
- this.creatorValidator = creatorValidator;
- this.dependencyRequestValidator = dependencyRequestValidator;
- this.membersInjectionValidator = membersInjectionValidator;
- this.methodSignatureFormatter = methodSignatureFormatter;
- this.dependencyRequestFactory = dependencyRequestFactory;
- }
-
- @Override
- public void clearCache() {
- reports.clear();
- }
-
- /** Validates the given component. */
- public ValidationReport<TypeElement> validate(TypeElement component) {
- return reentrantComputeIfAbsent(reports, component, this::validateUncached);
- }
-
- private ValidationReport<TypeElement> validateUncached(TypeElement component) {
- return new ElementValidator(component).validateElement();
- }
-
- private class ElementValidator {
- private final TypeElement component;
- private final ValidationReport.Builder<TypeElement> report;
- private final ImmutableSet<ComponentKind> componentKinds;
-
- // Populated by ComponentMethodValidators
- private final SetMultimap<Element, ExecutableElement> referencedSubcomponents =
- LinkedHashMultimap.create();
-
- ElementValidator(TypeElement component) {
- this.component = component;
- this.report = ValidationReport.about(component);
- this.componentKinds = ComponentKind.getComponentKinds(component);
- }
-
- private ComponentKind componentKind() {
- return getOnlyElement(componentKinds);
- }
-
- private ComponentAnnotation componentAnnotation() {
- return anyComponentAnnotation(component).get();
- }
-
- private DeclaredType componentType() {
- return asDeclared(component.asType());
- }
-
- ValidationReport<TypeElement> validateElement() {
- if (componentKinds.size() > 1) {
- return moreThanOneComponentAnnotation();
- }
-
- validateUseOfCancellationPolicy();
- validateIsAbstractType();
- validateCreators();
- validateNoReusableAnnotation();
- validateComponentMethods();
- validateNoConflictingEntryPoints();
- validateSubcomponentReferences();
- validateComponentDependencies();
- validateReferencedModules();
- validateSubcomponents();
-
- return report.build();
- }
-
- private ValidationReport<TypeElement> moreThanOneComponentAnnotation() {
- String error =
- "Components may not be annotated with more than one component annotation: found "
- + annotationsFor(componentKinds);
- report.addError(error, component);
- return report.build();
- }
-
- private void validateUseOfCancellationPolicy() {
- if (isAnnotationPresent(component, CancellationPolicy.class)
- && !componentKind().isProducer()) {
- report.addError(
- "@CancellationPolicy may only be applied to production components and subcomponents",
- component);
- }
- }
-
- private void validateIsAbstractType() {
- if (!component.getKind().equals(INTERFACE)
- && !(component.getKind().equals(CLASS) && component.getModifiers().contains(ABSTRACT))) {
- report.addError(
- String.format(
- "@%s may only be applied to an interface or abstract class",
- componentKind().annotation().getSimpleName()),
- component);
- }
- }
-
- private void validateCreators() {
- ImmutableList<DeclaredType> creators =
- creatorAnnotationsFor(componentAnnotation()).stream()
- .flatMap(annotation -> enclosedAnnotatedTypes(component, annotation).stream())
- .collect(toImmutableList());
- creators.forEach(
- creator -> report.addSubreport(creatorValidator.validate(asTypeElement(creator))));
- if (creators.size() > 1) {
- report.addError(
- String.format(
- ErrorMessages.componentMessagesFor(componentKind()).moreThanOne(), creators),
- component);
- }
- }
-
- private void validateNoReusableAnnotation() {
- Optional<AnnotationMirror> reusableAnnotation =
- getAnnotationMirror(component, Reusable.class);
- if (reusableAnnotation.isPresent()) {
- report.addError(
- "@Reusable cannot be applied to components or subcomponents",
- component,
- reusableAnnotation.get());
- }
- }
-
- private void validateComponentMethods() {
- getLocalAndInheritedMethods(component, types, elements).stream()
- .filter(method -> method.getModifiers().contains(ABSTRACT))
- .map(ComponentMethodValidator::new)
- .forEachOrdered(ComponentMethodValidator::validateMethod);
- }
-
- private class ComponentMethodValidator {
- private final ExecutableElement method;
- private final ExecutableType resolvedMethod;
- private final List<? extends TypeMirror> parameterTypes;
- private final List<? extends VariableElement> parameters;
- private final TypeMirror returnType;
-
- ComponentMethodValidator(ExecutableElement method) {
- this.method = method;
- this.resolvedMethod = asExecutable(types.asMemberOf(componentType(), method));
- this.parameterTypes = resolvedMethod.getParameterTypes();
- this.parameters = method.getParameters();
- this.returnType = resolvedMethod.getReturnType();
- }
-
- void validateMethod() {
- validateNoTypeVariables();
-
- // abstract methods are ones we have to implement, so they each need to be validated
- // first, check the return type. if it's a subcomponent, validate that method as
- // such.
- Optional<AnnotationMirror> subcomponentAnnotation = subcomponentAnnotation();
- if (subcomponentAnnotation.isPresent()) {
- validateSubcomponentFactoryMethod(subcomponentAnnotation.get());
- } else if (subcomponentCreatorAnnotation().isPresent()) {
- validateSubcomponentCreatorMethod();
- } else {
- // if it's not a subcomponent...
- switch (parameters.size()) {
- case 0:
- validateProvisionMethod();
- break;
- case 1:
- validateMembersInjectionMethod();
- break;
- default:
- reportInvalidMethod();
- break;
- }
- }
- }
-
- private void validateNoTypeVariables() {
- if (!resolvedMethod.getTypeVariables().isEmpty()) {
- report.addError("Component methods cannot have type variables", method);
- }
- }
-
- private Optional<AnnotationMirror> subcomponentAnnotation() {
- return checkForAnnotations(
- returnType,
- componentKind().legalSubcomponentKinds().stream()
- .map(ComponentKind::annotation)
- .collect(toImmutableSet()));
- }
-
- private Optional<AnnotationMirror> subcomponentCreatorAnnotation() {
- return checkForAnnotations(
- returnType,
- componentAnnotation().isProduction()
- ? intersection(subcomponentCreatorAnnotations(), productionCreatorAnnotations())
- : subcomponentCreatorAnnotations());
- }
-
- private void validateSubcomponentFactoryMethod(AnnotationMirror subcomponentAnnotation) {
- referencedSubcomponents.put(MoreTypes.asElement(returnType), method);
-
- ComponentKind subcomponentKind =
- ComponentKind.forAnnotatedElement(MoreTypes.asTypeElement(returnType)).get();
- ImmutableSet<TypeElement> moduleTypes =
- ComponentAnnotation.componentAnnotation(subcomponentAnnotation).modules();
-
- // TODO(gak): This logic maybe/probably shouldn't live here as it requires us to traverse
- // subcomponents and their modules separately from how it is done in ComponentDescriptor and
- // ModuleDescriptor
- @SuppressWarnings("deprecation")
- ImmutableSet<TypeElement> transitiveModules =
- getTransitiveModules(types, elements, moduleTypes);
-
- Set<TypeElement> variableTypes = Sets.newHashSet();
-
- for (int i = 0; i < parameterTypes.size(); i++) {
- VariableElement parameter = parameters.get(i);
- TypeMirror parameterType = parameterTypes.get(i);
- Optional<TypeElement> moduleType =
- parameterType.accept(
- new SimpleTypeVisitor8<Optional<TypeElement>, Void>() {
- @Override
- protected Optional<TypeElement> defaultAction(TypeMirror e, Void p) {
- return Optional.empty();
- }
-
- @Override
- public Optional<TypeElement> visitDeclared(DeclaredType t, Void p) {
- for (ModuleKind moduleKind : subcomponentKind.legalModuleKinds()) {
- if (isAnnotationPresent(t.asElement(), moduleKind.annotation())) {
- return Optional.of(MoreTypes.asTypeElement(t));
- }
- }
- return Optional.empty();
- }
- },
- null);
- if (moduleType.isPresent()) {
- if (variableTypes.contains(moduleType.get())) {
- report.addError(
- String.format(
- "A module may only occur once an an argument in a Subcomponent factory "
- + "method, but %s was already passed.",
- moduleType.get().getQualifiedName()),
- parameter);
- }
- if (!transitiveModules.contains(moduleType.get())) {
- report.addError(
- String.format(
- "%s is present as an argument to the %s factory method, but is not one of the"
- + " modules used to implement the subcomponent.",
- moduleType.get().getQualifiedName(),
- MoreTypes.asTypeElement(returnType).getQualifiedName()),
- method);
- }
- variableTypes.add(moduleType.get());
- } else {
- report.addError(
- String.format(
- "Subcomponent factory methods may only accept modules, but %s is not.",
- parameterType),
- parameter);
- }
- }
- }
-
- private void validateSubcomponentCreatorMethod() {
- referencedSubcomponents.put(MoreTypes.asElement(returnType).getEnclosingElement(), method);
-
- if (!parameters.isEmpty()) {
- report.addError(builderMethodRequiresNoArgs(), method);
- }
-
- TypeElement creatorElement = MoreTypes.asTypeElement(returnType);
- // TODO(sameb): The creator validator right now assumes the element is being compiled
- // in this pass, which isn't true here. We should change error messages to spit out
- // this method as the subject and add the original subject to the message output.
- report.addSubreport(creatorValidator.validate(creatorElement));
- }
-
- private void validateProvisionMethod() {
- dependencyRequestValidator.validateDependencyRequest(report, method, returnType);
- }
-
- private void validateMembersInjectionMethod() {
- TypeMirror parameterType = getOnlyElement(parameterTypes);
- report.addSubreport(
- membersInjectionValidator.validateMembersInjectionMethod(method, parameterType));
- if (!(returnType.getKind().equals(VOID) || types.isSameType(returnType, parameterType))) {
- report.addError(
- "Members injection methods may only return the injected type or void.", method);
- }
- }
-
- private void reportInvalidMethod() {
- report.addError(
- "This method isn't a valid provision method, members injection method or "
- + "subcomponent factory method. Dagger cannot implement this method",
- method);
- }
- }
-
- private void validateNoConflictingEntryPoints() {
- // Collect entry point methods that are not overridden by others. If the "same" method is
- // inherited from more than one supertype, each will be in the multimap.
- SetMultimap<String, ExecutableElement> entryPointMethods = HashMultimap.create();
-
- methodsIn(elements.getAllMembers(component)).stream()
- .filter(
- method ->
- isEntryPoint(method, asExecutable(types.asMemberOf(componentType(), method))))
- .forEach(
- method ->
- addMethodUnlessOverridden(
- method, entryPointMethods.get(method.getSimpleName().toString())));
-
- for (Set<ExecutableElement> methods : asMap(entryPointMethods).values()) {
- if (distinctKeys(methods).size() > 1) {
- reportConflictingEntryPoints(methods);
- }
- }
- }
-
- private void reportConflictingEntryPoints(Collection<ExecutableElement> methods) {
- verify(
- methods.stream().map(ExecutableElement::getEnclosingElement).distinct().count()
- == methods.size(),
- "expected each method to be declared on a different type: %s",
- methods);
- StringBuilder message = new StringBuilder("conflicting entry point declarations:");
- methodSignatureFormatter
- .typedFormatter(componentType())
- .formatIndentedList(
- message,
- ImmutableList.sortedCopyOf(
- comparing(
- method -> asType(method.getEnclosingElement()).getQualifiedName().toString()),
- methods),
- 1);
- report.addError(message.toString());
- }
-
- private void validateSubcomponentReferences() {
- Maps.filterValues(referencedSubcomponents.asMap(), methods -> methods.size() > 1)
- .forEach(
- (subcomponent, methods) ->
- report.addError(
- String.format(moreThanOneRefToSubcomponent(), subcomponent, methods),
- component));
- }
-
- private void validateComponentDependencies() {
- for (TypeMirror type : componentAnnotation().dependencyTypes()) {
- type.accept(CHECK_DEPENDENCY_TYPES, report);
- }
- }
-
- private void validateReferencedModules() {
- report.addSubreport(
- moduleValidator.validateReferencedModules(
- component,
- componentAnnotation().annotation(),
- componentKind().legalModuleKinds(),
- new HashSet<>()));
- }
-
- private void validateSubcomponents() {
- // Make sure we validate any subcomponents we're referencing.
- for (Element subcomponent : referencedSubcomponents.keySet()) {
- ValidationReport<TypeElement> subreport = validate(asType(subcomponent));
- report.addSubreport(subreport);
- }
- }
-
- private ImmutableSet<Key> distinctKeys(Set<ExecutableElement> methods) {
- return methods.stream()
- .map(this::dependencyRequest)
- .map(DependencyRequest::key)
- .collect(toImmutableSet());
- }
-
- private DependencyRequest dependencyRequest(ExecutableElement method) {
- ExecutableType methodType = asExecutable(types.asMemberOf(componentType(), method));
- return ComponentKind.forAnnotatedElement(component).get().isProducer()
- ? dependencyRequestFactory.forComponentProductionMethod(method, methodType)
- : dependencyRequestFactory.forComponentProvisionMethod(method, methodType);
- }
- }
-
- private static boolean isEntryPoint(ExecutableElement method, ExecutableType methodType) {
- return method.getModifiers().contains(ABSTRACT)
- && method.getParameters().isEmpty()
- && !methodType.getReturnType().getKind().equals(VOID)
- && methodType.getTypeVariables().isEmpty();
- }
-
- private void addMethodUnlessOverridden(ExecutableElement method, Set<ExecutableElement> methods) {
- if (methods.stream().noneMatch(existingMethod -> overridesAsDeclared(existingMethod, method))) {
- methods.removeIf(existingMethod -> overridesAsDeclared(method, existingMethod));
- methods.add(method);
- }
- }
-
- /**
- * Returns {@code true} if {@code overrider} overrides {@code overridden} considered from within
- * the type that declares {@code overrider}.
- */
- // TODO(dpb): Does this break for ECJ?
- private boolean overridesAsDeclared(ExecutableElement overrider, ExecutableElement overridden) {
- return elements.overrides(overrider, overridden, asType(overrider.getEnclosingElement()));
- }
-
- private static final TypeVisitor<Void, ValidationReport.Builder<?>> CHECK_DEPENDENCY_TYPES =
- new SimpleTypeVisitor8<Void, ValidationReport.Builder<?>>() {
- @Override
- protected Void defaultAction(TypeMirror type, ValidationReport.Builder<?> report) {
- report.addError(type + " is not a valid component dependency type");
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType type, ValidationReport.Builder<?> report) {
- if (moduleAnnotation(MoreTypes.asTypeElement(type)).isPresent()) {
- report.addError(type + " is a module, which cannot be a component dependency");
- }
- return null;
- }
- };
-
- private static Optional<AnnotationMirror> checkForAnnotations(
- TypeMirror type, final Set<? extends Class<? extends Annotation>> annotations) {
- return type.accept(
- new SimpleTypeVisitor8<Optional<AnnotationMirror>, Void>(Optional.empty()) {
- @Override
- public Optional<AnnotationMirror> visitDeclared(DeclaredType t, Void p) {
- return getAnyAnnotation(t.asElement(), annotations);
- }
- },
- null);
- }
-}
diff --git a/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java b/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java
deleted file mode 100644
index a9c650a..0000000
--- a/java/dagger/internal/codegen/validation/CompositeBindingGraphPlugin.java
+++ /dev/null
@@ -1,284 +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.internal.codegen.validation;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Lists.asList;
-import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.elementEncloses;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.util.Elements; // ALLOW_TYPES_ELEMENTS because of interface dependencies
-import javax.lang.model.util.Types; // ALLOW_TYPES_ELEMENTS because of interface dependencies
-import javax.tools.Diagnostic;
-
-/**
- * Combines many {@link BindingGraphPlugin} implementations. This helps reduce spam by combining
- * all of the messages that are reported on the root component.
- */
-public final class CompositeBindingGraphPlugin implements BindingGraphPlugin {
-
- private final ImmutableSet<BindingGraphPlugin> plugins;
- private final String pluginName;
- private final DiagnosticMessageGenerator.Factory messageGeneratorFactory;
-
- /** Factory class for {@link CompositeBindingGraphPlugin}. */
- public static final class Factory {
- private final DiagnosticMessageGenerator.Factory messageGeneratorFactory;
-
- @Inject Factory(DiagnosticMessageGenerator.Factory messageGeneratorFactory) {
- this.messageGeneratorFactory = messageGeneratorFactory;
- }
-
- public CompositeBindingGraphPlugin create(
- ImmutableSet<BindingGraphPlugin> plugins, String pluginName) {
- return new CompositeBindingGraphPlugin(plugins, pluginName, messageGeneratorFactory);
- }
- }
-
- private CompositeBindingGraphPlugin(
- ImmutableSet<BindingGraphPlugin> plugins,
- String pluginName,
- DiagnosticMessageGenerator.Factory messageGeneratorFactory) {
- this.plugins = plugins;
- this.pluginName = pluginName;
- this.messageGeneratorFactory = messageGeneratorFactory;
- }
-
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- AggregatingDiagnosticReporter aggregatingDiagnosticReporter = new AggregatingDiagnosticReporter(
- bindingGraph, diagnosticReporter, messageGeneratorFactory.create(bindingGraph));
- plugins.forEach(plugin -> {
- aggregatingDiagnosticReporter.setCurrentPlugin(plugin.pluginName());
- plugin.visitGraph(bindingGraph, aggregatingDiagnosticReporter);
- });
- aggregatingDiagnosticReporter.report();
- }
-
- @Override
- public void initFiler(Filer filer) {
- plugins.forEach(plugin -> plugin.initFiler(filer));
- }
-
- @Override
- public void initTypes(Types types) {
- plugins.forEach(plugin -> plugin.initTypes(types));
- }
-
- @Override
- public void initElements(Elements elements) {
- plugins.forEach(plugin -> plugin.initElements(elements));
- }
-
- @Override
- public void initOptions(Map<String, String> options) {
- plugins.forEach(plugin -> plugin.initOptions(options));
- }
-
- @Override
- public Set<String> supportedOptions() {
- return plugins.stream().flatMap(
- plugin -> plugin.supportedOptions().stream()).collect(toImmutableSet());
- }
-
- @Override
- public String pluginName() {
- return pluginName;
- }
-
- // TODO(erichang): This kind of breaks some of the encapsulation by relying on or repeating
- // logic within DiagnosticReporterImpl. Hopefully if the experiment for aggregated messages
- // goes well though this can be merged with that implementation.
- private static final class AggregatingDiagnosticReporter implements DiagnosticReporter {
- private final DiagnosticReporter delegate;
- private final BindingGraph graph;
- // Initialize with a new line so the first message appears below the reported component
- private final StringBuilder messageBuilder = new StringBuilder("\n");
- private final DiagnosticMessageGenerator messageGenerator;
- private Optional<Diagnostic.Kind> mergedDiagnosticKind = Optional.empty();
- private String currentPluginName = null;
-
- AggregatingDiagnosticReporter(
- BindingGraph graph,
- DiagnosticReporter delegate,
- DiagnosticMessageGenerator messageGenerator) {
- this.graph = graph;
- this.delegate = delegate;
- this.messageGenerator = messageGenerator;
- }
-
- /** Sets the currently running aggregated plugin. Used to add a diagnostic prefix. */
- void setCurrentPlugin(String pluginName) {
- currentPluginName = pluginName;
- }
-
- /** Reports all of the stored diagnostics. */
- void report() {
- if (mergedDiagnosticKind.isPresent()) {
- delegate.reportComponent(
- mergedDiagnosticKind.get(),
- graph.rootComponentNode(),
- PackageNameCompressor.compressPackagesInMessage(messageBuilder.toString()));
- }
- }
-
- @Override
- public void reportComponent(Diagnostic.Kind diagnosticKind, ComponentNode componentNode,
- String message) {
- addMessage(diagnosticKind, message);
- messageGenerator.appendComponentPathUnlessAtRoot(messageBuilder, componentNode);
- }
-
- @Override
- @FormatMethod
- public void reportComponent(
- Diagnostic.Kind diagnosticKind,
- ComponentNode componentNode,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportComponent(
- diagnosticKind, componentNode, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- @Override
- public void reportBinding(Diagnostic.Kind diagnosticKind, MaybeBinding binding,
- String message) {
- addMessage(diagnosticKind,
- String.format("%s%s", message, messageGenerator.getMessage(binding)));
- }
-
- @Override
- @FormatMethod
- public void reportBinding(
- Diagnostic.Kind diagnosticKind,
- MaybeBinding binding,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportBinding(diagnosticKind, binding, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- @Override
- public void reportDependency(
- Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
- addMessage(diagnosticKind,
- String.format("%s%s", message, messageGenerator.getMessage(dependencyEdge)));
- }
-
- @Override
- @FormatMethod
- public void reportDependency(
- Diagnostic.Kind diagnosticKind,
- DependencyEdge dependencyEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportDependency(
- diagnosticKind, dependencyEdge, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- @Override
- public void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String message) {
- // TODO(erichang): This repeats some of the logic in DiagnosticReporterImpl. Remove when
- // merged.
- if (elementEncloses(
- graph.rootComponentNode().componentPath().currentComponent(),
- childFactoryMethodEdge.factoryMethod())) {
- // Let this pass through since it is not an error reported on the root component
- delegate.reportSubcomponentFactoryMethod(diagnosticKind, childFactoryMethodEdge, message);
- } else {
- addMessage(
- diagnosticKind,
- String.format(
- "[%s] %s", elementToString(childFactoryMethodEdge.factoryMethod()), message));
- }
- }
-
- @Override
- @FormatMethod
- public void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportSubcomponentFactoryMethod(
- diagnosticKind, childFactoryMethodEdge, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- /** Adds a message to the stored aggregated message. */
- private void addMessage(Diagnostic.Kind diagnosticKind, String message) {
- checkNotNull(diagnosticKind);
- checkNotNull(message);
- checkState(currentPluginName != null);
-
- // Add a separator if this isn't the first message
- if (mergedDiagnosticKind.isPresent()) {
- messageBuilder.append("\n\n");
- }
-
- mergeDiagnosticKind(diagnosticKind);
- // Adds brackets as well as special color strings to make the string red and bold.
- messageBuilder.append(String.format("\033[1;31m[%s]\033[0m ", currentPluginName));
- messageBuilder.append(message);
- }
-
- private static String formatMessage(String messageFormat, Object firstArg, Object[] moreArgs) {
- return String.format(messageFormat, asList(firstArg, moreArgs).toArray());
- }
-
- private void mergeDiagnosticKind(Diagnostic.Kind diagnosticKind) {
- checkArgument(diagnosticKind != Diagnostic.Kind.MANDATORY_WARNING,
- "Dagger plugins should not be issuing mandatory warnings");
- if (!mergedDiagnosticKind.isPresent()) {
- mergedDiagnosticKind = Optional.of(diagnosticKind);
- return;
- }
- Diagnostic.Kind current = mergedDiagnosticKind.get();
- if (current == Diagnostic.Kind.ERROR || diagnosticKind == Diagnostic.Kind.ERROR) {
- mergedDiagnosticKind = Optional.of(Diagnostic.Kind.ERROR);
- } else if (current == Diagnostic.Kind.WARNING || diagnosticKind == Diagnostic.Kind.WARNING) {
- mergedDiagnosticKind = Optional.of(Diagnostic.Kind.WARNING);
- } else if (current == Diagnostic.Kind.NOTE || diagnosticKind == Diagnostic.Kind.NOTE) {
- mergedDiagnosticKind = Optional.of(Diagnostic.Kind.NOTE);
- } else {
- mergedDiagnosticKind = Optional.of(Diagnostic.Kind.OTHER);
- }
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java b/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
deleted file mode 100644
index 68c9604..0000000
--- a/java/dagger/internal/codegen/validation/DependencyRequestValidator.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.asVariable;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedInjectionType;
-import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.type.TypeKind.WILDCARD;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableCollection;
-import dagger.MembersInjector;
-import dagger.assisted.Assisted;
-import dagger.internal.codegen.base.FrameworkTypes;
-import dagger.internal.codegen.base.RequestKinds;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.RequestKind;
-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.ElementKind;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/** Validation for dependency requests. */
-final class DependencyRequestValidator {
- private final MembersInjectionValidator membersInjectionValidator;
- private final InjectionAnnotations injectionAnnotations;
- private final KotlinMetadataUtil metadataUtil;
- private final DaggerElements elements;
-
- @Inject
- DependencyRequestValidator(
- MembersInjectionValidator membersInjectionValidator,
- InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil,
- DaggerElements elements) {
- this.membersInjectionValidator = membersInjectionValidator;
- this.injectionAnnotations = injectionAnnotations;
- this.metadataUtil = metadataUtil;
- this.elements = elements;
- }
-
- /**
- * Adds an error if the given dependency request has more than one qualifier annotation or is a
- * non-instance request with a wildcard type.
- */
- void validateDependencyRequest(
- ValidationReport.Builder<?> report, Element requestElement, TypeMirror requestType) {
- if (MoreElements.isAnnotationPresent(requestElement, Assisted.class)) {
- // Don't validate assisted parameters. These are not dependency requests.
- return;
- }
- checkQualifiers(report, requestElement);
- checkType(report, requestElement, requestType);
- }
-
- private void checkQualifiers(ValidationReport.Builder<?> report, Element requestElement) {
- if (requestElement.getKind() == ElementKind.FIELD
- // static injected fields are not supported, no need to get qualifier from kotlin metadata
- && !requestElement.getModifiers().contains(STATIC)
- && metadataUtil.hasMetadata(requestElement)
- && metadataUtil.isMissingSyntheticPropertyForAnnotations(asVariable(requestElement))) {
- Optional<TypeElement> membersInjector =
- Optional.ofNullable(
- elements.getTypeElement(
- membersInjectorNameForType(asType(requestElement.getEnclosingElement()))));
- if (!membersInjector.isPresent()) {
- report.addError(
- "Unable to read annotations on an injected Kotlin property. The Dagger compiler must"
- + " also be applied to any project containing @Inject properties.",
- requestElement);
- return; // finish checking qualifiers since current information is unreliable.
- }
- }
-
- ImmutableCollection<? extends AnnotationMirror> qualifiers =
- injectionAnnotations.getQualifiers(requestElement);
- if (qualifiers.size() > 1) {
- for (AnnotationMirror qualifier : qualifiers) {
- report.addError(
- "A single dependency request may not use more than one @Qualifier",
- requestElement,
- qualifier);
- }
- }
- }
-
- private void checkType(
- ValidationReport.Builder<?> report, Element requestElement, TypeMirror requestType) {
- TypeMirror keyType = extractKeyType(requestType);
- RequestKind requestKind = RequestKinds.getRequestKind(requestType);
- if (keyType.getKind() == TypeKind.DECLARED) {
- TypeElement typeElement = asTypeElement(keyType);
- if (isAssistedInjectionType(typeElement)) {
- report.addError(
- "Dagger does not support injecting @AssistedInject type, "
- + requestType
- + ". Did you mean to inject its assisted factory type instead?",
- requestElement);
- }
- if (requestKind != RequestKind.INSTANCE && isAssistedFactoryType(typeElement)) {
- report.addError(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, "
- + "or Produced<T> when T is an @AssistedFactory-annotated type such as "
- + keyType,
- requestElement);
- }
- }
- if (keyType.getKind().equals(WILDCARD)) {
- // TODO(ronshapiro): Explore creating this message using RequestKinds.
- report.addError(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, "
- + "or Produced<T> when T is a wildcard type such as "
- + keyType,
- requestElement);
- }
- if (MoreTypes.isType(keyType) && MoreTypes.isTypeOf(MembersInjector.class, keyType)) {
- DeclaredType membersInjectorType = MoreTypes.asDeclared(keyType);
- if (membersInjectorType.getTypeArguments().isEmpty()) {
- report.addError("Cannot inject a raw MembersInjector", requestElement);
- } else {
- report.addSubreport(
- membersInjectionValidator.validateMembersInjectionRequest(
- requestElement, membersInjectorType.getTypeArguments().get(0)));
- }
- }
- }
-
- /**
- * Adds an error if the given dependency request is for a {@link dagger.producers.Producer} or
- * {@link dagger.producers.Produced}.
- *
- * <p>Only call this when processing a provision binding.
- */
- // TODO(dpb): Should we disallow Producer entry points in non-production components?
- void checkNotProducer(ValidationReport.Builder<?> report, VariableElement requestElement) {
- TypeMirror requestType = requestElement.asType();
- if (FrameworkTypes.isProducerType(requestType)) {
- report.addError(
- String.format(
- "%s may only be injected in @Produces methods",
- MoreTypes.asTypeElement(requestType).getSimpleName()),
- requestElement);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java b/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
deleted file mode 100644
index 7d7b9e3..0000000
--- a/java/dagger/internal/codegen/validation/DiagnosticMessageGenerator.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Predicates.equalTo;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.getLast;
-import static com.google.common.collect.Iterables.indexOf;
-import static com.google.common.collect.Iterables.transform;
-import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static dagger.internal.codegen.extension.DaggerGraphs.shortestPath;
-import static dagger.internal.codegen.extension.DaggerStreams.instancesOf;
-import static dagger.internal.codegen.extension.DaggerStreams.presentValues;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.DECLARATION_ORDER;
-import static dagger.internal.codegen.langmodel.DaggerElements.closestEnclosingTypeElement;
-import static java.util.Collections.min;
-import static java.util.Comparator.comparing;
-import static java.util.Comparator.comparingInt;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Table;
-import dagger.internal.codegen.base.ElementFormatter;
-import dagger.internal.codegen.base.Formatter;
-import dagger.internal.codegen.binding.DependencyRequestFormatter;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.Edge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.model.BindingGraph.Node;
-import dagger.model.ComponentPath;
-import java.util.Comparator;
-import java.util.Set;
-import java.util.function.Function;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/** Helper class for generating diagnostic messages. */
-public final class DiagnosticMessageGenerator {
-
- /** Injectable factory for {@code DiagnosticMessageGenerator}. */
- public static final class Factory {
- private final DaggerTypes types;
- private final DependencyRequestFormatter dependencyRequestFormatter;
- private final ElementFormatter elementFormatter;
-
- @Inject
- Factory(
- DaggerTypes types,
- DependencyRequestFormatter dependencyRequestFormatter,
- ElementFormatter elementFormatter) {
- this.types = types;
- this.dependencyRequestFormatter = dependencyRequestFormatter;
- this.elementFormatter = elementFormatter;
- }
-
- /** Creates a {@code DiagnosticMessageGenerator} for the given binding graph. */
- public DiagnosticMessageGenerator create(BindingGraph graph) {
- return new DiagnosticMessageGenerator(
- graph, types, dependencyRequestFormatter, elementFormatter);
- }
- }
-
- private final BindingGraph graph;
- private final DependencyRequestFormatter dependencyRequestFormatter;
- private final ElementFormatter elementFormatter;
-
- /** A cached function from type to all of its supertypes in breadth-first order. */
- private final Function<TypeElement, Iterable<TypeElement>> supertypes;
-
- /** The shortest path (value) from an entry point (column) to a binding (row). */
- private final Table<MaybeBinding, DependencyEdge, ImmutableList<Node>> shortestPaths =
- HashBasedTable.create();
-
- private static <K, V> Function<K, V> memoize(Function<K, V> uncached) {
- // If Android Guava is on the processor path, then c.g.c.b.Function (which LoadingCache
- // implements) does not extend j.u.f.Function.
- // TODO(erichang): Fix current breakages and try to remove this to enforce not having this on
- // processor path.
-
- // First, explicitly convert uncached to c.g.c.b.Function because CacheLoader.from() expects
- // one.
- com.google.common.base.Function<K, V> uncachedAsBaseFunction = uncached::apply;
-
- LoadingCache<K, V> cache =
- CacheBuilder.newBuilder().build(CacheLoader.from(uncachedAsBaseFunction));
-
- // Second, explicitly convert LoadingCache to j.u.f.Function.
- @SuppressWarnings("deprecation") // uncachedAsBaseFunction throws only unchecked exceptions
- Function<K, V> memoized = cache::apply;
-
- return memoized;
- }
-
- private DiagnosticMessageGenerator(
- BindingGraph graph,
- DaggerTypes types,
- DependencyRequestFormatter dependencyRequestFormatter,
- ElementFormatter elementFormatter) {
- this.graph = graph;
- this.dependencyRequestFormatter = dependencyRequestFormatter;
- this.elementFormatter = elementFormatter;
- supertypes =
- memoize(
- component -> transform(types.supertypes(component.asType()), MoreTypes::asTypeElement));
- }
-
- public String getMessage(MaybeBinding binding) {
- ImmutableSet<DependencyEdge> entryPoints = graph.entryPointEdgesDependingOnBinding(binding);
- ImmutableSet<DependencyEdge> requests = requests(binding);
- ImmutableList<DependencyEdge> dependencyTrace = dependencyTrace(binding, entryPoints);
-
- return getMessageInternal(dependencyTrace, requests, entryPoints);
- }
-
- public String getMessage(DependencyEdge dependencyEdge) {
- ImmutableSet<DependencyEdge> requests = ImmutableSet.of(dependencyEdge);
-
- ImmutableSet<DependencyEdge> entryPoints;
- ImmutableList<DependencyEdge> dependencyTrace;
- if (dependencyEdge.isEntryPoint()) {
- entryPoints = ImmutableSet.of(dependencyEdge);
- dependencyTrace = ImmutableList.of(dependencyEdge);
- } else {
- // It's not an entry point, so it's part of a binding
- dagger.model.Binding binding = (dagger.model.Binding) source(dependencyEdge);
- entryPoints = graph.entryPointEdgesDependingOnBinding(binding);
- dependencyTrace =
- ImmutableList.<DependencyEdge>builder()
- .add(dependencyEdge)
- .addAll(dependencyTrace(binding, entryPoints))
- .build();
- }
-
- return getMessageInternal(dependencyTrace, requests, entryPoints);
- }
-
- private String getMessageInternal(
- ImmutableList<DependencyEdge> dependencyTrace,
- ImmutableSet<DependencyEdge> requests,
- ImmutableSet<DependencyEdge> entryPoints) {
- StringBuilder message =
- graph.isFullBindingGraph()
- ? new StringBuilder()
- : new StringBuilder(dependencyTrace.size() * 100 /* a guess heuristic */);
-
- // Print the dependency trace unless it's a full binding graph
- if (!graph.isFullBindingGraph()) {
- dependencyTrace.forEach(
- edge -> dependencyRequestFormatter.appendFormatLine(message, edge.dependencyRequest()));
- if (!dependencyTrace.isEmpty()) {
- appendComponentPathUnlessAtRoot(message, source(getLast(dependencyTrace)));
- }
- }
-
- // Print any dependency requests that aren't shown as part of the dependency trace.
- ImmutableSet<Element> requestsToPrint =
- requests.stream()
- // if printing entry points, skip entry points and the traced request
- .filter(
- request ->
- graph.isFullBindingGraph()
- || (!request.isEntryPoint() && !isTracedRequest(dependencyTrace, request)))
- .map(request -> request.dependencyRequest().requestElement())
- .flatMap(presentValues())
- .collect(toImmutableSet());
- if (!requestsToPrint.isEmpty()) {
- message
- .append("\nIt is")
- .append(graph.isFullBindingGraph() ? " " : " also ")
- .append("requested at:");
- elementFormatter.formatIndentedList(message, requestsToPrint, 1);
- }
-
- // Print the remaining entry points, showing which component they're in, unless it's a full
- // binding graph
- if (!graph.isFullBindingGraph() && entryPoints.size() > 1) {
- message.append("\nThe following other entry points also depend on it:");
- entryPointFormatter.formatIndentedList(
- message,
- entryPoints.stream()
- .filter(entryPoint -> !entryPoint.equals(getLast(dependencyTrace)))
- .sorted(
- // 1. List entry points in components closest to the root first.
- // 2. List entry points declared in a component before those in a supertype.
- // 3. List entry points in declaration order in their declaring type.
- rootComponentFirst()
- .thenComparing(nearestComponentSupertypeFirst())
- .thenComparing(requestElementDeclarationOrder()))
- .collect(toImmutableList()),
- 1);
- }
- return message.toString();
- }
-
- public void appendComponentPathUnlessAtRoot(StringBuilder message, Node node) {
- if (!node.componentPath().equals(graph.rootComponentNode().componentPath())) {
- message.append(String.format(" [%s]", node.componentPath()));
- }
- }
-
- private final Formatter<DependencyEdge> entryPointFormatter =
- new Formatter<DependencyEdge>() {
- @Override
- public String format(DependencyEdge object) {
- Element requestElement = object.dependencyRequest().requestElement().get();
- StringBuilder element = new StringBuilder(elementToString(requestElement));
-
- // For entry points declared in subcomponents or supertypes of the root component,
- // append the component path to make clear to the user which component it's in.
- ComponentPath componentPath = source(object).componentPath();
- if (!componentPath.atRoot()
- || !requestElement.getEnclosingElement().equals(componentPath.rootComponent())) {
- element.append(String.format(" [%s]", componentPath));
- }
- return element.toString();
- }
- };
-
- private static boolean isTracedRequest(
- ImmutableList<DependencyEdge> dependencyTrace, DependencyEdge request) {
- return !dependencyTrace.isEmpty() && request.equals(dependencyTrace.get(0));
- }
-
- /**
- * 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.model could be useful, i.e.
- // bindingGraph.shortestPathFromEntryPoint(DependencyEdge, MaybeBindingNode)
- ImmutableList<DependencyEdge> dependencyTrace(
- MaybeBinding binding, ImmutableSet<DependencyEdge> entryPoints) {
- // Module binding graphs may have bindings unreachable from any entry points. If there are
- // no entry points for this DiagnosticInfo, don't try to print a dependency trace.
- if (entryPoints.isEmpty()) {
- return ImmutableList.of();
- }
- // Show the full dependency trace for one entry point.
- DependencyEdge entryPointForTrace =
- min(
- entryPoints,
- // prefer entry points in components closest to the root
- rootComponentFirst()
- // then prefer entry points with a short dependency path to the error
- .thenComparing(shortestDependencyPathFirst(binding))
- // then prefer entry points declared in the component to those declared in a
- // supertype
- .thenComparing(nearestComponentSupertypeFirst())
- // finally prefer entry points declared first in their enclosing type
- .thenComparing(requestElementDeclarationOrder()));
-
- ImmutableList<Node> shortestBindingPath =
- shortestPathFromEntryPoint(entryPointForTrace, binding);
- verify(
- !shortestBindingPath.isEmpty(),
- "no dependency path from %s to %s in %s",
- entryPointForTrace,
- binding,
- graph);
-
- ImmutableList.Builder<DependencyEdge> dependencyTrace = ImmutableList.builder();
- dependencyTrace.add(entryPointForTrace);
- for (int i = 0; i < shortestBindingPath.size() - 1; i++) {
- Set<Edge> dependenciesBetween =
- graph
- .network()
- .edgesConnecting(shortestBindingPath.get(i), shortestBindingPath.get(i + 1));
- // If a binding requests a key more than once, any of them should be fine to get to the
- // shortest path
- dependencyTrace.add((DependencyEdge) Iterables.get(dependenciesBetween, 0));
- }
- return dependencyTrace.build().reverse();
- }
-
- /** Returns all the nonsynthetic dependency requests for a binding. */
- ImmutableSet<DependencyEdge> requests(MaybeBinding binding) {
- return graph.network().inEdges(binding).stream()
- .flatMap(instancesOf(DependencyEdge.class))
- .filter(edge -> edge.dependencyRequest().requestElement().isPresent())
- .sorted(requestEnclosingTypeName().thenComparing(requestElementDeclarationOrder()))
- .collect(toImmutableSet());
- }
-
- /**
- * Returns a comparator that sorts entry points in components whose paths from the root are
- * shorter first.
- */
- Comparator<DependencyEdge> rootComponentFirst() {
- return comparingInt(entryPoint -> source(entryPoint).componentPath().components().size());
- }
-
- /**
- * Returns a comparator that puts entry points whose shortest dependency path to {@code binding}
- * is shortest first.
- */
- Comparator<DependencyEdge> shortestDependencyPathFirst(MaybeBinding binding) {
- return comparing(entryPoint -> shortestPathFromEntryPoint(entryPoint, binding).size());
- }
-
- ImmutableList<Node> shortestPathFromEntryPoint(DependencyEdge entryPoint, MaybeBinding binding) {
- return shortestPaths
- .row(binding)
- .computeIfAbsent(
- entryPoint,
- ep ->
- shortestPath(
- node ->
- filter(graph.network().successors(node), MaybeBinding.class::isInstance),
- graph.network().incidentNodes(ep).target(),
- binding));
- }
-
- /**
- * Returns a comparator that sorts entry points in by the distance of the type that declares them
- * from the type of the component that contains them.
- *
- * <p>For instance, an entry point declared directly in the component type would sort before one
- * declared in a direct supertype, which would sort before one declared in a supertype of a
- * supertype.
- */
- Comparator<DependencyEdge> nearestComponentSupertypeFirst() {
- return comparingInt(
- entryPoint ->
- indexOf(
- supertypes.apply(componentContainingEntryPoint(entryPoint)),
- equalTo(typeDeclaringEntryPoint(entryPoint))));
- }
-
- TypeElement componentContainingEntryPoint(DependencyEdge entryPoint) {
- return source(entryPoint).componentPath().currentComponent();
- }
-
- TypeElement typeDeclaringEntryPoint(DependencyEdge entryPoint) {
- return MoreElements.asType(
- entryPoint.dependencyRequest().requestElement().get().getEnclosingElement());
- }
-
- /**
- * Returns a comparator that sorts dependency edges lexicographically by the qualified name of the
- * type that contains them. Only appropriate for edges with request elements.
- */
- Comparator<DependencyEdge> requestEnclosingTypeName() {
- return comparing(
- edge ->
- closestEnclosingTypeElement(edge.dependencyRequest().requestElement().get())
- .getQualifiedName()
- .toString());
- }
-
- /**
- * Returns a comparator that sorts edges in the order in which their request elements were
- * declared in their declaring type.
- *
- * <p>Only useful to compare edges whose request elements were declared in the same type.
- */
- Comparator<DependencyEdge> requestElementDeclarationOrder() {
- return comparing(edge -> edge.dependencyRequest().requestElement().get(), DECLARATION_ORDER);
- }
-
- private Node source(Edge edge) {
- return graph.network().incidentNodes(edge).source();
- }
-}
diff --git a/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java b/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
deleted file mode 100644
index 35ae7c7..0000000
--- a/java/dagger/internal/codegen/validation/DiagnosticReporterFactory.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.collect.Lists.asList;
-import static dagger.internal.codegen.base.ElementFormatter.elementToString;
-import static dagger.internal.codegen.langmodel.DaggerElements.elementEncloses;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.model.BindingGraph;
-import dagger.model.BindingGraph.ChildFactoryMethodEdge;
-import dagger.model.BindingGraph.ComponentNode;
-import dagger.model.BindingGraph.DependencyEdge;
-import dagger.model.BindingGraph.MaybeBinding;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic;
-import org.checkerframework.checker.nullness.compatqual.NullableDecl;
-
-/** A factory for {@link DiagnosticReporter}s. */
-// TODO(ronshapiro): If multiple plugins print errors on the same node/edge, should we condense the
-// messages and only print the dependency trace once?
-final class DiagnosticReporterFactory {
- private final Messager messager;
- private final DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory;
-
- @Inject
- DiagnosticReporterFactory(
- Messager messager, DiagnosticMessageGenerator.Factory diagnosticMessageGeneratorFactory) {
- this.messager = messager;
- this.diagnosticMessageGeneratorFactory = diagnosticMessageGeneratorFactory;
- }
-
- /** Creates a reporter for a binding graph and a plugin. */
- DiagnosticReporterImpl reporter(
- BindingGraph graph, BindingGraphPlugin plugin, boolean reportErrorsAsWarnings) {
- return new DiagnosticReporterImpl(graph, plugin.pluginName(), reportErrorsAsWarnings);
- }
-
- /**
- * A {@link DiagnosticReporter} that keeps track of which {@linkplain Diagnostic.Kind kinds} of
- * diagnostics were reported.
- */
- final class DiagnosticReporterImpl implements DiagnosticReporter {
- private final String plugin;
- private final TypeElement rootComponent;
- private final boolean reportErrorsAsWarnings;
- private final ImmutableSet.Builder<Diagnostic.Kind> reportedDiagnosticKinds =
- ImmutableSet.builder();
- private final DiagnosticMessageGenerator diagnosticMessageGenerator;
-
- DiagnosticReporterImpl(BindingGraph graph, String plugin, boolean reportErrorsAsWarnings) {
- this.plugin = plugin;
- this.reportErrorsAsWarnings = reportErrorsAsWarnings;
- this.rootComponent = graph.rootComponentNode().componentPath().currentComponent();
- this.diagnosticMessageGenerator = diagnosticMessageGeneratorFactory.create(graph);
- }
-
- /** Returns which {@linkplain Diagnostic.Kind kinds} of diagnostics were reported. */
- ImmutableSet<Diagnostic.Kind> reportedDiagnosticKinds() {
- return reportedDiagnosticKinds.build();
- }
-
- @Override
- public void reportComponent(
- Diagnostic.Kind diagnosticKind, ComponentNode componentNode, String messageFormat) {
- StringBuilder message = new StringBuilder(messageFormat);
- diagnosticMessageGenerator.appendComponentPathUnlessAtRoot(message, componentNode);
- // TODO(dpb): Report at the component node component.
- printMessage(diagnosticKind, message, rootComponent);
- }
-
- @Override
- @FormatMethod
- public void reportComponent(
- Diagnostic.Kind diagnosticKind,
- ComponentNode componentNode,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportComponent(
- diagnosticKind, componentNode, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- // TODO(ronshapiro): should this also include the binding element?
- @Override
- public void reportBinding(
- Diagnostic.Kind diagnosticKind, MaybeBinding binding, String message) {
- printMessage(
- diagnosticKind, message + diagnosticMessageGenerator.getMessage(binding), rootComponent);
- }
-
- @Override
- public void reportBinding(
- Diagnostic.Kind diagnosticKind,
- MaybeBinding binding,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportBinding(diagnosticKind, binding, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- @Override
- public void reportDependency(
- Diagnostic.Kind diagnosticKind, DependencyEdge dependencyEdge, String message) {
- printMessage(
- diagnosticKind,
- message + diagnosticMessageGenerator.getMessage(dependencyEdge),
- rootComponent);
- }
-
- @Override
- public void reportDependency(
- Diagnostic.Kind diagnosticKind,
- DependencyEdge dependencyEdge,
- String messageFormat,
- Object firstArg,
- Object... moreArgs) {
- reportDependency(
- diagnosticKind, dependencyEdge, formatMessage(messageFormat, firstArg, moreArgs));
- }
-
- @Override
- public void reportSubcomponentFactoryMethod(
- Diagnostic.Kind diagnosticKind,
- ChildFactoryMethodEdge childFactoryMethodEdge,
- String message) {
- printMessage(diagnosticKind, message, childFactoryMethodEdge.factoryMethod());
- }
-
- @Override
- public 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());
- }
-
- void printMessage(
- Diagnostic.Kind diagnosticKind,
- CharSequence message,
- @NullableDecl Element elementToReport) {
- if (diagnosticKind.equals(ERROR) && reportErrorsAsWarnings) {
- diagnosticKind = Diagnostic.Kind.WARNING;
- }
- reportedDiagnosticKinds.add(diagnosticKind);
- StringBuilder fullMessage = new StringBuilder();
- appendBracketPrefix(fullMessage, plugin);
-
- // TODO(ronshapiro): should we create a HashSet out of elementEncloses() so we don't
- // need to do an O(n) contains() each time?
- if (elementToReport != null && !elementEncloses(rootComponent, elementToReport)) {
- appendBracketPrefix(fullMessage, elementToString(elementToReport));
- elementToReport = rootComponent;
- }
-
- messager.printMessage(diagnosticKind, fullMessage.append(message), elementToReport);
- }
-
- private void appendBracketPrefix(StringBuilder message, String prefix) {
- message.append(String.format("[%s] ", prefix));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java b/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
deleted file mode 100644
index 06f68f6..0000000
--- a/java/dagger/internal/codegen/validation/InjectBindingRegistryImpl.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static dagger.internal.codegen.base.Keys.isValidImplicitProvisionKey;
-import static dagger.internal.codegen.base.Keys.isValidMembersInjectionKey;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
-import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import dagger.Component;
-import dagger.MembersInjector;
-import dagger.Provides;
-import dagger.internal.codegen.base.SourceFileGenerationException;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingFactory;
-import dagger.internal.codegen.binding.InjectBindingRegistry;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.tools.Diagnostic.Kind;
-
-/**
- * Maintains the collection of provision bindings from {@link Inject} constructors and members
- * injection bindings from {@link Inject} fields and methods known to the annotation processor.
- * Note that this registry <b>does not</b> handle any explicit bindings (those from {@link Provides}
- * methods, {@link Component} dependencies, etc.).
- */
-@Singleton
-final class InjectBindingRegistryImpl implements InjectBindingRegistry {
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final Messager messager;
- private final InjectValidator injectValidator;
- private final InjectValidator injectValidatorWhenGeneratingCode;
- private final KeyFactory keyFactory;
- private final BindingFactory bindingFactory;
- private final CompilerOptions compilerOptions;
-
- final class BindingsCollection<B extends Binding> {
- private final Class<?> factoryClass;
- private final Map<Key, B> bindingsByKey = Maps.newLinkedHashMap();
- private final Deque<B> bindingsRequiringGeneration = new ArrayDeque<>();
- private final Set<Key> materializedBindingKeys = Sets.newLinkedHashSet();
-
- BindingsCollection(Class<?> factoryClass) {
- this.factoryClass = factoryClass;
- }
-
- void generateBindings(SourceFileGenerator<B> generator) throws SourceFileGenerationException {
- for (B binding = bindingsRequiringGeneration.poll();
- binding != null;
- binding = bindingsRequiringGeneration.poll()) {
- checkState(!binding.unresolved().isPresent());
- if (injectValidatorWhenGeneratingCode.isValidType(binding.key().type())) {
- generator.generate(binding);
- }
- materializedBindingKeys.add(binding.key());
- }
- // Because Elements instantiated across processing rounds are not guaranteed to be equals() to
- // the logically same element, clear the cache after generating
- bindingsByKey.clear();
- }
-
- /** Returns a previously cached binding. */
- B getBinding(Key key) {
- return bindingsByKey.get(key);
- }
-
- /** Caches the binding and generates it if it needs generation. */
- void tryRegisterBinding(B binding, boolean warnIfNotAlreadyGenerated) {
- tryToCacheBinding(binding);
- tryToGenerateBinding(binding, warnIfNotAlreadyGenerated);
- }
-
- /**
- * Tries to generate a binding, not generating if it already is generated. For resolved
- * bindings, this will try to generate the unresolved version of the binding.
- */
- void tryToGenerateBinding(B binding, boolean warnIfNotAlreadyGenerated) {
- if (shouldGenerateBinding(binding)) {
- bindingsRequiringGeneration.offer(binding);
- if (compilerOptions.warnIfInjectionFactoryNotGeneratedUpstream()
- && warnIfNotAlreadyGenerated) {
- messager.printMessage(
- Kind.NOTE,
- String.format(
- "Generating a %s for %s. "
- + "Prefer to run the dagger processor over that class instead.",
- factoryClass.getSimpleName(),
- types.erasure(binding.key().type()))); // erasure to strip <T> from msgs.
- }
- }
- }
-
- /** Returns true if the binding needs to be generated. */
- private boolean shouldGenerateBinding(B binding) {
- return !binding.unresolved().isPresent()
- && !materializedBindingKeys.contains(binding.key())
- && !bindingsRequiringGeneration.contains(binding)
- && elements.getTypeElement(generatedClassNameForBinding(binding)) == null;
- }
-
- /** Caches the binding for future lookups by key. */
- private void tryToCacheBinding(B binding) {
- // We only cache resolved bindings or unresolved bindings w/o type arguments.
- // Unresolved bindings w/ type arguments aren't valid for the object graph.
- if (binding.unresolved().isPresent()
- || binding.bindingTypeElement().get().getTypeParameters().isEmpty()) {
- Key key = binding.key();
- Binding previousValue = bindingsByKey.put(key, binding);
- checkState(previousValue == null || binding.equals(previousValue),
- "couldn't register %s. %s was already registered for %s",
- binding, previousValue, key);
- }
- }
- }
-
- private final BindingsCollection<ProvisionBinding> provisionBindings =
- new BindingsCollection<>(Provider.class);
- private final BindingsCollection<MembersInjectionBinding> membersInjectionBindings =
- new BindingsCollection<>(MembersInjector.class);
-
- @Inject
- InjectBindingRegistryImpl(
- DaggerElements elements,
- DaggerTypes types,
- Messager messager,
- InjectValidator injectValidator,
- KeyFactory keyFactory,
- BindingFactory bindingFactory,
- CompilerOptions compilerOptions) {
- this.elements = elements;
- this.types = types;
- this.messager = messager;
- this.injectValidator = injectValidator;
- this.injectValidatorWhenGeneratingCode = injectValidator.whenGeneratingCode();
- this.keyFactory = keyFactory;
- this.bindingFactory = bindingFactory;
- this.compilerOptions = compilerOptions;
- }
-
-
- // TODO(dpb): make the SourceFileGenerators fields so they don't have to be passed in
- @Override
- public void generateSourcesForRequiredBindings(
- SourceFileGenerator<ProvisionBinding> factoryGenerator,
- SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator)
- throws SourceFileGenerationException {
- provisionBindings.generateBindings(factoryGenerator);
- membersInjectionBindings.generateBindings(membersInjectorGenerator);
- }
-
- /**
- * Registers the binding for generation and later lookup. If the binding is resolved, we also
- * attempt to register an unresolved version of it.
- */
- private void registerBinding(ProvisionBinding binding, boolean warnIfNotAlreadyGenerated) {
- provisionBindings.tryRegisterBinding(binding, warnIfNotAlreadyGenerated);
- if (binding.unresolved().isPresent()) {
- provisionBindings.tryToGenerateBinding(binding.unresolved().get(), warnIfNotAlreadyGenerated);
- }
- }
-
- /**
- * Registers the binding for generation and later lookup. If the binding is resolved, we also
- * attempt to register an unresolved version of it.
- */
- private void registerBinding(MembersInjectionBinding binding, boolean warnIfNotAlreadyGenerated) {
- /*
- * We generate MembersInjector classes for types with @Inject constructors only if they have any
- * injection sites.
- *
- * We generate MembersInjector classes for types without @Inject constructors only if they have
- * local (non-inherited) injection sites.
- *
- * Warn only when registering bindings post-hoc for those types.
- */
- if (warnIfNotAlreadyGenerated) {
- boolean hasInjectConstructor =
- !(injectedConstructors(binding.membersInjectedType()).isEmpty()
- && assistedInjectedConstructors(binding.membersInjectedType()).isEmpty());
- warnIfNotAlreadyGenerated =
- hasInjectConstructor
- ? !binding.injectionSites().isEmpty()
- : binding.hasLocalInjectionSites();
- }
-
- membersInjectionBindings.tryRegisterBinding(binding, warnIfNotAlreadyGenerated);
- if (binding.unresolved().isPresent()) {
- membersInjectionBindings.tryToGenerateBinding(
- binding.unresolved().get(), warnIfNotAlreadyGenerated);
- }
- }
-
- @Override
- public Optional<ProvisionBinding> tryRegisterConstructor(ExecutableElement constructorElement) {
- return tryRegisterConstructor(constructorElement, Optional.empty(), false);
- }
-
- @CanIgnoreReturnValue
- private Optional<ProvisionBinding> tryRegisterConstructor(
- ExecutableElement constructorElement,
- Optional<TypeMirror> resolvedType,
- boolean warnIfNotAlreadyGenerated) {
- TypeElement typeElement = MoreElements.asType(constructorElement.getEnclosingElement());
- DeclaredType type = MoreTypes.asDeclared(typeElement.asType());
- Key key = keyFactory.forInjectConstructorWithResolvedType(type);
- ProvisionBinding cachedBinding = provisionBindings.getBinding(key);
- if (cachedBinding != null) {
- return Optional.of(cachedBinding);
- }
-
- ValidationReport<TypeElement> report = injectValidator.validateConstructor(constructorElement);
- report.printMessagesTo(messager);
- if (report.isClean()) {
- ProvisionBinding binding = bindingFactory.injectionBinding(constructorElement, resolvedType);
- registerBinding(binding, warnIfNotAlreadyGenerated);
- if (!binding.injectionSites().isEmpty()) {
- tryRegisterMembersInjectedType(typeElement, resolvedType, warnIfNotAlreadyGenerated);
- }
- return Optional.of(binding);
- }
- return Optional.empty();
- }
-
- @Override
- public Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(TypeElement typeElement) {
- return tryRegisterMembersInjectedType(typeElement, Optional.empty(), false);
- }
-
- @CanIgnoreReturnValue
- private Optional<MembersInjectionBinding> tryRegisterMembersInjectedType(
- TypeElement typeElement,
- Optional<TypeMirror> resolvedType,
- boolean warnIfNotAlreadyGenerated) {
- DeclaredType type = MoreTypes.asDeclared(typeElement.asType());
- Key key = keyFactory.forInjectConstructorWithResolvedType(type);
- MembersInjectionBinding cachedBinding = membersInjectionBindings.getBinding(key);
- if (cachedBinding != null) {
- return Optional.of(cachedBinding);
- }
-
- ValidationReport<TypeElement> report =
- injectValidator.validateMembersInjectionType(typeElement);
- report.printMessagesTo(messager);
- if (report.isClean()) {
- MembersInjectionBinding binding = bindingFactory.membersInjectionBinding(type, resolvedType);
- registerBinding(binding, warnIfNotAlreadyGenerated);
- for (Optional<DeclaredType> supertype = types.nonObjectSuperclass(type);
- supertype.isPresent();
- supertype = types.nonObjectSuperclass(supertype.get())) {
- getOrFindMembersInjectionBinding(keyFactory.forMembersInjectedType(supertype.get()));
- }
- return Optional.of(binding);
- }
- return Optional.empty();
- }
-
- @CanIgnoreReturnValue
- @Override
- public Optional<ProvisionBinding> getOrFindProvisionBinding(Key key) {
- checkNotNull(key);
- if (!isValidImplicitProvisionKey(key, types)) {
- return Optional.empty();
- }
- ProvisionBinding binding = provisionBindings.getBinding(key);
- if (binding != null) {
- return Optional.of(binding);
- }
-
- // ok, let's see if we can find an @Inject constructor
- TypeElement element = MoreElements.asType(types.asElement(key.type()));
- ImmutableSet<ExecutableElement> injectConstructors =
- ImmutableSet.<ExecutableElement>builder()
- .addAll(injectedConstructors(element))
- .addAll(assistedInjectedConstructors(element))
- .build();
- switch (injectConstructors.size()) {
- case 0:
- // No constructor found.
- return Optional.empty();
- case 1:
- return tryRegisterConstructor(
- Iterables.getOnlyElement(injectConstructors), Optional.of(key.type()), true);
- default:
- throw new IllegalStateException("Found multiple @Inject constructors: "
- + injectConstructors);
- }
- }
-
- @CanIgnoreReturnValue
- @Override
- public Optional<MembersInjectionBinding> getOrFindMembersInjectionBinding(Key key) {
- checkNotNull(key);
- // TODO(gak): is checking the kind enough?
- checkArgument(isValidMembersInjectionKey(key));
- MembersInjectionBinding binding = membersInjectionBindings.getBinding(key);
- if (binding != null) {
- return Optional.of(binding);
- }
- Optional<MembersInjectionBinding> newBinding =
- tryRegisterMembersInjectedType(
- MoreTypes.asTypeElement(key.type()), Optional.of(key.type()), true);
- return newBinding;
- }
-
- @Override
- public Optional<ProvisionBinding> getOrFindMembersInjectorProvisionBinding(Key key) {
- if (!isValidMembersInjectionKey(key)) {
- return Optional.empty();
- }
- Key membersInjectionKey = keyFactory.forMembersInjectedType(types.unwrapType(key.type()));
- return getOrFindMembersInjectionBinding(membersInjectionKey)
- .map(binding -> bindingFactory.membersInjectorBinding(key, binding));
- }
-}
diff --git a/java/dagger/internal/codegen/validation/InjectBindingRegistryModule.java b/java/dagger/internal/codegen/validation/InjectBindingRegistryModule.java
deleted file mode 100644
index 3a164ca..0000000
--- a/java/dagger/internal/codegen/validation/InjectBindingRegistryModule.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 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 dagger.Binds;
-import dagger.Module;
-import dagger.internal.codegen.binding.InjectBindingRegistry;
-
-/** Binds the {@link InjectBindingRegistry} implementation. */
-@Module
-public interface InjectBindingRegistryModule {
- @Binds InjectBindingRegistry injectBindingRegistry(InjectBindingRegistryImpl impl);
-}
diff --git a/java/dagger/internal/codegen/validation/InjectValidator.java b/java/dagger/internal/codegen/validation/InjectValidator.java
deleted file mode 100644
index 240f9d0..0000000
--- a/java/dagger/internal/codegen/validation/InjectValidator.java
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static dagger.internal.codegen.base.Scopes.scopesOf;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
-import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.type.TypeKind.DECLARED;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.assisted.AssistedInject;
-import dagger.internal.codegen.base.ClearableCache;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.Accessibility;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Scope;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-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.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.tools.Diagnostic;
-import javax.tools.Diagnostic.Kind;
-
-/**
- * A {@linkplain ValidationReport validator} for {@link Inject}-annotated elements and the types
- * that contain them.
- */
-@Singleton
-public final class InjectValidator implements ClearableCache {
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final CompilerOptions compilerOptions;
- private final DependencyRequestValidator dependencyRequestValidator;
- private final Optional<Diagnostic.Kind> privateAndStaticInjectionDiagnosticKind;
- private final InjectionAnnotations injectionAnnotations;
- private final KotlinMetadataUtil metadataUtil;
- private final Map<ExecutableElement, ValidationReport<TypeElement>> reports = new HashMap<>();
-
- @Inject
- InjectValidator(
- DaggerTypes types,
- DaggerElements elements,
- DependencyRequestValidator dependencyRequestValidator,
- CompilerOptions compilerOptions,
- InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil) {
- this(
- types,
- elements,
- compilerOptions,
- dependencyRequestValidator,
- Optional.empty(),
- injectionAnnotations,
- metadataUtil);
- }
-
- private InjectValidator(
- DaggerTypes types,
- DaggerElements elements,
- CompilerOptions compilerOptions,
- DependencyRequestValidator dependencyRequestValidator,
- Optional<Kind> privateAndStaticInjectionDiagnosticKind,
- InjectionAnnotations injectionAnnotations,
- KotlinMetadataUtil metadataUtil) {
- this.types = types;
- this.elements = elements;
- this.compilerOptions = compilerOptions;
- this.dependencyRequestValidator = dependencyRequestValidator;
- this.privateAndStaticInjectionDiagnosticKind = privateAndStaticInjectionDiagnosticKind;
- this.injectionAnnotations = injectionAnnotations;
- this.metadataUtil = metadataUtil;
- }
-
- @Override
- public void clearCache() {
- reports.clear();
- }
-
- /**
- * Returns a new validator that performs the same validation as this one, but is strict about
- * rejecting optionally-specified JSR 330 behavior that Dagger doesn't support (unless {@code
- * -Adagger.ignorePrivateAndStaticInjectionForComponent=enabled} was set in the javac options).
- */
- public InjectValidator whenGeneratingCode() {
- return compilerOptions.ignorePrivateAndStaticInjectionForComponent()
- ? this
- : new InjectValidator(
- types,
- elements,
- compilerOptions,
- dependencyRequestValidator,
- Optional.of(Diagnostic.Kind.ERROR),
- injectionAnnotations,
- metadataUtil);
- }
-
- public ValidationReport<TypeElement> validateConstructor(ExecutableElement constructorElement) {
- return reentrantComputeIfAbsent(reports, constructorElement, this::validateConstructorUncached);
- }
-
- private ValidationReport<TypeElement> validateConstructorUncached(
- ExecutableElement constructorElement) {
- ValidationReport.Builder<TypeElement> builder =
- ValidationReport.about(asType(constructorElement.getEnclosingElement()));
-
- if (isAnnotationPresent(constructorElement, Inject.class)
- && isAnnotationPresent(constructorElement, AssistedInject.class)) {
- builder.addError("Constructors cannot be annotated with both @Inject and @AssistedInject");
- }
-
- Class<?> injectAnnotation =
- isAnnotationPresent(constructorElement, Inject.class) ? Inject.class : AssistedInject.class;
-
- if (constructorElement.getModifiers().contains(PRIVATE)) {
- builder.addError(
- "Dagger does not support injection into private constructors", constructorElement);
- }
-
- for (AnnotationMirror qualifier : injectionAnnotations.getQualifiers(constructorElement)) {
- builder.addError(
- String.format(
- "@Qualifier annotations are not allowed on @%s constructors",
- injectAnnotation.getSimpleName()),
- constructorElement,
- qualifier);
- }
-
- String scopeErrorMsg =
- String.format(
- "@Scope annotations are not allowed on @%s constructors",
- injectAnnotation.getSimpleName());
-
- if (injectAnnotation == Inject.class) {
- scopeErrorMsg += "; annotate the class instead";
- }
-
- for (Scope scope : scopesOf(constructorElement)) {
- builder.addError(scopeErrorMsg, constructorElement, scope.scopeAnnotation());
- }
-
- for (VariableElement parameter : constructorElement.getParameters()) {
- validateDependencyRequest(builder, parameter);
- }
-
- if (throwsCheckedExceptions(constructorElement)) {
- builder.addItem(
- String.format(
- "Dagger does not support checked exceptions on @%s constructors",
- injectAnnotation.getSimpleName()),
- privateMemberDiagnosticKind(),
- constructorElement);
- }
-
- checkInjectIntoPrivateClass(constructorElement, builder);
-
- TypeElement enclosingElement =
- MoreElements.asType(constructorElement.getEnclosingElement());
-
- Set<Modifier> typeModifiers = enclosingElement.getModifiers();
- if (typeModifiers.contains(ABSTRACT)) {
- builder.addError(
- String.format(
- "@%s is nonsense on the constructor of an abstract class",
- injectAnnotation.getSimpleName()),
- constructorElement);
- }
-
- if (enclosingElement.getNestingKind().isNested()
- && !typeModifiers.contains(STATIC)) {
- builder.addError(
- String.format(
- "@%s constructors are invalid on inner classes. "
- + "Did you mean to make the class static?",
- injectAnnotation.getSimpleName()),
- constructorElement);
- }
-
- // This is computationally expensive, but probably preferable to a giant index
- ImmutableSet<ExecutableElement> injectConstructors =
- ImmutableSet.<ExecutableElement>builder()
- .addAll(injectedConstructors(enclosingElement))
- .addAll(assistedInjectedConstructors(enclosingElement))
- .build();
-
- if (injectConstructors.size() > 1) {
- builder.addError("Types may only contain one injected constructor", constructorElement);
- }
-
- ImmutableSet<Scope> scopes = scopesOf(enclosingElement);
- if (injectAnnotation == AssistedInject.class) {
- for (Scope scope : scopes) {
- builder.addError(
- "A type with an @AssistedInject-annotated constructor cannot be scoped",
- enclosingElement,
- scope.scopeAnnotation());
- }
- } else if (scopes.size() > 1) {
- for (Scope scope : scopes) {
- builder.addError(
- "A single binding may not declare more than one @Scope",
- enclosingElement,
- scope.scopeAnnotation());
- }
- }
-
- return builder.build();
- }
-
- private ValidationReport<VariableElement> validateField(VariableElement fieldElement) {
- ValidationReport.Builder<VariableElement> builder = ValidationReport.about(fieldElement);
- Set<Modifier> modifiers = fieldElement.getModifiers();
- if (modifiers.contains(FINAL)) {
- builder.addError("@Inject fields may not be final", fieldElement);
- }
-
- if (modifiers.contains(PRIVATE)) {
- builder.addItem(
- "Dagger does not support injection into private fields",
- privateMemberDiagnosticKind(),
- fieldElement);
- }
-
- if (modifiers.contains(STATIC)) {
- builder.addItem(
- "Dagger does not support injection into static fields",
- staticMemberDiagnosticKind(),
- fieldElement);
- }
-
- validateDependencyRequest(builder, fieldElement);
-
- return builder.build();
- }
-
- private ValidationReport<ExecutableElement> validateMethod(ExecutableElement methodElement) {
- ValidationReport.Builder<ExecutableElement> builder = ValidationReport.about(methodElement);
- Set<Modifier> modifiers = methodElement.getModifiers();
- if (modifiers.contains(ABSTRACT)) {
- builder.addError("Methods with @Inject may not be abstract", methodElement);
- }
-
- if (modifiers.contains(PRIVATE)) {
- builder.addItem(
- "Dagger does not support injection into private methods",
- privateMemberDiagnosticKind(),
- methodElement);
- }
-
- if (modifiers.contains(STATIC)) {
- builder.addItem(
- "Dagger does not support injection into static methods",
- staticMemberDiagnosticKind(),
- methodElement);
- }
-
- if (!methodElement.getTypeParameters().isEmpty()) {
- builder.addError("Methods with @Inject may not declare type parameters", methodElement);
- }
-
- if (!methodElement.getThrownTypes().isEmpty()) {
- builder.addError("Methods with @Inject may not throw checked exceptions. "
- + "Please wrap your exceptions in a RuntimeException instead.", methodElement);
- }
-
- for (VariableElement parameter : methodElement.getParameters()) {
- validateDependencyRequest(builder, parameter);
- }
-
- return builder.build();
- }
-
- private void validateDependencyRequest(
- ValidationReport.Builder<?> builder, VariableElement parameter) {
- dependencyRequestValidator.validateDependencyRequest(builder, parameter, parameter.asType());
- dependencyRequestValidator.checkNotProducer(builder, parameter);
- }
-
- public ValidationReport<TypeElement> validateMembersInjectionType(TypeElement typeElement) {
- // TODO(beder): This element might not be currently compiled, so this error message could be
- // left in limbo. Find an appropriate way to display the error message in that case.
- ValidationReport.Builder<TypeElement> builder = ValidationReport.about(typeElement);
- boolean hasInjectedMembers = false;
- for (VariableElement element : ElementFilter.fieldsIn(typeElement.getEnclosedElements())) {
- if (MoreElements.isAnnotationPresent(element, Inject.class)) {
- hasInjectedMembers = true;
- ValidationReport<VariableElement> report = validateField(element);
- if (!report.isClean()) {
- builder.addSubreport(report);
- }
- }
- }
- for (ExecutableElement element : ElementFilter.methodsIn(typeElement.getEnclosedElements())) {
- if (MoreElements.isAnnotationPresent(element, Inject.class)) {
- hasInjectedMembers = true;
- ValidationReport<ExecutableElement> report = validateMethod(element);
- if (!report.isClean()) {
- builder.addSubreport(report);
- }
- }
- }
-
- if (hasInjectedMembers) {
- checkInjectIntoPrivateClass(typeElement, builder);
- checkInjectIntoKotlinObject(typeElement, builder);
- }
- TypeMirror superclass = typeElement.getSuperclass();
- if (!superclass.getKind().equals(TypeKind.NONE)) {
- ValidationReport<TypeElement> report = validateType(MoreTypes.asTypeElement(superclass));
- if (!report.isClean()) {
- builder.addSubreport(report);
- }
- }
- return builder.build();
- }
-
- public ValidationReport<TypeElement> validateType(TypeElement typeElement) {
- ValidationReport.Builder<TypeElement> builder = ValidationReport.about(typeElement);
- ValidationReport<TypeElement> membersInjectionReport =
- validateMembersInjectionType(typeElement);
- if (!membersInjectionReport.isClean()) {
- builder.addSubreport(membersInjectionReport);
- }
- for (ExecutableElement element :
- ElementFilter.constructorsIn(typeElement.getEnclosedElements())) {
- if (isAnnotationPresent(element, Inject.class)
- || isAnnotationPresent(element, AssistedInject.class)) {
- ValidationReport<TypeElement> report = validateConstructor(element);
- if (!report.isClean()) {
- builder.addSubreport(report);
- }
- }
- }
- return builder.build();
- }
-
- public boolean isValidType(TypeMirror type) {
- if (!type.getKind().equals(DECLARED)) {
- return true;
- }
- return validateType(MoreTypes.asTypeElement(type)).isClean();
- }
-
- /** Returns true if the given method element declares a checked exception. */
- private boolean throwsCheckedExceptions(ExecutableElement methodElement) {
- TypeMirror runtimeExceptionType = elements.getTypeElement(RuntimeException.class).asType();
- TypeMirror errorType = elements.getTypeElement(Error.class).asType();
- for (TypeMirror thrownType : methodElement.getThrownTypes()) {
- if (!types.isSubtype(thrownType, runtimeExceptionType)
- && !types.isSubtype(thrownType, errorType)) {
- return true;
- }
- }
- return false;
- }
-
- private void checkInjectIntoPrivateClass(
- Element element, ValidationReport.Builder<TypeElement> builder) {
- if (!Accessibility.isElementAccessibleFromOwnPackage(
- DaggerElements.closestEnclosingTypeElement(element))) {
- builder.addItem(
- "Dagger does not support injection into private classes",
- privateMemberDiagnosticKind(),
- element);
- }
- }
-
- private void checkInjectIntoKotlinObject(
- TypeElement element, ValidationReport.Builder<TypeElement> builder) {
- if (metadataUtil.isObjectClass(element) || metadataUtil.isCompanionObjectClass(element)) {
- builder.addError("Dagger does not support injection into Kotlin objects", element);
- }
- }
-
- private Diagnostic.Kind privateMemberDiagnosticKind() {
- return privateAndStaticInjectionDiagnosticKind.orElse(
- compilerOptions.privateMemberValidationKind());
- }
-
- private Diagnostic.Kind staticMemberDiagnosticKind() {
- return privateAndStaticInjectionDiagnosticKind.orElse(
- compilerOptions.staticMemberValidationKind());
- }
-}
diff --git a/java/dagger/internal/codegen/validation/MapKeyValidator.java b/java/dagger/internal/codegen/validation/MapKeyValidator.java
deleted file mode 100644
index 6aa5147..0000000
--- a/java/dagger/internal/codegen/validation/MapKeyValidator.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2014 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 javax.lang.model.util.ElementFilter.methodsIn;
-
-import dagger.MapKey;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.List;
-import javax.inject.Inject;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-
-/**
- * A validator for {@link MapKey} annotations.
- */
-// TODO(dpb,gak): Should unwrapped MapKeys be required to have their single member be named "value"?
-public final class MapKeyValidator {
- private final DaggerElements elements;
-
- @Inject
- MapKeyValidator(DaggerElements elements) {
- this.elements = elements;
- }
-
- public ValidationReport<Element> validate(Element element) {
- ValidationReport.Builder<Element> builder = ValidationReport.about(element);
- List<ExecutableElement> members = methodsIn(((TypeElement) element).getEnclosedElements());
- if (members.isEmpty()) {
- builder.addError("Map key annotations must have members", element);
- } else if (element.getAnnotation(MapKey.class).unwrapValue()) {
- if (members.size() > 1) {
- builder.addError(
- "Map key annotations with unwrapped values must have exactly one member", element);
- } else if (members.get(0).getReturnType().getKind() == TypeKind.ARRAY) {
- builder.addError("Map key annotations with unwrapped values cannot use arrays", element);
- }
- } else if (autoAnnotationIsMissing()) {
- builder.addError(
- "@AutoAnnotation is a necessary dependency if @MapKey(unwrapValue = false). Add a "
- + "dependency on com.google.auto.value:auto-value:<current version>");
- }
- return builder.build();
- }
-
- private boolean autoAnnotationIsMissing() {
- return elements.getTypeElement("com.google.auto.value.AutoAnnotation") == null;
- }
-}
diff --git a/java/dagger/internal/codegen/validation/MembersInjectionValidator.java b/java/dagger/internal/codegen/validation/MembersInjectionValidator.java
deleted file mode 100644
index afa6270..0000000
--- a/java/dagger/internal/codegen/validation/MembersInjectionValidator.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkArgument;
-
-import com.google.auto.common.MoreElements;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-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.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVisitor;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/**
- * Validates members injection requests (members injection methods on components and requests for
- * {@code MembersInjector<Foo>}).
- */
-final class MembersInjectionValidator {
- private final InjectionAnnotations injectionAnnotations;
-
- @Inject
- MembersInjectionValidator(InjectionAnnotations injectionAnnotations) {
- this.injectionAnnotations = injectionAnnotations;
- }
-
- /** Reports errors if a request for a {@code MembersInjector<Foo>}) is invalid. */
- ValidationReport<Element> validateMembersInjectionRequest(
- Element requestElement, TypeMirror membersInjectedType) {
- ValidationReport.Builder<Element> report = ValidationReport.about(requestElement);
- checkQualifiers(report, requestElement);
- membersInjectedType.accept(VALIDATE_MEMBERS_INJECTED_TYPE, report);
- return report.build();
- }
-
- /**
- * Reports errors if a members injection method on a component is invalid.
- *
- * @throws IllegalArgumentException if the method doesn't have exactly one parameter
- */
- ValidationReport<ExecutableElement> validateMembersInjectionMethod(
- ExecutableElement method, TypeMirror membersInjectedType) {
- checkArgument(
- method.getParameters().size() == 1, "expected a method with one parameter: %s", method);
-
- ValidationReport.Builder<ExecutableElement> report = ValidationReport.about(method);
- checkQualifiers(report, method);
- checkQualifiers(report, method.getParameters().get(0));
- membersInjectedType.accept(VALIDATE_MEMBERS_INJECTED_TYPE, report);
- return report.build();
- }
-
- private void checkQualifiers(ValidationReport.Builder<?> report, Element element) {
- for (AnnotationMirror qualifier : injectionAnnotations.getQualifiers(element)) {
- report.addError("Cannot inject members into qualified types", element, qualifier);
- break; // just report on the first qualifier, in case there is more than one
- }
- }
-
- private static final TypeVisitor<Void, ValidationReport.Builder<?>>
- VALIDATE_MEMBERS_INJECTED_TYPE =
- new SimpleTypeVisitor8<Void, ValidationReport.Builder<?>>() {
- // Only declared types can be members-injected.
- @Override
- protected Void defaultAction(TypeMirror type, ValidationReport.Builder<?> report) {
- report.addError("Cannot inject members into " + type);
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType type, ValidationReport.Builder<?> report) {
- if (type.getTypeArguments().isEmpty()) {
- // If the type is the erasure of a generic type, that means the user referred to
- // Foo<T> as just 'Foo', which we don't allow. (This is a judgement call; we
- // *could* allow it and instantiate the type bounds, but we don't.)
- if (!MoreElements.asType(type.asElement()).getTypeParameters().isEmpty()) {
- report.addError("Cannot inject members into raw type " + type);
- }
- } else {
- // If the type has arguments, validate that each type argument is declared.
- // Otherwise the type argument may be a wildcard (or other type), and we can't
- // resolve that to actual types. For array type arguments, validate the type of the
- // array.
- for (TypeMirror arg : type.getTypeArguments()) {
- if (!arg.accept(DECLARED_OR_ARRAY, null)) {
- report.addError(
- "Cannot inject members into types with unbounded type arguments: " + type);
- }
- }
- }
- return null;
- }
- };
-
- // TODO(dpb): Can this be inverted so it explicitly rejects wildcards or type variables?
- // This logic is hard to describe.
- private static final TypeVisitor<Boolean, Void> DECLARED_OR_ARRAY =
- new SimpleTypeVisitor8<Boolean, Void>(false) {
- @Override
- public Boolean visitArray(ArrayType arrayType, Void p) {
- return arrayType
- .getComponentType()
- .accept(
- new SimpleTypeVisitor8<Boolean, Void>(false) {
- @Override
- public Boolean visitDeclared(DeclaredType declaredType, Void p) {
- for (TypeMirror arg : declaredType.getTypeArguments()) {
- if (!arg.accept(this, null)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Boolean visitArray(ArrayType arrayType, Void p) {
- return arrayType.getComponentType().accept(this, null);
- }
-
- @Override
- public Boolean visitPrimitive(PrimitiveType primitiveType, Void p) {
- return true;
- }
- },
- null);
- }
-
- @Override
- public Boolean visitDeclared(DeclaredType t, Void p) {
- return true;
- }
- };
-}
diff --git a/java/dagger/internal/codegen/validation/ModuleValidator.java b/java/dagger/internal/codegen/validation/ModuleValidator.java
deleted file mode 100644
index 02ac06a..0000000
--- a/java/dagger/internal/codegen/validation/ModuleValidator.java
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.auto.common.AnnotationMirrors.getAnnotatedAnnotations;
-import static com.google.auto.common.MoreElements.isAnnotationPresent;
-import static com.google.auto.common.MoreTypes.asTypeElement;
-import static com.google.auto.common.Visibility.PRIVATE;
-import static com.google.auto.common.Visibility.PUBLIC;
-import static com.google.auto.common.Visibility.effectiveVisibilityOfElement;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.base.ComponentAnnotation.componentAnnotation;
-import static dagger.internal.codegen.base.ComponentAnnotation.isComponentAnnotation;
-import static dagger.internal.codegen.base.ComponentAnnotation.subcomponentAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.isModuleAnnotation;
-import static dagger.internal.codegen.base.ModuleAnnotation.moduleAnnotation;
-import static dagger.internal.codegen.base.MoreAnnotationMirrors.simpleName;
-import static dagger.internal.codegen.base.MoreAnnotationValues.asType;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.getCreatorAnnotations;
-import static dagger.internal.codegen.binding.ConfigurationAnnotations.getSubcomponentCreator;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static dagger.internal.codegen.langmodel.DaggerElements.getAnnotationMirror;
-import static dagger.internal.codegen.langmodel.DaggerElements.isAnyAnnotationPresent;
-import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreElements;
-import com.google.auto.common.MoreTypes;
-import com.google.auto.common.Visibility;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.MultimapBuilder;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.Sets;
-import com.google.errorprone.annotations.FormatMethod;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.internal.codegen.base.ModuleAnnotation;
-import dagger.internal.codegen.binding.BindingGraphFactory;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
-import dagger.internal.codegen.binding.ComponentDescriptorFactory;
-import dagger.internal.codegen.binding.MethodSignatureFormatter;
-import dagger.internal.codegen.binding.ModuleKind;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingGraph;
-import dagger.producers.ProducerModule;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Scope;
-import javax.inject.Singleton;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleAnnotationValueVisitor8;
-import javax.lang.model.util.SimpleTypeVisitor8;
-
-/** A {@linkplain ValidationReport validator} for {@link Module}s or {@link ProducerModule}s. */
-@Singleton
-public final class ModuleValidator {
- private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_TYPES =
- ImmutableSet.of(Subcomponent.class, ProductionSubcomponent.class);
- private static final ImmutableSet<Class<? extends Annotation>> SUBCOMPONENT_CREATOR_TYPES =
- ImmutableSet.of(
- Subcomponent.Builder.class,
- Subcomponent.Factory.class,
- ProductionSubcomponent.Builder.class,
- ProductionSubcomponent.Factory.class);
- private static final Optional<Class<?>> ANDROID_PROCESSOR;
- private static final String CONTRIBUTES_ANDROID_INJECTOR_NAME =
- "dagger.android.ContributesAndroidInjector";
- private static final String ANDROID_PROCESSOR_NAME = "dagger.android.processor.AndroidProcessor";
-
- static {
- Class<?> clazz;
- try {
- clazz = Class.forName(ANDROID_PROCESSOR_NAME, false, ModuleValidator.class.getClassLoader());
- } catch (ClassNotFoundException ignored) {
- clazz = null;
- }
- ANDROID_PROCESSOR = Optional.ofNullable(clazz);
- }
-
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final AnyBindingMethodValidator anyBindingMethodValidator;
- private final MethodSignatureFormatter methodSignatureFormatter;
- private final ComponentDescriptorFactory componentDescriptorFactory;
- private final BindingGraphFactory bindingGraphFactory;
- private final BindingGraphValidator bindingGraphValidator;
- private final KotlinMetadataUtil metadataUtil;
- private final Map<TypeElement, ValidationReport<TypeElement>> cache = new HashMap<>();
- private final Set<TypeElement> knownModules = new HashSet<>();
-
- @Inject
- ModuleValidator(
- DaggerTypes types,
- DaggerElements elements,
- AnyBindingMethodValidator anyBindingMethodValidator,
- MethodSignatureFormatter methodSignatureFormatter,
- ComponentDescriptorFactory componentDescriptorFactory,
- BindingGraphFactory bindingGraphFactory,
- BindingGraphValidator bindingGraphValidator,
- KotlinMetadataUtil metadataUtil) {
- this.types = types;
- this.elements = elements;
- this.anyBindingMethodValidator = anyBindingMethodValidator;
- this.methodSignatureFormatter = methodSignatureFormatter;
- this.componentDescriptorFactory = componentDescriptorFactory;
- this.bindingGraphFactory = bindingGraphFactory;
- this.bindingGraphValidator = bindingGraphValidator;
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Adds {@code modules} to the set of module types that will be validated during this compilation
- * step. If a component or module includes a module that is not in this set, that included module
- * is assumed to be valid because it was processed in a previous compilation step. If it were
- * invalid, that previous compilation step would have failed and blocked this one.
- *
- * <p>This logic depends on this method being called before {@linkplain #validate(TypeElement)
- * validating} any module or {@linkplain #validateReferencedModules(TypeElement, AnnotationMirror,
- * ImmutableSet, Set) component}.
- */
- public void addKnownModules(Collection<TypeElement> modules) {
- knownModules.addAll(modules);
- }
-
- /** Returns a validation report for a module type. */
- public ValidationReport<TypeElement> validate(TypeElement module) {
- return validate(module, new HashSet<>());
- }
-
- private ValidationReport<TypeElement> validate(
- TypeElement module, Set<TypeElement> visitedModules) {
- if (visitedModules.add(module)) {
- return reentrantComputeIfAbsent(cache, module, m -> validateUncached(module, visitedModules));
- }
- return ValidationReport.about(module).build();
- }
-
- private ValidationReport<TypeElement> validateUncached(
- TypeElement module, Set<TypeElement> visitedModules) {
- ValidationReport.Builder<TypeElement> builder = ValidationReport.about(module);
- ModuleKind moduleKind = ModuleKind.forAnnotatedElement(module).get();
- TypeElement contributesAndroidInjectorElement =
- elements.getTypeElement(CONTRIBUTES_ANDROID_INJECTOR_NAME);
- TypeMirror contributesAndroidInjector =
- contributesAndroidInjectorElement != null
- ? contributesAndroidInjectorElement.asType()
- : null;
- List<ExecutableElement> moduleMethods = methodsIn(module.getEnclosedElements());
- List<ExecutableElement> bindingMethods = new ArrayList<>();
- for (ExecutableElement moduleMethod : moduleMethods) {
- if (anyBindingMethodValidator.isBindingMethod(moduleMethod)) {
- builder.addSubreport(anyBindingMethodValidator.validate(moduleMethod));
- bindingMethods.add(moduleMethod);
- }
-
- for (AnnotationMirror annotation : moduleMethod.getAnnotationMirrors()) {
- if (!ANDROID_PROCESSOR.isPresent()
- && MoreTypes.equivalence()
- .equivalent(contributesAndroidInjector, annotation.getAnnotationType())) {
- builder.addSubreport(
- ValidationReport.about(moduleMethod)
- .addError(
- String.format(
- "@%s was used, but %s was not found on the processor path",
- CONTRIBUTES_ANDROID_INJECTOR_NAME, ANDROID_PROCESSOR_NAME))
- .build());
- break;
- }
- }
- }
-
- if (bindingMethods.stream()
- .map(ModuleMethodKind::ofMethod)
- .collect(toImmutableSet())
- .containsAll(
- EnumSet.of(ModuleMethodKind.ABSTRACT_DECLARATION, ModuleMethodKind.INSTANCE_BINDING))) {
- builder.addError(
- String.format(
- "A @%s may not contain both non-static and abstract binding methods",
- moduleKind.annotation().getSimpleName()));
- }
-
- validateModuleVisibility(module, moduleKind, builder);
-
- ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName =
- Multimaps.index(bindingMethods, ExecutableElement::getSimpleName);
-
- validateMethodsWithSameName(builder, bindingMethodsByName);
- if (module.getKind() != ElementKind.INTERFACE) {
- validateBindingMethodOverrides(
- module,
- builder,
- Multimaps.index(moduleMethods, ExecutableElement::getSimpleName),
- bindingMethodsByName);
- }
- validateModifiers(module, builder);
- validateReferencedModules(module, moduleKind, visitedModules, builder);
- validateReferencedSubcomponents(module, moduleKind, builder);
- validateNoScopeAnnotationsOnModuleElement(module, moduleKind, builder);
- validateSelfCycles(module, builder);
- if (metadataUtil.hasEnclosedCompanionObject(module)) {
- validateCompanionModule(module, builder);
- }
-
- if (builder.build().isClean()
- && bindingGraphValidator.shouldDoFullBindingGraphValidation(module)) {
- validateModuleBindings(module, builder);
- }
-
- return builder.build();
- }
-
- private void validateReferencedSubcomponents(
- final TypeElement subject,
- ModuleKind moduleKind,
- final ValidationReport.Builder<TypeElement> builder) {
- // TODO(ronshapiro): use validateTypesAreDeclared when it is checked in
- ModuleAnnotation moduleAnnotation = moduleAnnotation(moduleKind.getModuleAnnotation(subject));
- for (AnnotationValue subcomponentAttribute :
- moduleAnnotation.subcomponentsAsAnnotationValues()) {
- asType(subcomponentAttribute)
- .accept(
- new SimpleTypeVisitor8<Void, Void>() {
- @Override
- protected Void defaultAction(TypeMirror e, Void aVoid) {
- builder.addError(
- e + " is not a valid subcomponent type",
- subject,
- moduleAnnotation.annotation(),
- subcomponentAttribute);
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType declaredType, Void aVoid) {
- TypeElement attributeType = asTypeElement(declaredType);
- if (isAnyAnnotationPresent(attributeType, SUBCOMPONENT_TYPES)) {
- validateSubcomponentHasBuilder(
- attributeType, moduleAnnotation.annotation(), builder);
- } else {
- builder.addError(
- isAnyAnnotationPresent(attributeType, SUBCOMPONENT_CREATOR_TYPES)
- ? moduleSubcomponentsIncludesCreator(attributeType)
- : moduleSubcomponentsIncludesNonSubcomponent(attributeType),
- subject,
- moduleAnnotation.annotation(),
- subcomponentAttribute);
- }
-
- return null;
- }
- },
- null);
- }
- }
-
- private static String moduleSubcomponentsIncludesNonSubcomponent(TypeElement notSubcomponent) {
- return notSubcomponent.getQualifiedName()
- + " is not a @Subcomponent or @ProductionSubcomponent";
- }
-
- private static String moduleSubcomponentsIncludesCreator(
- TypeElement moduleSubcomponentsAttribute) {
- TypeElement subcomponentType =
- MoreElements.asType(moduleSubcomponentsAttribute.getEnclosingElement());
- ComponentCreatorAnnotation creatorAnnotation =
- getOnlyElement(getCreatorAnnotations(moduleSubcomponentsAttribute));
- return String.format(
- "%s is a @%s.%s. Did you mean to use %s?",
- moduleSubcomponentsAttribute.getQualifiedName(),
- subcomponentAnnotation(subcomponentType).get().simpleName(),
- creatorAnnotation.creatorKind().typeName(),
- subcomponentType.getQualifiedName());
- }
-
- private static void validateSubcomponentHasBuilder(
- TypeElement subcomponentAttribute,
- AnnotationMirror moduleAnnotation,
- ValidationReport.Builder<TypeElement> builder) {
- if (getSubcomponentCreator(subcomponentAttribute).isPresent()) {
- return;
- }
- builder.addError(
- moduleSubcomponentsDoesntHaveCreator(subcomponentAttribute, moduleAnnotation),
- builder.getSubject(),
- moduleAnnotation);
- }
-
- private static String moduleSubcomponentsDoesntHaveCreator(
- TypeElement subcomponent, AnnotationMirror moduleAnnotation) {
- return String.format(
- "%1$s doesn't have a @%2$s.Builder or @%2$s.Factory, which is required when used with "
- + "@%3$s.subcomponents",
- subcomponent.getQualifiedName(),
- subcomponentAnnotation(subcomponent).get().simpleName(),
- simpleName(moduleAnnotation));
- }
-
- enum ModuleMethodKind {
- ABSTRACT_DECLARATION,
- INSTANCE_BINDING,
- STATIC_BINDING,
- ;
-
- static ModuleMethodKind ofMethod(ExecutableElement moduleMethod) {
- if (moduleMethod.getModifiers().contains(STATIC)) {
- return STATIC_BINDING;
- } else if (moduleMethod.getModifiers().contains(ABSTRACT)) {
- return ABSTRACT_DECLARATION;
- } else {
- return INSTANCE_BINDING;
- }
- }
- }
-
- private void validateModifiers(
- TypeElement subject, ValidationReport.Builder<TypeElement> builder) {
- // This coupled with the check for abstract modules in ComponentValidator guarantees that
- // only modules without type parameters are referenced from @Component(modules={...}).
- if (!subject.getTypeParameters().isEmpty() && !subject.getModifiers().contains(ABSTRACT)) {
- builder.addError("Modules with type parameters must be abstract", subject);
- }
- }
-
- private void validateMethodsWithSameName(
- ValidationReport.Builder<TypeElement> builder,
- ListMultimap<Name, ExecutableElement> bindingMethodsByName) {
- for (Entry<Name, Collection<ExecutableElement>> entry :
- bindingMethodsByName.asMap().entrySet()) {
- if (entry.getValue().size() > 1) {
- for (ExecutableElement offendingMethod : entry.getValue()) {
- builder.addError(
- String.format(
- "Cannot have more than one binding method with the same name in a single module"),
- offendingMethod);
- }
- }
- }
- }
-
- private void validateReferencedModules(
- TypeElement subject,
- ModuleKind moduleKind,
- Set<TypeElement> visitedModules,
- ValidationReport.Builder<TypeElement> builder) {
- // Validate that all the modules we include are valid for inclusion.
- AnnotationMirror mirror = moduleKind.getModuleAnnotation(subject);
- builder.addSubreport(
- validateReferencedModules(
- subject, mirror, moduleKind.legalIncludedModuleKinds(), visitedModules));
- }
-
- /**
- * Validates modules included in a given module or installed in a given component.
- *
- * <p>Checks that the referenced modules are non-generic types annotated with {@code @Module} or
- * {@code @ProducerModule}.
- *
- * <p>If the referenced module is in the {@linkplain #addKnownModules(Collection) known modules
- * set} and has errors, reports an error at that module's inclusion.
- *
- * @param annotatedType the annotated module or component
- * @param annotation the annotation specifying the referenced modules ({@code @Component},
- * {@code @ProductionComponent}, {@code @Subcomponent}, {@code @ProductionSubcomponent},
- * {@code @Module}, or {@code @ProducerModule})
- * @param validModuleKinds the module kinds that the annotated type is permitted to include
- */
- ValidationReport<TypeElement> validateReferencedModules(
- TypeElement annotatedType,
- AnnotationMirror annotation,
- ImmutableSet<ModuleKind> validModuleKinds,
- Set<TypeElement> visitedModules) {
- ValidationReport.Builder<TypeElement> subreport = ValidationReport.about(annotatedType);
- ImmutableSet<? extends Class<? extends Annotation>> validModuleAnnotations =
- validModuleKinds.stream().map(ModuleKind::annotation).collect(toImmutableSet());
-
- for (AnnotationValue includedModule : getModules(annotation)) {
- asType(includedModule)
- .accept(
- new SimpleTypeVisitor8<Void, Void>() {
- @Override
- protected Void defaultAction(TypeMirror mirror, Void p) {
- reportError("%s is not a valid module type.", mirror);
- return null;
- }
-
- @Override
- public Void visitDeclared(DeclaredType t, Void p) {
- TypeElement module = MoreElements.asType(t.asElement());
- if (!t.getTypeArguments().isEmpty()) {
- reportError(
- "%s is listed as a module, but has type parameters",
- module.getQualifiedName());
- }
- if (!isAnyAnnotationPresent(module, validModuleAnnotations)) {
- reportError(
- "%s is listed as a module, but is not annotated with %s",
- module.getQualifiedName(),
- (validModuleAnnotations.size() > 1 ? "one of " : "")
- + validModuleAnnotations.stream()
- .map(otherClass -> "@" + otherClass.getSimpleName())
- .collect(joining(", ")));
- } else if (knownModules.contains(module)
- && !validate(module, visitedModules).isClean()) {
- reportError("%s has errors", module.getQualifiedName());
- }
- if (metadataUtil.isCompanionObjectClass(module)) {
- reportError(
- "%s is listed as a module, but it is a companion object class. "
- + "Add @Module to the enclosing class and reference that instead.",
- module.getQualifiedName());
- }
- return null;
- }
-
- @FormatMethod
- private void reportError(String format, Object... args) {
- subreport.addError(
- String.format(format, args), annotatedType, annotation, includedModule);
- }
- },
- null);
- }
- return subreport.build();
- }
-
- private static ImmutableList<AnnotationValue> getModules(AnnotationMirror annotation) {
- if (isModuleAnnotation(annotation)) {
- return moduleAnnotation(annotation).includesAsAnnotationValues();
- }
- if (isComponentAnnotation(annotation)) {
- return componentAnnotation(annotation).moduleValues();
- }
- throw new IllegalArgumentException(String.format("unsupported annotation: %s", annotation));
- }
-
- private void validateBindingMethodOverrides(
- TypeElement subject,
- ValidationReport.Builder<TypeElement> builder,
- ImmutableListMultimap<Name, ExecutableElement> moduleMethodsByName,
- ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName) {
- // For every binding method, confirm it overrides nothing *and* nothing overrides it.
- // Consider the following hierarchy:
- // class Parent {
- // @Provides Foo a() {}
- // @Provides Foo b() {}
- // Foo c() {}
- // }
- // class Child extends Parent {
- // @Provides Foo a() {}
- // Foo b() {}
- // @Provides Foo c() {}
- // }
- // In each of those cases, we want to fail. "a" is clear, "b" because Child is overriding
- // a binding method in Parent, and "c" because Child is defining a binding method that overrides
- // Parent.
- TypeElement currentClass = subject;
- TypeMirror objectType = elements.getTypeElement(Object.class).asType();
- // We keep track of methods that failed so we don't spam with multiple failures.
- Set<ExecutableElement> failedMethods = Sets.newHashSet();
- ListMultimap<Name, ExecutableElement> allMethodsByName =
- MultimapBuilder.hashKeys().arrayListValues().build(moduleMethodsByName);
-
- while (!types.isSameType(currentClass.getSuperclass(), objectType)) {
- currentClass = MoreElements.asType(types.asElement(currentClass.getSuperclass()));
- List<ExecutableElement> superclassMethods = methodsIn(currentClass.getEnclosedElements());
- for (ExecutableElement superclassMethod : superclassMethods) {
- Name name = superclassMethod.getSimpleName();
- // For each method in the superclass, confirm our binding methods don't override it
- for (ExecutableElement bindingMethod : bindingMethodsByName.get(name)) {
- if (failedMethods.add(bindingMethod)
- && elements.overrides(bindingMethod, superclassMethod, subject)) {
- builder.addError(
- String.format(
- "Binding methods may not override another method. Overrides: %s",
- methodSignatureFormatter.format(superclassMethod)),
- bindingMethod);
- }
- }
- // For each binding method in superclass, confirm our methods don't override it.
- if (anyBindingMethodValidator.isBindingMethod(superclassMethod)) {
- for (ExecutableElement method : allMethodsByName.get(name)) {
- if (failedMethods.add(method)
- && elements.overrides(method, superclassMethod, subject)) {
- builder.addError(
- String.format(
- "Binding methods may not be overridden in modules. Overrides: %s",
- methodSignatureFormatter.format(superclassMethod)),
- method);
- }
- }
- }
- allMethodsByName.put(superclassMethod.getSimpleName(), superclassMethod);
- }
- }
- }
-
- private void validateModuleVisibility(
- final TypeElement moduleElement,
- ModuleKind moduleKind,
- final ValidationReport.Builder<?> reportBuilder) {
- ModuleAnnotation moduleAnnotation =
- moduleAnnotation(getAnnotationMirror(moduleElement, moduleKind.annotation()).get());
- Visibility moduleVisibility = Visibility.ofElement(moduleElement);
- Visibility moduleEffectiveVisibility = effectiveVisibilityOfElement(moduleElement);
- if (moduleVisibility.equals(PRIVATE)) {
- reportBuilder.addError("Modules cannot be private.", moduleElement);
- } else if (moduleEffectiveVisibility.equals(PRIVATE)) {
- reportBuilder.addError("Modules cannot be enclosed in private types.", moduleElement);
- }
-
- switch (moduleElement.getNestingKind()) {
- case ANONYMOUS:
- throw new IllegalStateException("Can't apply @Module to an anonymous class");
- case LOCAL:
- throw new IllegalStateException("Local classes shouldn't show up in the processor");
- case MEMBER:
- case TOP_LEVEL:
- if (moduleEffectiveVisibility.equals(PUBLIC)) {
- ImmutableSet<TypeElement> invalidVisibilityIncludes =
- getModuleIncludesWithInvalidVisibility(moduleAnnotation);
- if (!invalidVisibilityIncludes.isEmpty()) {
- reportBuilder.addError(
- String.format(
- "This module is public, but it includes non-public (or effectively non-public) "
- + "modules (%s) that have non-static, non-abstract binding methods. Either "
- + "reduce the visibility of this module, make the included modules "
- + "public, or make all of the binding methods on the included modules "
- + "abstract or static.",
- formatListForErrorMessage(invalidVisibilityIncludes.asList())),
- moduleElement);
- }
- }
- }
- }
-
- private ImmutableSet<TypeElement> getModuleIncludesWithInvalidVisibility(
- ModuleAnnotation moduleAnnotation) {
- return moduleAnnotation.includes().stream()
- .filter(include -> !effectiveVisibilityOfElement(include).equals(PUBLIC))
- .filter(this::requiresModuleInstance)
- .collect(toImmutableSet());
- }
-
- /**
- * Returns {@code true} if a module instance is needed for any of the binding methods on the given
- * {@code module}. This is the case when the module has any binding methods that are neither
- * {@code abstract} nor {@code static}. Alternatively, if the module is a Kotlin Object then the
- * binding methods are considered {@code static}, requiring no module instance.
- */
- private boolean requiresModuleInstance(TypeElement module) {
- // Note elements.getAllMembers(module) rather than module.getEnclosedElements() here: we need to
- // include binding methods declared in supertypes because unlike most other validations being
- // done in this class, which assume that supertype binding methods will be validated in a
- // separate call to the validator since the supertype itself must be a @Module, we need to look
- // at all the binding methods in the module's type hierarchy here.
- boolean isKotlinObject =
- metadataUtil.isObjectClass(module) || metadataUtil.isCompanionObjectClass(module);
- if (isKotlinObject) {
- return false;
- }
- return methodsIn(elements.getAllMembers(module)).stream()
- .filter(anyBindingMethodValidator::isBindingMethod)
- .map(ExecutableElement::getModifiers)
- .anyMatch(modifiers -> !modifiers.contains(ABSTRACT) && !modifiers.contains(STATIC));
- }
-
- private void validateNoScopeAnnotationsOnModuleElement(
- TypeElement module, ModuleKind moduleKind, ValidationReport.Builder<TypeElement> report) {
- for (AnnotationMirror scope : getAnnotatedAnnotations(module, Scope.class)) {
- report.addError(
- String.format(
- "@%ss cannot be scoped. Did you mean to scope a method instead?",
- moduleKind.annotation().getSimpleName()),
- module,
- scope);
- }
- }
-
- private void validateSelfCycles(
- TypeElement module, ValidationReport.Builder<TypeElement> builder) {
- ModuleAnnotation moduleAnnotation = moduleAnnotation(module).get();
- moduleAnnotation
- .includesAsAnnotationValues()
- .forEach(
- value ->
- value.accept(
- new SimpleAnnotationValueVisitor8<Void, Void>() {
- @Override
- public Void visitType(TypeMirror includedModule, Void aVoid) {
- if (MoreTypes.equivalence().equivalent(module.asType(), includedModule)) {
- String moduleKind = moduleAnnotation.annotationName();
- builder.addError(
- String.format("@%s cannot include themselves.", moduleKind),
- module,
- moduleAnnotation.annotation(),
- value);
- }
- return null;
- }
- },
- null));
- }
-
- private void validateCompanionModule(
- TypeElement module, ValidationReport.Builder<TypeElement> builder) {
- checkArgument(metadataUtil.hasEnclosedCompanionObject(module));
- TypeElement companionModule = metadataUtil.getEnclosedCompanionObject(module);
- List<ExecutableElement> companionModuleMethods =
- methodsIn(companionModule.getEnclosedElements());
- List<ExecutableElement> companionBindingMethods = new ArrayList<>();
- for (ExecutableElement companionModuleMethod : companionModuleMethods) {
- if (anyBindingMethodValidator.isBindingMethod(companionModuleMethod)) {
- builder.addSubreport(anyBindingMethodValidator.validate(companionModuleMethod));
- companionBindingMethods.add(companionModuleMethod);
- }
-
- // On normal modules only overriding other binding methods is disallowed, but for companion
- // objects we are prohibiting any override. For this can rely on checking the @Override
- // annotation since the Kotlin compiler will always produce them for overriding methods.
- if (isAnnotationPresent(companionModuleMethod, Override.class)) {
- builder.addError(
- "Binding method in companion object may not override another method.",
- companionModuleMethod);
- }
-
- // TODO(danysantiago): Be strict about the usage of @JvmStatic, i.e. tell user to remove it.
- }
-
- ImmutableListMultimap<Name, ExecutableElement> bindingMethodsByName =
- Multimaps.index(companionBindingMethods, ExecutableElement::getSimpleName);
- validateMethodsWithSameName(builder, bindingMethodsByName);
-
- // If there are provision methods, then check the visibility. Companion objects are composed by
- // an inner class and a static field, it is not enough to check the visibility on the type
- // element or the field, therefore we check the metadata.
- if (!companionBindingMethods.isEmpty() && metadataUtil.isVisibilityPrivate(companionModule)) {
- builder.addError(
- "A Companion Module with binding methods cannot be private.", companionModule);
- }
- }
-
- private void validateModuleBindings(
- TypeElement module, ValidationReport.Builder<TypeElement> report) {
- BindingGraph bindingGraph =
- bindingGraphFactory.create(
- componentDescriptorFactory.moduleComponentDescriptor(module), true)
- .topLevelBindingGraph();
- if (!bindingGraphValidator.isValid(bindingGraph)) {
- // Since the validator uses a DiagnosticReporter to report errors, the ValdiationReport won't
- // have any Items for them. We have to tell the ValidationReport that some errors were
- // reported for the subject.
- report.markDirty();
- }
- }
-
- private static String formatListForErrorMessage(List<?> things) {
- switch (things.size()) {
- case 0:
- return "";
- case 1:
- return things.get(0).toString();
- default:
- StringBuilder output = new StringBuilder();
- Joiner.on(", ").appendTo(output, things.subList(0, things.size() - 1));
- output.append(" and ").append(things.get(things.size() - 1));
- return output.toString();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java b/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java
deleted file mode 100644
index 2c72e5f..0000000
--- a/java/dagger/internal/codegen/validation/MonitoringModuleGenerator.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.validation;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCTION_COMPONENT_MONITOR_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-import static dagger.internal.codegen.javapoet.TypeNames.setOf;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.SourceFiles;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.multibindings.Multibinds;
-import dagger.producers.ProductionScope;
-import dagger.producers.monitoring.ProductionComponentMonitor;
-import dagger.producers.monitoring.internal.Monitors;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-
-/** Generates a monitoring module for use with production components. */
-final class MonitoringModuleGenerator extends SourceFileGenerator<TypeElement> {
-
- @Inject
- MonitoringModuleGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
- super(filer, elements, sourceVersion);
- }
-
- @Override
- public ClassName nameGeneratedType(TypeElement componentElement) {
- return SourceFiles.generatedMonitoringModuleName(componentElement);
- }
-
- @Override
- public Element originatingElement(TypeElement componentElement) {
- return componentElement;
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(TypeElement componentElement) {
- return Optional.of(
- classBuilder(nameGeneratedType(componentElement))
- .addAnnotation(Module.class)
- .addModifiers(ABSTRACT)
- .addMethod(privateConstructor())
- .addMethod(setOfFactories())
- .addMethod(monitor(componentElement)));
- }
-
- private MethodSpec privateConstructor() {
- return constructorBuilder().addModifiers(PRIVATE).build();
- }
-
- private MethodSpec setOfFactories() {
- return methodBuilder("setOfFactories")
- .addAnnotation(Multibinds.class)
- .addModifiers(ABSTRACT)
- .returns(setOf(PRODUCTION_COMPONENT_MONITOR_FACTORY))
- .build();
- }
-
- private MethodSpec monitor(TypeElement componentElement) {
- return methodBuilder("monitor")
- .returns(ProductionComponentMonitor.class)
- .addModifiers(STATIC)
- .addAnnotation(Provides.class)
- .addAnnotation(ProductionScope.class)
- .addParameter(providerOf(ClassName.get(componentElement.asType())), "component")
- .addParameter(
- providerOf(setOf(PRODUCTION_COMPONENT_MONITOR_FACTORY)), "factories")
- .addStatement(
- "return $T.createMonitorForComponent(component, factories)", Monitors.class)
- .build();
- }
-}
diff --git a/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java b/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java
deleted file mode 100644
index 5d4c64e..0000000
--- a/java/dagger/internal/codegen/validation/MonitoringModuleProcessingStep.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.validation;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import dagger.producers.ProductionComponent;
-import dagger.producers.ProductionSubcomponent;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-
-/**
- * A processing step that is responsible for generating a special module for a {@link
- * ProductionComponent} or {@link ProductionSubcomponent}.
- */
-public final class MonitoringModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement> {
- private final Messager messager;
- private final MonitoringModuleGenerator monitoringModuleGenerator;
-
- @Inject
- MonitoringModuleProcessingStep(
- Messager messager, MonitoringModuleGenerator monitoringModuleGenerator) {
- super(MoreElements::asType);
- this.messager = messager;
- this.monitoringModuleGenerator = monitoringModuleGenerator;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(ProductionComponent.class, ProductionSubcomponent.class);
- }
-
- @Override
- protected void process(
- TypeElement element, ImmutableSet<Class<? extends Annotation>> annotations) {
- monitoringModuleGenerator.generate(MoreElements.asType(element), messager);
- }
-}
diff --git a/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java b/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java
deleted file mode 100644
index fd75eac..0000000
--- a/java/dagger/internal/codegen/validation/MultibindingAnnotationsProcessingStep.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 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.langmodel.DaggerElements.getAnnotationMirror;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableSet;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.IntoSet;
-import java.lang.annotation.Annotation;
-import java.util.Set;
-import javax.annotation.processing.Messager;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-
-/**
- * Processing step that verifies that {@link IntoSet}, {@link ElementsIntoSet} and {@link IntoMap}
- * are not present on non-binding methods.
- */
-public final class MultibindingAnnotationsProcessingStep
- extends TypeCheckingProcessingStep<ExecutableElement> {
- private final AnyBindingMethodValidator anyBindingMethodValidator;
- private final Messager messager;
-
- @Inject
- MultibindingAnnotationsProcessingStep(
- AnyBindingMethodValidator anyBindingMethodValidator, Messager messager) {
- super(MoreElements::asExecutable);
- this.anyBindingMethodValidator = anyBindingMethodValidator;
- this.messager = messager;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotations() {
- return ImmutableSet.of(IntoSet.class, ElementsIntoSet.class, IntoMap.class);
- }
-
- @Override
- protected void process(
- ExecutableElement method, ImmutableSet<Class<? extends Annotation>> annotations) {
- if (!anyBindingMethodValidator.isBindingMethod(method)) {
- annotations.forEach(
- annotation ->
- messager.printMessage(
- ERROR,
- "Multibinding annotations may only be on @Provides, @Produces, or @Binds methods",
- method,
- getAnnotationMirror(method, annotation).get()));
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java b/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
deleted file mode 100644
index 8829667..0000000
--- a/java/dagger/internal/codegen/validation/MultibindsMethodValidator.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2016 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.base.FrameworkTypes.isFrameworkType;
-import static dagger.internal.codegen.validation.BindingElementValidator.AllowsMultibindings.NO_MULTIBINDINGS;
-import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.NO_SCOPING;
-import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_ABSTRACT;
-import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.NO_EXCEPTIONS;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.multibindings.Multibinds;
-import dagger.producers.ProducerModule;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A validator for {@link Multibinds} methods. */
-class MultibindsMethodValidator extends BindingMethodValidator {
-
- /** Creates a validator for {@link Multibinds @Multibinds} methods. */
- @Inject
- MultibindsMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
- DependencyRequestValidator dependencyRequestValidator,
- InjectionAnnotations injectionAnnotations) {
- super(
- elements,
- types,
- kotlinMetadataUtil,
- Multibinds.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
- dependencyRequestValidator,
- MUST_BE_ABSTRACT,
- NO_EXCEPTIONS,
- NO_MULTIBINDINGS,
- NO_SCOPING,
- injectionAnnotations);
- }
-
- @Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected void checkParameters() {
- if (!element.getParameters().isEmpty()) {
- report.addError(bindingMethods("cannot have parameters"));
- }
- }
-
- /** Adds an error unless the method returns a {@code Map<K, V>} or {@code Set<T>}. */
- @Override
- protected void checkType() {
- if (!isPlainMap(element.getReturnType())
- && !isPlainSet(element.getReturnType())) {
- report.addError(bindingMethods("must return Map<K, V> or Set<T>"));
- }
- }
-
- private boolean isPlainMap(TypeMirror returnType) {
- if (!MapType.isMap(returnType)) {
- return false;
- }
- MapType mapType = MapType.from(returnType);
- return !mapType.isRawType()
- && MoreTypes.isType(mapType.valueType()) // No wildcards.
- && !isFrameworkType(mapType.valueType());
- }
-
- private boolean isPlainSet(TypeMirror returnType) {
- if (!SetType.isSet(returnType)) {
- return false;
- }
- SetType setType = SetType.from(returnType);
- return !setType.isRawType()
- && MoreTypes.isType(setType.elementType()) // No wildcards.
- && !isFrameworkType(setType.elementType());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/PackageNameCompressor.java b/java/dagger/internal/codegen/validation/PackageNameCompressor.java
deleted file mode 100644
index 6b7c720..0000000
--- a/java/dagger/internal/codegen/validation/PackageNameCompressor.java
+++ /dev/null
@@ -1,181 +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.internal.codegen.validation;
-
-import static java.util.Comparator.comparing;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Munges an error message to remove/shorten package names and adds a legend at the end.
- */
-final class PackageNameCompressor {
-
- static final String LEGEND_HEADER =
- "\n\n======================\nFull classname legend:\n======================\n";
- static final String LEGEND_FOOTER =
- "========================\nEnd of classname legend:\n========================\n";
-
- private static final ImmutableSet<String> PACKAGES_SKIPPED_IN_LEGEND = ImmutableSet.of(
- "java.lang.",
- "java.util.");
-
- private static final Splitter PACKAGE_SPLITTER = Splitter.on('.');
-
- private static final Joiner PACKAGE_JOINER = Joiner.on('.');
-
- // TODO(erichang): Consider validating this regex by also passing in all of the known types from
- // keys, module names, component names, etc and checking against that list. This may have some
- // extra complications with taking apart types like List<Foo> to get the inner class names.
- private static final Pattern CLASSNAME_PATTERN =
- // Match lowercase package names with trailing dots. Start with a non-word character so we
- // don't match substrings in like Bar.Foo and match the ar.Foo. Start a group to not include
- // the non-word character.
- Pattern.compile("[\\W](([a-z_0-9]++[.])++"
- // Then match a name starting with an uppercase letter. This is the outer class name.
- + "[A-Z][\\w$]++)");
-
- /**
- * Compresses an error message by stripping the packages out of class names and adding them
- * to a legend at the bottom of the error.
- */
- static String compressPackagesInMessage(String input) {
- Matcher matcher = CLASSNAME_PATTERN.matcher(input);
-
- Set<String> names = new HashSet<>();
- // Find all classnames in the error. Note that if our regex isn't complete, it just means the
- // classname is left in the full form, which is a fine fallback.
- while (matcher.find()) {
- String name = matcher.group(1);
- names.add(name);
- }
- // Now dedupe any conflicts. Use a TreeMap since we're going to need the legend sorted anyway.
- // This map is from short name to full name.
- Map<String, String> replacementMap = shortenNames(names);
-
- // If we have nothing to replace, just return the original.
- if (replacementMap.isEmpty()) {
- return input;
- }
-
- // Find the longest key for building the legend
- int longestKey = replacementMap.keySet().stream().max(comparing(String::length)).get().length();
-
- String replacedString = input;
- StringBuilder legendBuilder = new StringBuilder();
- for (Map.Entry<String, String> entry : replacementMap.entrySet()) {
- String shortName = entry.getKey();
- String fullName = entry.getValue();
- // Do the replacements in the message
- replacedString = replacedString.replace(fullName, shortName);
-
- // Skip certain prefixes. We need to check the shortName for a . though in case
- // there was some type of conflict like java.util.concurrent.Future and
- // java.util.foo.Future that got shortened to concurrent.Future and foo.Future.
- // In those cases we do not want to skip the legend. We only skip if the class
- // is directly in that package.
- String prefix = fullName.substring(0, fullName.length() - shortName.length());
- if (PACKAGES_SKIPPED_IN_LEGEND.contains(prefix) && !shortName.contains(".")) {
- continue;
- }
-
- // Add to the legend
- legendBuilder
- .append(shortName)
- .append(": ")
- // Add enough spaces to adjust the columns
- .append(Strings.repeat(" ", longestKey - shortName.length()))
- .append(fullName)
- .append("\n");
- }
-
- return legendBuilder.length() == 0 ? replacedString
- : replacedString + LEGEND_HEADER + legendBuilder + LEGEND_FOOTER;
- }
-
- /**
- * Returns a map from short name to full name after resolving conflicts. This resolves conflicts
- * by adding on segments of the package name until they are unique. For example, com.foo.Baz and
- * com.bar.Baz will conflict on Baz and then resolve with foo.Baz and bar.Baz as replacements.
- */
- private static Map<String, String> shortenNames(Collection<String> names) {
- HashMultimap<String, List<String>> shortNameToPartsMap = HashMultimap.create();
- for (String name : names) {
- List<String> parts = new ArrayList<>(PACKAGE_SPLITTER.splitToList(name));
- // Start with the just the class name as the simple name
- String className = parts.remove(parts.size() - 1);
- shortNameToPartsMap.put(className, parts);
- }
-
- // Iterate through looking for conflicts adding the next part of the package until there are no
- // more conflicts
- while (true) {
- // Save the keys with conflicts to avoid concurrent modification issues
- List<String> conflictingShortNames = new ArrayList<>();
- for (Map.Entry<String, Collection<List<String>>> entry
- : shortNameToPartsMap.asMap().entrySet()) {
- if (entry.getValue().size() > 1) {
- conflictingShortNames.add(entry.getKey());
- }
- }
-
- if (conflictingShortNames.isEmpty()) {
- break;
- }
-
- // For all conflicts, add in the next part of the package
- for (String conflictingShortName : conflictingShortNames) {
- Set<List<String>> partsCollection = shortNameToPartsMap.removeAll(conflictingShortName);
- for (List<String> parts : partsCollection) {
- String newShortName = parts.remove(parts.size() - 1) + "." + conflictingShortName;
- // If we've removed the last part of the package, then just skip it entirely because
- // now we're not shortening it at all.
- if (!parts.isEmpty()) {
- shortNameToPartsMap.put(newShortName, parts);
- }
- }
- }
- }
-
- // Turn the multimap into a regular map now that conflicts have been resolved. Use a TreeMap
- // since we're going to need the legend sorted anyway. This map is from short name to full name.
- Map<String, String> replacementMap = new TreeMap<>();
- for (Map.Entry<String, Collection<List<String>>> entry
- : shortNameToPartsMap.asMap().entrySet()) {
- replacementMap.put(
- entry.getKey(),
- PACKAGE_JOINER.join(Iterables.getOnlyElement(entry.getValue())) + "." + entry.getKey());
- }
- return replacementMap;
- }
-
- private PackageNameCompressor() {}
-}
diff --git a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java b/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
deleted file mode 100644
index 1606ebe..0000000
--- a/java/dagger/internal/codegen/validation/ProducesMethodValidator.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.google.common.collect.Iterables.getOnlyElement;
-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;
-import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.EXCEPTION;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.internal.codegen.binding.ConfigurationAnnotations;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.multibindings.ElementsIntoSet;
-import dagger.producers.ProducerModule;
-import dagger.producers.Produces;
-import java.util.Optional;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/** A validator for {@link Produces} methods. */
-final class ProducesMethodValidator extends BindingMethodValidator {
-
- @Inject
- ProducesMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
- DependencyRequestValidator dependencyRequestValidator,
- InjectionAnnotations injectionAnnotations) {
- super(
- elements,
- types,
- kotlinMetadataUtil,
- dependencyRequestValidator,
- Produces.class,
- ProducerModule.class,
- MUST_BE_CONCRETE,
- EXCEPTION,
- ALLOWS_MULTIBINDINGS,
- NO_SCOPING,
- injectionAnnotations);
- }
-
- @Override
- protected String elementsIntoSetNotASetMessage() {
- return "@Produces methods of type set values must return a Set or ListenableFuture of Set";
- }
-
- @Override
- protected String badTypeMessage() {
- return "@Produces methods can return only a primitive, an array, a type variable, "
- + "a declared type, or a ListenableFuture of one of those types";
- }
-
- @Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected void checkAdditionalMethodProperties() {
- checkNullable();
- }
-
- /** Adds a warning if a {@link Produces @Produces} method is declared nullable. */
- // TODO(beder): Properly handle nullable with producer methods.
- private void checkNullable() {
- if (ConfigurationAnnotations.getNullableType(element).isPresent()) {
- report.addWarning("@Nullable on @Produces methods does not do anything");
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>Allows {@code keyType} to be a {@link ListenableFuture} of an otherwise-valid key type.
- */
- @Override
- protected void checkKeyType(TypeMirror keyType) {
- Optional<TypeMirror> typeToCheck = unwrapListenableFuture(keyType);
- if (typeToCheck.isPresent()) {
- super.checkKeyType(typeToCheck.get());
- }
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>Allows an {@link ElementsIntoSet @ElementsIntoSet} or {@code SET_VALUES} method to return
- * a {@link ListenableFuture} of a {@link Set} as well.
- */
- @Override
- protected void checkSetValuesType() {
- Optional<TypeMirror> typeToCheck = unwrapListenableFuture(element.getReturnType());
- if (typeToCheck.isPresent()) {
- checkSetValuesType(typeToCheck.get());
- }
- }
-
- private Optional<TypeMirror> unwrapListenableFuture(TypeMirror type) {
- if (MoreTypes.isType(type) && MoreTypes.isTypeOf(ListenableFuture.class, type)) {
- DeclaredType declaredType = MoreTypes.asDeclared(type);
- if (declaredType.getTypeArguments().isEmpty()) {
- report.addError("@Produces methods cannot return a raw ListenableFuture");
- return Optional.empty();
- } else {
- return Optional.of((TypeMirror) getOnlyElement(declaredType.getTypeArguments()));
- }
- }
- return Optional.of(type);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java b/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java
deleted file mode 100644
index 6b4f303..0000000
--- a/java/dagger/internal/codegen/validation/ProvidesMethodValidator.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2014 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.validation.BindingElementValidator.AllowsMultibindings.ALLOWS_MULTIBINDINGS;
-import static dagger.internal.codegen.validation.BindingElementValidator.AllowsScoping.ALLOWS_SCOPING;
-import static dagger.internal.codegen.validation.BindingMethodValidator.Abstractness.MUST_BE_CONCRETE;
-import static dagger.internal.codegen.validation.BindingMethodValidator.ExceptionSuperclass.RUNTIME_EXCEPTION;
-
-import com.google.common.collect.ImmutableSet;
-import dagger.Module;
-import dagger.Provides;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.producers.ProducerModule;
-import javax.inject.Inject;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-
-/** A validator for {@link Provides} methods. */
-final class ProvidesMethodValidator extends BindingMethodValidator {
-
- private final DependencyRequestValidator dependencyRequestValidator;
-
- @Inject
- ProvidesMethodValidator(
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil kotlinMetadataUtil,
- DependencyRequestValidator dependencyRequestValidator,
- InjectionAnnotations injectionAnnotations) {
- super(
- elements,
- types,
- kotlinMetadataUtil,
- Provides.class,
- ImmutableSet.of(Module.class, ProducerModule.class),
- dependencyRequestValidator,
- MUST_BE_CONCRETE,
- RUNTIME_EXCEPTION,
- ALLOWS_MULTIBINDINGS,
- ALLOWS_SCOPING,
- injectionAnnotations);
- this.dependencyRequestValidator = dependencyRequestValidator;
- }
-
- @Override
- protected ElementValidator elementValidator(ExecutableElement element) {
- return new Validator(element);
- }
-
- private class Validator extends MethodValidator {
- Validator(ExecutableElement element) {
- super(element);
- }
-
- @Override
- protected void checkAdditionalMethodProperties() {
- }
-
- /** Adds an error if a {@link Provides @Provides} method depends on a producer type. */
- @Override
- protected void checkParameter(VariableElement parameter) {
- super.checkParameter(parameter);
- dependencyRequestValidator.checkNotProducer(report, parameter);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java b/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java
deleted file mode 100644
index 57867f1..0000000
--- a/java/dagger/internal/codegen/validation/TypeCheckingProcessingStep.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 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 com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.collect.SetMultimap;
-import java.lang.annotation.Annotation;
-import java.util.function.Function;
-import javax.lang.model.element.Element;
-
-/**
- * A {@link ProcessingStep} that processes one element at a time and defers any for which {@link
- * TypeNotPresentException} is thrown.
- */
-// TODO(dpb): Contribute to auto-common.
-public abstract class TypeCheckingProcessingStep<E extends Element> implements ProcessingStep {
- private final Function<Element, E> downcaster;
-
- protected TypeCheckingProcessingStep(Function<Element, E> downcaster) {
- this.downcaster = checkNotNull(downcaster);
- }
-
- @Override
- public ImmutableSet<Element> process(
- SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
- ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder();
- ImmutableSetMultimap.copyOf(elementsByAnnotation)
- .inverse()
- .asMap()
- .forEach(
- (element, annotations) -> {
- try {
- process(downcaster.apply(element), ImmutableSet.copyOf(annotations));
- } catch (TypeNotPresentException e) {
- deferredElements.add(element);
- }
- });
- return deferredElements.build();
- }
-
- /**
- * Processes one element. If this method throws {@link TypeNotPresentException}, the element will
- * be deferred until the next round of processing.
- *
- * @param annotations the subset of {@link ProcessingStep#annotations()} that annotate {@code
- * element}
- */
- protected abstract void process(E element, ImmutableSet<Class<? extends Annotation>> annotations);
-}
diff --git a/java/dagger/internal/codegen/validation/TypeHierarchyValidator.java b/java/dagger/internal/codegen/validation/TypeHierarchyValidator.java
deleted file mode 100644
index 5fa0270..0000000
--- a/java/dagger/internal/codegen/validation/TypeHierarchyValidator.java
+++ /dev/null
@@ -1,56 +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.internal.codegen.validation;
-
-import com.google.auto.common.MoreTypes;
-import com.google.auto.common.SuperficialValidation;
-import com.google.common.base.Equivalence;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.ArrayDeque;
-import java.util.HashSet;
-import java.util.Queue;
-import java.util.Set;
-import javax.lang.model.type.TypeMirror;
-
-/** Utility methods for validating the type hierarchy of a given type. */
-final class TypeHierarchyValidator {
- private TypeHierarchyValidator() {}
-
- /**
- * Validate the type hierarchy of the given type including all super classes, interfaces, and
- * type parameters.
- *
- * @throws TypeNotPresentException if an type in the hierarchy is not valid.
- */
- public static void validateTypeHierarchy(TypeMirror type, DaggerTypes types) {
- Queue<TypeMirror> queue = new ArrayDeque<>();
- Set<Equivalence.Wrapper<TypeMirror>> queued = new HashSet<>();
- queue.add(type);
- queued.add(MoreTypes.equivalence().wrap(type));
- while (!queue.isEmpty()) {
- TypeMirror currType = queue.remove();
- if (!SuperficialValidation.validateType(currType)) {
- throw new TypeNotPresentException(currType.toString(), null);
- }
- for (TypeMirror superType : types.directSupertypes(currType)) {
- if (queued.add(MoreTypes.equivalence().wrap(superType))) {
- queue.add(superType);
- }
- }
- }
- }
-}
diff --git a/java/dagger/internal/codegen/validation/Validation.java b/java/dagger/internal/codegen/validation/Validation.java
deleted file mode 100644
index 620b0f0..0000000
--- a/java/dagger/internal/codegen/validation/Validation.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2018 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 java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import javax.inject.Qualifier;
-
-/**
- * Qualifier annotation for the {@link dagger.spi.BindingGraphPlugin}s that are used to implement
- * core Dagger validation.
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Qualifier
-public @interface Validation {}
diff --git a/java/dagger/internal/codegen/validation/ValidationReport.java b/java/dagger/internal/codegen/validation/ValidationReport.java
deleted file mode 100644
index 7f37375..0000000
--- a/java/dagger/internal/codegen/validation/ValidationReport.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2014 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.base.ElementFormatter.elementToString;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static javax.tools.Diagnostic.Kind.ERROR;
-import static javax.tools.Diagnostic.Kind.NOTE;
-import static javax.tools.Diagnostic.Kind.WARNING;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.graph.Traverser;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.google.errorprone.annotations.CheckReturnValue;
-import java.util.Optional;
-import javax.annotation.processing.Messager;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.tools.Diagnostic;
-import javax.tools.Diagnostic.Kind;
-
-/** A collection of issues to report for source code. */
-public final class ValidationReport<T extends Element> {
- private static final Traverser<ValidationReport<?>> SUBREPORTS =
- Traverser.forTree(report -> report.subreports);
-
- private final T subject;
- private final ImmutableSet<Item> items;
- private final ImmutableSet<ValidationReport<?>> subreports;
- private final boolean markedDirty;
- private boolean hasPrintedErrors;
-
- private ValidationReport(
- T subject,
- ImmutableSet<Item> items,
- ImmutableSet<ValidationReport<?>> subreports,
- boolean markedDirty) {
- this.subject = subject;
- this.items = items;
- this.subreports = subreports;
- this.markedDirty = markedDirty;
- }
-
- /** Returns the items from this report and all transitive subreports. */
- public ImmutableSet<Item> allItems() {
- return ImmutableSet.copyOf(SUBREPORTS.depthFirstPreOrder(this))
- .stream()
- .flatMap(report -> report.items.stream())
- .collect(toImmutableSet());
- }
-
- /**
- * Returns {@code true} if there are no errors in this report or any subreports and markedDirty is
- * {@code false}.
- */
- public boolean isClean() {
- if (markedDirty) {
- return false;
- }
- for (Item item : items) {
- switch (item.kind()) {
- case ERROR:
- return false;
- default:
- break;
- }
- }
- for (ValidationReport<?> subreport : subreports) {
- if (!subreport.isClean()) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Prints all messages to {@code messager} (and recurs for subreports). If a
- * message's {@linkplain Item#element() element} is contained within the report's subject,
- * associates the message with the message's element. Otherwise, since {@link Diagnostic}
- * reporting is expected to be associated with elements that are currently being compiled,
- * associates the message with the subject itself and prepends a reference to the item's element.
- */
- public void printMessagesTo(Messager messager) {
- if (hasPrintedErrors) {
- // Avoid printing the errors from this validation report more than once.
- return;
- }
- hasPrintedErrors = true;
- for (Item item : items) {
- if (isEnclosedIn(subject, item.element())) {
- if (item.annotation().isPresent()) {
- if (item.annotationValue().isPresent()) {
- messager.printMessage(
- item.kind(),
- item.message(),
- item.element(),
- item.annotation().get(),
- item.annotationValue().get());
- } else {
- messager.printMessage(
- item.kind(), item.message(), item.element(), item.annotation().get());
- }
- } else {
- messager.printMessage(item.kind(), item.message(), item.element());
- }
- } else {
- String message = String.format("[%s] %s", elementToString(item.element()), item.message());
- messager.printMessage(item.kind(), message, subject);
- }
- }
- for (ValidationReport<?> subreport : subreports) {
- subreport.printMessagesTo(messager);
- }
- }
-
- private static boolean isEnclosedIn(Element parent, Element child) {
- Element current = child;
- while (current != null) {
- if (current.equals(parent)) {
- return true;
- }
- current = current.getEnclosingElement();
- }
- return false;
- }
-
- /** Metadata about a {@link ValidationReport} item. */
- @AutoValue
- public abstract static class Item {
- public abstract String message();
- public abstract Kind kind();
- public abstract Element element();
- public abstract Optional<AnnotationMirror> annotation();
- abstract Optional<AnnotationValue> annotationValue();
- }
-
- public static <T extends Element> Builder<T> about(T subject) {
- return new Builder<>(subject);
- }
-
- /** A {@link ValidationReport} builder. */
- @CanIgnoreReturnValue
- public static final class Builder<T extends Element> {
- private final T subject;
- private final ImmutableSet.Builder<Item> items = ImmutableSet.builder();
- private final ImmutableSet.Builder<ValidationReport<?>> subreports = ImmutableSet.builder();
- private boolean markedDirty;
-
- private Builder(T subject) {
- this.subject = subject;
- }
-
- @CheckReturnValue
- T getSubject() {
- return subject;
- }
-
- Builder<T> addItems(Iterable<Item> newItems) {
- items.addAll(newItems);
- return this;
- }
-
- public Builder<T> addError(String message) {
- return addError(message, subject);
- }
-
- public Builder<T> addError(String message, Element element) {
- return addItem(message, ERROR, element);
- }
-
- public Builder<T> addError(String message, Element element, AnnotationMirror annotation) {
- return addItem(message, ERROR, element, annotation);
- }
-
- public Builder<T> addError(
- String message,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
- return addItem(message, ERROR, element, annotation, annotationValue);
- }
-
- Builder<T> addWarning(String message) {
- return addWarning(message, subject);
- }
-
- Builder<T> addWarning(String message, Element element) {
- return addItem(message, WARNING, element);
- }
-
- Builder<T> addWarning(String message, Element element, AnnotationMirror annotation) {
- return addItem(message, WARNING, element, annotation);
- }
-
- Builder<T> addWarning(
- String message,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
- return addItem(message, WARNING, element, annotation, annotationValue);
- }
-
- Builder<T> addNote(String message) {
- return addNote(message, subject);
- }
-
- Builder<T> addNote(String message, Element element) {
- return addItem(message, NOTE, element);
- }
-
- Builder<T> addNote(String message, Element element, AnnotationMirror annotation) {
- return addItem(message, NOTE, element, annotation);
- }
-
- Builder<T> addNote(
- String message,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
- return addItem(message, NOTE, element, annotation, annotationValue);
- }
-
- Builder<T> addItem(String message, Kind kind, Element element) {
- return addItem(message, kind, element, Optional.empty(), Optional.empty());
- }
-
- Builder<T> addItem(String message, Kind kind, Element element, AnnotationMirror annotation) {
- return addItem(message, kind, element, Optional.of(annotation), Optional.empty());
- }
-
- Builder<T> addItem(
- String message,
- Kind kind,
- Element element,
- AnnotationMirror annotation,
- AnnotationValue annotationValue) {
- return addItem(message, kind, element, Optional.of(annotation), Optional.of(annotationValue));
- }
-
- private Builder<T> addItem(
- String message,
- Kind kind,
- Element element,
- Optional<AnnotationMirror> annotation,
- Optional<AnnotationValue> annotationValue) {
- items.add(
- new AutoValue_ValidationReport_Item(message, kind, element, annotation, annotationValue));
- return this;
- }
-
- /**
- * If called, then {@link #isClean()} will return {@code false} even if there are no error items
- * in the report.
- */
- void markDirty() {
- this.markedDirty = true;
- }
-
- public Builder<T> addSubreport(ValidationReport<?> subreport) {
- subreports.add(subreport);
- return this;
- }
-
- @CheckReturnValue
- public ValidationReport<T> build() {
- return new ValidationReport<>(subject, items.build(), subreports.build(), markedDirty);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java b/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
deleted file mode 100644
index 96e6340..0000000
--- a/java/dagger/internal/codegen/writing/AnnotationCreatorGenerator.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2014 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.writing;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.AnnotationExpression.createMethodName;
-import static dagger.internal.codegen.binding.AnnotationExpression.getAnnotationCreatorClassName;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.google.errorprone.annotations.CanIgnoreReturnValue;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.LinkedHashSet;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-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.type.DeclaredType;
-import javax.lang.model.util.SimpleTypeVisitor6;
-
-/**
- * Generates classes that create annotation instances for an annotation type. The generated class
- * will have a private empty constructor, a static method that creates the annotation type itself,
- * and a static method that creates each annotation type that is nested in the top-level annotation
- * type.
- *
- * <p>So for an example annotation:
- *
- * <pre>
- * {@literal @interface} Foo {
- * String s();
- * int i();
- * Bar bar(); // an annotation defined elsewhere
- * }
- * </pre>
- *
- * the generated class will look like:
- *
- * <pre>
- * public final class FooCreator {
- * private FooCreator() {}
- *
- * public static Foo createFoo(String s, int i, Bar bar) { … }
- * public static Bar createBar(…) { … }
- * }
- * </pre>
- */
-public class AnnotationCreatorGenerator extends SourceFileGenerator<TypeElement> {
- private static final ClassName AUTO_ANNOTATION =
- ClassName.get("com.google.auto.value", "AutoAnnotation");
-
- @Inject
- AnnotationCreatorGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
- super(filer, elements, sourceVersion);
- }
-
- @Override
- public ClassName nameGeneratedType(TypeElement annotationType) {
- return getAnnotationCreatorClassName(annotationType);
- }
-
- @Override
- public Element originatingElement(TypeElement annotationType) {
- return annotationType;
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(TypeElement annotationType) {
- ClassName generatedTypeName = nameGeneratedType(annotationType);
- TypeSpec.Builder annotationCreatorBuilder =
- classBuilder(generatedTypeName)
- .addModifiers(PUBLIC, FINAL)
- .addMethod(constructorBuilder().addModifiers(PRIVATE).build());
-
- for (TypeElement annotationElement : annotationsToCreate(annotationType)) {
- annotationCreatorBuilder.addMethod(buildCreateMethod(generatedTypeName, annotationElement));
- }
-
- return Optional.of(annotationCreatorBuilder);
- }
-
- private MethodSpec buildCreateMethod(ClassName generatedTypeName, TypeElement annotationElement) {
- String createMethodName = createMethodName(annotationElement);
- MethodSpec.Builder createMethod =
- methodBuilder(createMethodName)
- .addAnnotation(AUTO_ANNOTATION)
- .addModifiers(PUBLIC, STATIC)
- .returns(TypeName.get(annotationElement.asType()));
-
- ImmutableList.Builder<CodeBlock> parameters = ImmutableList.builder();
- for (ExecutableElement annotationMember : methodsIn(annotationElement.getEnclosedElements())) {
- String parameterName = annotationMember.getSimpleName().toString();
- TypeName parameterType = TypeName.get(annotationMember.getReturnType());
- createMethod.addParameter(parameterType, parameterName);
- parameters.add(CodeBlock.of("$L", parameterName));
- }
-
- ClassName autoAnnotationClass =
- generatedTypeName.peerClass(
- "AutoAnnotation_" + generatedTypeName.simpleName() + "_" + createMethodName);
- createMethod.addStatement(
- "return new $T($L)", autoAnnotationClass, makeParametersCodeBlock(parameters.build()));
- return createMethod.build();
- }
-
- /**
- * Returns the annotation types for which {@code @AutoAnnotation static Foo createFoo(…)} methods
- * should be written.
- */
- protected Set<TypeElement> annotationsToCreate(TypeElement annotationElement) {
- return nestedAnnotationElements(annotationElement, new LinkedHashSet<>());
- }
-
- @CanIgnoreReturnValue
- private static Set<TypeElement> nestedAnnotationElements(
- TypeElement annotationElement, Set<TypeElement> annotationElements) {
- if (annotationElements.add(annotationElement)) {
- for (ExecutableElement method : methodsIn(annotationElement.getEnclosedElements())) {
- TRAVERSE_NESTED_ANNOTATIONS.visit(method.getReturnType(), annotationElements);
- }
- }
- return annotationElements;
- }
-
- private static final SimpleTypeVisitor6<Void, Set<TypeElement>> TRAVERSE_NESTED_ANNOTATIONS =
- new SimpleTypeVisitor6<Void, Set<TypeElement>>() {
- @Override
- public Void visitDeclared(DeclaredType t, Set<TypeElement> p) {
- TypeElement typeElement = MoreTypes.asTypeElement(t);
- if (typeElement.getKind() == ElementKind.ANNOTATION_TYPE) {
- nestedAnnotationElements(typeElement, p);
- }
- return null;
- }
- };
-}
diff --git a/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java b/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
deleted file mode 100644
index b1237ca..0000000
--- a/java/dagger/internal/codegen/writing/AnonymousProviderCreationExpression.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.javapoet.CodeBlocks.anonymousProvider;
-import static dagger.model.RequestKind.INSTANCE;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-
-/**
- * A {@link javax.inject.Provider} creation expression for an anonymous inner class whose
- * {@code get()} method returns the expression for an instance binding request for its key.
- */
-final class AnonymousProviderCreationExpression
- implements FrameworkInstanceCreationExpression {
- private final ContributionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final ClassName requestingClass;
-
- AnonymousProviderCreationExpression(
- ContributionBinding binding,
- ComponentBindingExpressions componentBindingExpressions,
- ClassName requestingClass) {
- this.binding = binding;
- this.componentBindingExpressions = componentBindingExpressions;
- this.requestingClass = requestingClass;
- }
-
- @Override
- public CodeBlock creationExpression() {
- BindingRequest instanceExpressionRequest = bindingRequest(binding.key(), INSTANCE);
- Expression instanceExpression =
- componentBindingExpressions.getDependencyExpression(
- instanceExpressionRequest,
- // Not a real class name, but the actual requestingClass is an inner class within the
- // given class, not that class itself.
- requestingClass.nestedClass("Anonymous"));
- return anonymousProvider(instanceExpression);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java b/java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java
deleted file mode 100644
index d0c481c..0000000
--- a/java/dagger/internal/codegen/writing/AssistedFactoryBindingExpression.java
+++ /dev/null
@@ -1,111 +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.internal.codegen.writing;
-
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreTypes.asDeclared;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryMethod;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedFactoryParameterSpecs;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-
-/**
- * A {@link dagger.internal.codegen.writing.BindingExpression} for {@link
- * dagger.assisted.AssistedFactory} methods.
- */
-final class AssistedFactoryBindingExpression extends SimpleInvocationBindingExpression {
- private final ProvisionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerElements elements;
- private final DaggerTypes types;
-
- AssistedFactoryBindingExpression(
- ProvisionBinding binding,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- DaggerElements elements) {
- super(binding);
- this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.elements = checkNotNull(elements);
- this.types = checkNotNull(types);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- // An assisted factory binding should have a single request for an assisted injection type.
- DependencyRequest assistedInjectionRequest = getOnlyElement(binding.provisionDependencies());
- Expression assistedInjectionExpression =
- componentBindingExpressions.getDependencyExpression(
- BindingRequest.bindingRequest(assistedInjectionRequest.key(), RequestKind.INSTANCE),
- // This is kind of gross because the anonymous class doesn't really have a name we can
- // reference. The requesting class name is really only needed to determine if we need to
- // append "OwningClass.this." to the method call or not.
- // TODO(bcorso): We should probably use a non-anonymous class here instead so that we
- // actually have a proper class name.
- requestingClass.peerClass(""));
- return Expression.create(
- assistedInjectionExpression.type(),
- CodeBlock.of("$L", anonymousfactoryImpl(assistedInjectionExpression)));
- }
-
- private TypeSpec anonymousfactoryImpl(Expression assistedInjectionExpression) {
- TypeElement factory = asType(binding.bindingElement().get());
- DeclaredType factoryType = asDeclared(binding.key().type());
- ExecutableElement factoryMethod = assistedFactoryMethod(factory, elements, types);
-
- // We can't use MethodSpec.overriding directly because we need to control the parameter names.
- MethodSpec factoryOverride = MethodSpec.overriding(factoryMethod, factoryType, types).build();
- TypeSpec.Builder builder =
- TypeSpec.anonymousClassBuilder("")
- .addMethod(
- MethodSpec.methodBuilder(factoryMethod.getSimpleName().toString())
- .addModifiers(factoryOverride.modifiers)
- .addTypeVariables(factoryOverride.typeVariables)
- .returns(factoryOverride.returnType)
- .addAnnotations(factoryOverride.annotations)
- .addExceptions(factoryOverride.exceptions)
- .addParameters(assistedFactoryParameterSpecs(binding, elements, types))
- .addStatement("return $L", assistedInjectionExpression.codeBlock())
- .build());
-
- if (factory.getKind() == ElementKind.INTERFACE) {
- builder.addSuperinterface(TypeName.get(factoryType));
- } else {
- builder.superclass(TypeName.get(factoryType));
- }
-
- return builder.build();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/BUILD b/java/dagger/internal/codegen/writing/BUILD
deleted file mode 100644
index dcb88b3..0000000
--- a/java/dagger/internal/codegen/writing/BUILD
+++ /dev/null
@@ -1,47 +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.
-
-# Description:
-# Classes that assemble the model of the generated code and write to the Filer
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "writing",
- srcs = glob(["*.java"]),
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
- tags = ["maven:merged"],
- deps = [
- "//java/dagger:core",
- "//java/dagger/internal/codegen/base",
- "//java/dagger/internal/codegen/binding",
- "//java/dagger/internal/codegen/compileroption",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
- "//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "//java/dagger/producers",
- "//java/dagger/spi",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/error_prone:annotations",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
- ],
-)
diff --git a/java/dagger/internal/codegen/writing/BindingExpression.java b/java/dagger/internal/codegen/writing/BindingExpression.java
deleted file mode 100644
index bd45f60..0000000
--- a/java/dagger/internal/codegen/writing/BindingExpression.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.javapoet.Expression;
-
-/** A factory of code expressions used to access a single request for a binding in a component. */
-// TODO(bcorso): Rename this to RequestExpression?
-abstract class BindingExpression {
-
- /**
- * Returns an expression that evaluates to the value of a request based on the given requesting
- * class.
- *
- * @param requestingClass the class that will contain the expression
- */
- abstract Expression getDependencyExpression(ClassName requestingClass);
-
- /**
- * Equivalent to {@link #getDependencyExpression} that is used only when the request is for an
- * implementation of a component method. By default, just delegates to {@link
- * #getDependencyExpression}.
- */
- Expression getDependencyExpressionForComponentMethod(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- return getDependencyExpression(component.name());
- }
-
- /** Returns {@code true} if this binding expression should be encapsulated in a method. */
- boolean requiresMethodEncapsulation() {
- return false;
- }
-
- /**
- * Returns an expression for the implementation of a component method with the given request.
- *
- * @param component the component that will contain the implemented method
- */
- CodeBlock getComponentMethodImplementation(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- // By default, just delegate to #getDependencyExpression().
- return CodeBlock.of(
- "return $L;",
- getDependencyExpressionForComponentMethod(componentMethod, component).codeBlock());
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentBindingExpressions.java b/java/dagger/internal/codegen/writing/ComponentBindingExpressions.java
deleted file mode 100644
index 5f1f0bd..0000000
--- a/java/dagger/internal/codegen/writing/ComponentBindingExpressions.java
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * Copyright (C) 2016 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Verify.verify;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.extension.DaggerCollectors.toOptional;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.DOUBLE_CHECK;
-import static dagger.internal.codegen.javapoet.TypeNames.SINGLE_CHECK;
-import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.writing.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope;
-import static dagger.internal.codegen.writing.MemberSelect.staticFactoryCreation;
-import static dagger.model.BindingKind.DELEGATE;
-import static dagger.model.BindingKind.MULTIBOUND_MAP;
-import static dagger.model.BindingKind.MULTIBOUND_SET;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.BindingNode;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.binding.FrameworkTypeMapper;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.internal.codegen.writing.MethodBindingExpression.MethodImplementationStrategy;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.type.TypeMirror;
-
-/** A central repository of code expressions used to access any binding available to a component. */
-@PerComponentImplementation
-public final class ComponentBindingExpressions {
- // TODO(dpb,ronshapiro): refactor this and ComponentRequirementExpressions into a
- // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
- // parents? If so, maybe make BindingExpression.Factory create it.
-
- private final Optional<ComponentBindingExpressions> parent;
- private final BindingGraph graph;
- private final ComponentImplementation componentImplementation;
- private final ComponentImplementation topLevelComponentImplementation;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final OptionalFactories optionalFactories;
- private final DaggerTypes types;
- private final DaggerElements elements;
- private final SourceVersion sourceVersion;
- private final CompilerOptions compilerOptions;
- private final MembersInjectionMethods membersInjectionMethods;
- private final InnerSwitchingProviders innerSwitchingProviders;
- private final Map<BindingRequest, BindingExpression> expressions = new HashMap<>();
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- ComponentBindingExpressions(
- @ParentComponent Optional<ComponentBindingExpressions> parent,
- BindingGraph graph,
- ComponentImplementation componentImplementation,
- @TopLevel ComponentImplementation topLevelComponentImplementation,
- ComponentRequirementExpressions componentRequirementExpressions,
- OptionalFactories optionalFactories,
- DaggerTypes types,
- DaggerElements elements,
- SourceVersion sourceVersion,
- CompilerOptions compilerOptions,
- KotlinMetadataUtil metadataUtil) {
- this.parent = parent;
- this.graph = graph;
- this.componentImplementation = componentImplementation;
- this.topLevelComponentImplementation = topLevelComponentImplementation;
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.optionalFactories = checkNotNull(optionalFactories);
- this.types = checkNotNull(types);
- this.elements = checkNotNull(elements);
- this.sourceVersion = checkNotNull(sourceVersion);
- this.compilerOptions = checkNotNull(compilerOptions);
- this.membersInjectionMethods =
- new MembersInjectionMethods(
- componentImplementation, this, graph, elements, types, metadataUtil);
- this.innerSwitchingProviders =
- new InnerSwitchingProviders(componentImplementation, this, types);
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Returns an expression that evaluates to the value of a binding request for a binding owned by
- * this component or an ancestor.
- *
- * @param requestingClass the class that will contain the expression
- * @throws IllegalStateException if there is no binding expression that satisfies the request
- */
- public Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) {
- return getBindingExpression(request).getDependencyExpression(requestingClass);
- }
-
- /**
- * Equivalent to {@link #getDependencyExpression(BindingRequest, ClassName)} that is used only
- * when the request is for implementation of a component method.
- *
- * @throws IllegalStateException if there is no binding expression that satisfies the request
- */
- Expression getDependencyExpressionForComponentMethod(
- BindingRequest request,
- ComponentMethodDescriptor componentMethod,
- ComponentImplementation componentImplementation) {
- return getBindingExpression(request)
- .getDependencyExpressionForComponentMethod(componentMethod, componentImplementation);
- }
-
- /**
- * Returns the {@link CodeBlock} for the method arguments used with the factory {@code create()}
- * method for the given {@link ContributionBinding binding}.
- */
- CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) {
- return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding));
- }
-
- private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) {
- ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
-
- if (binding.requiresModuleInstance()) {
- arguments.add(
- componentRequirementExpressions.getExpressionDuringInitialization(
- ComponentRequirement.forModule(binding.contributingModule().get().asType()),
- componentImplementation.name()));
- }
-
- binding.dependencies().stream()
- .map(dependency -> frameworkRequest(binding, dependency))
- .map(request -> getDependencyExpression(request, componentImplementation.name()))
- .map(Expression::codeBlock)
- .forEach(arguments::add);
-
- return arguments.build();
- }
-
- private static BindingRequest frameworkRequest(
- ContributionBinding binding, DependencyRequest dependency) {
- // TODO(bcorso): See if we can get rid of FrameworkTypeMatcher
- FrameworkType frameworkType =
- FrameworkTypeMapper.forBindingType(binding.bindingType())
- .getFrameworkType(dependency.kind());
- return BindingRequest.bindingRequest(dependency.key(), frameworkType);
- }
-
- /**
- * Returns an expression that evaluates to the value of a dependency request, for passing to a
- * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
- *
- * <p>If the method is a generated static {@link InjectionMethods injection method}, each
- * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
- * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
- *
- * @param requestingClass the class that will contain the expression
- */
- Expression getDependencyArgumentExpression(
- DependencyRequest dependencyRequest, ClassName requestingClass) {
-
- TypeMirror dependencyType = dependencyRequest.key().type();
- BindingRequest bindingRequest = bindingRequest(dependencyRequest);
- Expression dependencyExpression = getDependencyExpression(bindingRequest, requestingClass);
-
- if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
- && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
- && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
- return dependencyExpression.castTo(types.erasure(dependencyType));
- }
-
- return dependencyExpression;
- }
-
- /** Returns the implementation of a component method. */
- public MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
- checkArgument(componentMethod.dependencyRequest().isPresent());
- BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
- MethodSpec.Builder method =
- MethodSpec.overriding(
- componentMethod.methodElement(),
- MoreTypes.asDeclared(graph.componentTypeElement().asType()),
- types);
- // Even though this is not used if the method is abstract, we need to invoke the binding
- // expression in order for the side of effect of the method being added to the
- // ComponentImplementation
- CodeBlock methodBody =
- getBindingExpression(request)
- .getComponentMethodImplementation(componentMethod, componentImplementation);
-
- return method.addCode(methodBody).build();
- }
-
- /** Returns the {@link BindingExpression} for the given {@link BindingRequest}. */
- BindingExpression getBindingExpression(BindingRequest request) {
- if (expressions.containsKey(request)) {
- return expressions.get(request);
- }
-
- Optional<Binding> optionalBinding =
- graph.bindingNodes(request.key()).stream()
- // Filter out nodes we don't own.
- .filter(bindingNode -> bindingNode.componentPath().equals(graph.componentPath()))
- // Filter out nodes that don't match the request kind
- .filter(
- bindingNode ->
- // The binding used for the binding expression depends on the request:
- // 1. MembersInjectionBinding: satisfies MEMBERS_INJECTION requests
- // 2. ContributionBindings: satisfies all other requests.
- request.isRequestKind(RequestKind.MEMBERS_INJECTION)
- ? bindingNode.delegate().bindingType() == BindingType.MEMBERS_INJECTION
- : bindingNode.delegate().bindingType() == BindingType.PROVISION
- || bindingNode.delegate().bindingType() == BindingType.PRODUCTION)
- .map(BindingNode::delegate)
- // We expect at most one binding to match since this graph is already validated.
- .collect(toOptional());
-
- if (optionalBinding.isPresent()) {
- BindingExpression expression = createBindingExpression(optionalBinding.get(), request);
- expressions.put(request, expression);
- return expression;
- }
-
- checkArgument(parent.isPresent(), "no expression found for %s", request);
- return parent.get().getBindingExpression(request);
- }
-
- /** Creates a binding expression. */
- private BindingExpression createBindingExpression(Binding binding, BindingRequest request) {
- switch (binding.bindingType()) {
- case MEMBERS_INJECTION:
- checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
- return new MembersInjectionBindingExpression(
- (MembersInjectionBinding) binding, membersInjectionMethods);
-
- case PROVISION:
- return provisionBindingExpression((ContributionBinding) binding, request);
-
- case PRODUCTION:
- return productionBindingExpression((ContributionBinding) binding, request);
- }
- throw new AssertionError(binding);
- }
-
- /**
- * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
- * or a {@link dagger.producers.Producer} for production bindings.
- */
- private BindingExpression frameworkInstanceBindingExpression(ContributionBinding binding) {
- // TODO(bcorso): Consider merging the static factory creation logic into CreationExpressions?
- Optional<MemberSelect> staticMethod =
- useStaticFactoryCreation(binding) ? staticFactoryCreation(binding) : Optional.empty();
- FrameworkInstanceSupplier frameworkInstanceSupplier =
- staticMethod.isPresent()
- ? staticMethod::get
- : new FrameworkFieldInitializer(
- componentImplementation,
- binding,
- binding.scope().isPresent()
- ? scope(binding, frameworkInstanceCreationExpression(binding))
- : frameworkInstanceCreationExpression(binding));
-
- switch (binding.bindingType()) {
- case PROVISION:
- return new ProviderInstanceBindingExpression(
- binding, frameworkInstanceSupplier, types, elements);
- case PRODUCTION:
- return new ProducerNodeInstanceBindingExpression(
- binding, frameworkInstanceSupplier, types, elements, componentImplementation);
- default:
- throw new AssertionError("invalid binding type: " + binding.bindingType());
- }
- }
-
- private FrameworkInstanceCreationExpression scope(
- ContributionBinding binding, FrameworkInstanceCreationExpression unscoped) {
- return () ->
- CodeBlock.of(
- "$T.provider($L)",
- binding.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
- unscoped.creationExpression());
- }
-
- /**
- * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
- * {@link dagger.producers.Producer} for production bindings.
- */
- private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
- ContributionBinding binding) {
- switch (binding.kind()) {
- case COMPONENT:
- // The cast can be removed when we drop java 7 source support
- return new InstanceFactoryCreationExpression(
- () -> CodeBlock.of("($T) this", binding.key().type()));
-
- case BOUND_INSTANCE:
- return instanceFactoryCreationExpression(
- binding, ComponentRequirement.forBoundInstance(binding));
-
- case COMPONENT_DEPENDENCY:
- return instanceFactoryCreationExpression(
- binding, ComponentRequirement.forDependency(binding.key().type()));
-
- case COMPONENT_PROVISION:
- return new DependencyMethodProviderCreationExpression(
- binding,
- componentImplementation,
- componentRequirementExpressions,
- compilerOptions,
- graph);
-
- case SUBCOMPONENT_CREATOR:
- return new AnonymousProviderCreationExpression(
- binding, this, componentImplementation.name());
-
- case ASSISTED_FACTORY:
- case ASSISTED_INJECTION:
- case INJECTION:
- case PROVISION:
- return new InjectionOrProvisionProviderCreationExpression(binding, this);
-
- case COMPONENT_PRODUCTION:
- return new DependencyMethodProducerCreationExpression(
- binding, componentImplementation, componentRequirementExpressions, graph);
-
- case PRODUCTION:
- return new ProducerCreationExpression(binding, this);
-
- case MULTIBOUND_SET:
- return new SetFactoryCreationExpression(binding, componentImplementation, this, graph);
-
- case MULTIBOUND_MAP:
- return new MapFactoryCreationExpression(
- binding, componentImplementation, this, graph, elements);
-
- case DELEGATE:
- return new DelegatingFrameworkInstanceCreationExpression(
- binding, componentImplementation, this);
-
- case OPTIONAL:
- return new OptionalFactoryInstanceCreationExpression(
- optionalFactories, binding, componentImplementation, this);
-
- case MEMBERS_INJECTOR:
- return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
-
- default:
- throw new AssertionError(binding);
- }
- }
-
- private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
- ContributionBinding binding, ComponentRequirement componentRequirement) {
- return new InstanceFactoryCreationExpression(
- binding.nullableType().isPresent(),
- () ->
- componentRequirementExpressions.getExpressionDuringInitialization(
- componentRequirement, componentImplementation.name()));
- }
-
- /** Returns a binding expression for a provision binding. */
- private BindingExpression provisionBindingExpression(
- ContributionBinding binding, BindingRequest request) {
- if (!request.requestKind().isPresent()) {
- verify(
- request.frameworkType().get().equals(FrameworkType.PRODUCER_NODE),
- "expected a PRODUCER_NODE: %s",
- request);
- return producerFromProviderBindingExpression(binding);
- }
- RequestKind requestKind = request.requestKind().get();
- Key key = request.key();
- switch (requestKind) {
- case INSTANCE:
- return instanceBindingExpression(binding);
-
- case PROVIDER:
- return providerBindingExpression(binding);
-
- case LAZY:
- case PRODUCED:
- case PROVIDER_OF_LAZY:
- return new DerivedFromFrameworkInstanceBindingExpression(
- key, FrameworkType.PROVIDER, requestKind, this, types);
-
- case PRODUCER:
- return producerFromProviderBindingExpression(binding);
-
- case FUTURE:
- return new ImmediateFutureBindingExpression(key, this, types, sourceVersion);
-
- case MEMBERS_INJECTION:
- throw new IllegalArgumentException();
- }
-
- throw new AssertionError();
- }
-
- /** Returns a binding expression for a production binding. */
- private BindingExpression productionBindingExpression(
- ContributionBinding binding, BindingRequest request) {
- if (request.frameworkType().isPresent()) {
- return frameworkInstanceBindingExpression(binding);
- } else {
- // If no FrameworkType is present, a RequestKind is guaranteed to be present.
- RequestKind requestKind = request.requestKind().get();
- return new DerivedFromFrameworkInstanceBindingExpression(
- request.key(), FrameworkType.PRODUCER_NODE, requestKind, this, types);
- }
- }
-
- /**
- * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
- *
- * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ContributionBinding) need to be
- * cached} can use a {@link DelegateBindingExpression}.
- *
- * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
- * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
- * which case, just use that Provider directly).
- *
- * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
- */
- private BindingExpression providerBindingExpression(ContributionBinding binding) {
- if (binding.kind().equals(DELEGATE) && !needsCaching(binding)) {
- return new DelegateBindingExpression(binding, RequestKind.PROVIDER, this, types, elements);
- } else if (compilerOptions.fastInit(
- topLevelComponentImplementation.componentDescriptor().typeElement())
- && frameworkInstanceCreationExpression(binding).useInnerSwitchingProvider()
- && !(instanceBindingExpression(binding)
- instanceof DerivedFromFrameworkInstanceBindingExpression)) {
- return wrapInMethod(
- binding,
- bindingRequest(binding.key(), RequestKind.PROVIDER),
- innerSwitchingProviders.newBindingExpression(binding));
- }
- return frameworkInstanceBindingExpression(binding);
- }
-
- /**
- * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
- * provision binding.
- */
- private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
- ContributionBinding binding) {
- checkArgument(binding.bindingType().equals(BindingType.PROVISION));
- return new ProducerNodeInstanceBindingExpression(
- binding,
- new FrameworkFieldInitializer(
- componentImplementation,
- binding,
- new ProducerFromProviderCreationExpression(binding, componentImplementation, this)),
- types,
- elements,
- componentImplementation);
- }
-
- /**
- * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
- *
- * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
- * instance of this binding, return it, wrapped in a method if the binding {@linkplain
- * #needsCaching(ContributionBinding) needs to be cached} or the expression has dependencies.
- *
- * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
- */
- private BindingExpression instanceBindingExpression(ContributionBinding binding) {
- Optional<BindingExpression> maybeDirectInstanceExpression =
- unscopedDirectInstanceExpression(binding);
- if (canUseDirectInstanceExpression(binding) && maybeDirectInstanceExpression.isPresent()) {
- BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
- return directInstanceExpression.requiresMethodEncapsulation() || needsCaching(binding)
- ? wrapInMethod(
- binding,
- bindingRequest(binding.key(), RequestKind.INSTANCE),
- directInstanceExpression)
- : directInstanceExpression;
- }
- return new DerivedFromFrameworkInstanceBindingExpression(
- binding.key(), FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types);
- }
-
- /**
- * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
- * {@code get()} on its provider, if there is one.
- */
- private Optional<BindingExpression> unscopedDirectInstanceExpression(
- ContributionBinding binding) {
- switch (binding.kind()) {
- case DELEGATE:
- return Optional.of(
- new DelegateBindingExpression(binding, RequestKind.INSTANCE, this, types, elements));
-
- case COMPONENT:
- return Optional.of(
- new ComponentInstanceBindingExpression(binding, componentImplementation.name()));
-
- case COMPONENT_DEPENDENCY:
- return Optional.of(
- new ComponentRequirementBindingExpression(
- binding,
- ComponentRequirement.forDependency(binding.key().type()),
- componentRequirementExpressions));
-
- case COMPONENT_PROVISION:
- return Optional.of(
- new ComponentProvisionBindingExpression(
- (ProvisionBinding) binding,
- graph,
- componentRequirementExpressions,
- compilerOptions));
-
- case SUBCOMPONENT_CREATOR:
- return Optional.of(
- new SubcomponentCreatorBindingExpression(
- binding, componentImplementation.getSubcomponentCreatorSimpleName(binding.key())));
-
- case MULTIBOUND_SET:
- return Optional.of(
- new SetBindingExpression((ProvisionBinding) binding, graph, this, types, elements));
-
- case MULTIBOUND_MAP:
- return Optional.of(
- new MapBindingExpression((ProvisionBinding) binding, graph, this, types, elements));
-
- case OPTIONAL:
- return Optional.of(
- new OptionalBindingExpression((ProvisionBinding) binding, this, types, sourceVersion));
-
- case BOUND_INSTANCE:
- return Optional.of(
- new ComponentRequirementBindingExpression(
- binding,
- ComponentRequirement.forBoundInstance(binding),
- componentRequirementExpressions));
-
- case ASSISTED_FACTORY:
- return Optional.of(
- new AssistedFactoryBindingExpression(
- (ProvisionBinding) binding, this, types, elements));
-
- case ASSISTED_INJECTION:
- case INJECTION:
- case PROVISION:
- return Optional.of(
- new SimpleMethodBindingExpression(
- (ProvisionBinding) binding,
- compilerOptions,
- this,
- membersInjectionMethods,
- componentRequirementExpressions,
- elements,
- sourceVersion,
- metadataUtil));
-
- case MEMBERS_INJECTOR:
- return Optional.empty();
-
- case MEMBERS_INJECTION:
- case COMPONENT_PRODUCTION:
- case PRODUCTION:
- throw new IllegalArgumentException(binding.kind().toString());
- default:
- throw new AssertionError("Unexpected binding kind: " + binding.kind());
- }
- }
-
- /**
- * Returns {@code true} if the binding should use the static factory creation strategy.
- *
- * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we
- * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
- * however, we allow static factories that can reused across multiple bindings, e.g. {@code
- * MapFactory} or {@code SetFactory}.
- */
- private boolean useStaticFactoryCreation(ContributionBinding binding) {
- return !compilerOptions.fastInit(
- topLevelComponentImplementation.componentDescriptor().typeElement())
- || binding.kind().equals(MULTIBOUND_MAP)
- || binding.kind().equals(MULTIBOUND_SET);
- }
-
- /**
- * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
- * binding. If the binding doesn't {@linkplain #needsCaching(ContributionBinding) need to be
- * cached} and the binding is not an {@link BindingKind.ASSISTED_FACTORY}, we can.
- *
- * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
- * #needsCaching(ContributionBinding) needs to be cached}.
- */
- private boolean canUseDirectInstanceExpression(ContributionBinding binding) {
- return (!needsCaching(binding) && binding.kind() != BindingKind.ASSISTED_FACTORY)
- || compilerOptions.fastInit(
- topLevelComponentImplementation.componentDescriptor().typeElement());
- }
-
- /**
- * Returns a binding expression that uses a given one as the body of a method that users call. If
- * a component provision method matches it, it will be the method implemented. If it does not
- * match a component provision method and the binding is modifiable, then a new public modifiable
- * binding method will be written. If the binding doesn't match a component method and is not
- * modifiable, then a new private method will be written.
- */
- BindingExpression wrapInMethod(
- ContributionBinding binding, BindingRequest request, BindingExpression bindingExpression) {
- // If we've already wrapped the expression, then use the delegate.
- if (bindingExpression instanceof MethodBindingExpression) {
- return bindingExpression;
- }
-
- MethodImplementationStrategy methodImplementationStrategy =
- methodImplementationStrategy(binding, request);
- Optional<ComponentMethodDescriptor> matchingComponentMethod =
- graph.componentDescriptor().firstMatchingComponentMethod(request);
-
- ComponentImplementation shard = componentImplementation.shardImplementation(binding.key());
-
- // Consider the case of a request from a component method like:
- //
- // DaggerMyComponent extends MyComponent {
- // @Overrides
- // Foo getFoo() {
- // <FOO_BINDING_REQUEST>
- // }
- // }
- //
- // Normally, in this case we would return a ComponentMethodBindingExpression rather than a
- // PrivateMethodBindingExpression so that #getFoo() can inline the implementation rather than
- // create an unnecessary private method and return that. However, with sharding we don't want to
- // inline the implementation because that would defeat some of the class pool savings if those
- // fields had to communicate across shards. Thus, when a key belongs to a separate shard use a
- // PrivateMethodBindingExpression and put the private method in the shard.
- if (matchingComponentMethod.isPresent() && componentImplementation == shard) {
- ComponentMethodDescriptor componentMethod = matchingComponentMethod.get();
- return new ComponentMethodBindingExpression(
- request,
- binding,
- methodImplementationStrategy,
- bindingExpression,
- componentImplementation,
- componentMethod,
- types);
- } else {
- return new PrivateMethodBindingExpression(
- request,
- binding,
- methodImplementationStrategy,
- bindingExpression,
- shard,
- types,
- compilerOptions);
- }
- }
-
- private MethodImplementationStrategy methodImplementationStrategy(
- ContributionBinding binding, BindingRequest request) {
- if (compilerOptions.fastInit(
- topLevelComponentImplementation.componentDescriptor().typeElement())) {
- if (request.isRequestKind(RequestKind.PROVIDER)) {
- return MethodImplementationStrategy.SINGLE_CHECK;
- } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(binding)) {
- return binding.scope().get().isReusable()
- ? MethodImplementationStrategy.SINGLE_CHECK
- : MethodImplementationStrategy.DOUBLE_CHECK;
- }
- }
- return MethodImplementationStrategy.SIMPLE;
- }
-
- /**
- * Returns {@code true} if the component needs to make sure the provided value is cached.
- *
- * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
- * bindings whose scope is no stronger than their delegate's.
- */
- private boolean needsCaching(ContributionBinding binding) {
- if (!binding.scope().isPresent()) {
- return false;
- }
- if (binding.kind().equals(DELEGATE)) {
- return isBindsScopeStrongerThanDependencyScope(binding, graph);
- }
- return true;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentCreatorImplementation.java b/java/dagger/internal/codegen/writing/ComponentCreatorImplementation.java
deleted file mode 100644
index f9d218b..0000000
--- a/java/dagger/internal/codegen/writing/ComponentCreatorImplementation.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableMap;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.binding.ComponentRequirement;
-
-/** The implementation of a component creator type. */
-@AutoValue
-public abstract class ComponentCreatorImplementation {
-
- /** Creates a new {@link ComponentCreatorImplementation}. */
- public static ComponentCreatorImplementation create(
- TypeSpec spec, ClassName name, ImmutableMap<ComponentRequirement, FieldSpec> fields) {
- return new AutoValue_ComponentCreatorImplementation(spec, name, fields);
- }
-
- /** The type spec for the creator implementation. */
- public abstract TypeSpec spec();
-
- /** The name of the creator implementation class. */
- public abstract ClassName name();
-
- /** All fields that are present in this implementation. */
- abstract ImmutableMap<ComponentRequirement, FieldSpec> fields();
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentImplementation.java b/java/dagger/internal/codegen/writing/ComponentImplementation.java
deleted file mode 100644
index ef69124..0000000
--- a/java/dagger/internal/codegen/writing/ComponentImplementation.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2016 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.writing;
-
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.MultimapBuilder;
-import com.squareup.javapoet.AnnotationSpec;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.KeyVariableNamer;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.TypeSpecs;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** The implementation of a component type. */
-public final class ComponentImplementation {
- /** A type of field that this component can contain. */
- public enum FieldSpecKind {
- /** A field for a component shard. */
- COMPONENT_SHARD,
-
- /** A field required by the component, e.g. module instances. */
- COMPONENT_REQUIREMENT_FIELD,
-
- /**
- * A field for the lock and cached value for {@linkplain PrivateMethodBindingExpression
- * private-method scoped bindings}.
- */
- PRIVATE_METHOD_SCOPED_FIELD,
-
- /** A framework field for type T, e.g. {@code Provider<T>}. */
- FRAMEWORK_FIELD,
-
- /** A static field that always returns an absent {@code Optional} value for the binding. */
- ABSENT_OPTIONAL_FIELD
- }
-
- /** A type of method that this component can contain. */
- // TODO(bcorso, dpb): Change the oder to constructor, initialize, component, then private
- // (including MIM and AOM—why treat those separately?).
- public enum MethodSpecKind {
- /** The component constructor. */
- CONSTRUCTOR,
-
- /** A builder method for the component. (Only used by the root component.) */
- BUILDER_METHOD,
-
- /** A private method that wraps dependency expressions. */
- PRIVATE_METHOD,
-
- /** An initialization method that initializes component requirements and framework types. */
- INITIALIZE_METHOD,
-
- /** An implementation of a component interface method. */
- COMPONENT_METHOD,
-
- /** A private method that encapsulates members injection logic for a binding. */
- MEMBERS_INJECTION_METHOD,
-
- /** A static method that always returns an absent {@code Optional} value for the binding. */
- ABSENT_OPTIONAL_METHOD,
-
- /**
- * The {@link dagger.producers.internal.CancellationListener#onProducerFutureCancelled(boolean)}
- * method for a production component.
- */
- CANCELLATION_LISTENER_METHOD,
- ;
- }
-
- /** A type of nested class that this component can contain. */
- public enum TypeSpecKind {
- /** A factory class for a present optional binding. */
- PRESENT_FACTORY,
-
- /** A class for the component creator (only used by the root component.) */
- COMPONENT_CREATOR,
-
- /** A provider class for a component provision. */
- COMPONENT_PROVISION_FACTORY,
-
- /** A class for the subcomponent or subcomponent builder. */
- SUBCOMPONENT
- }
-
- private ComponentImplementation currentShard = this;
- private final Map<Key, ComponentImplementation> shardsByKey = new HashMap<>();
- private final Optional<ComponentImplementation> shardOwner;
- private final BindingGraph graph;
- private final ClassName name;
- private final TypeSpec.Builder component;
- private final SubcomponentNames subcomponentNames;
- private final CompilerOptions compilerOptions;
- private final CodeBlock externalReferenceBlock;
- private final UniqueNameSet componentFieldNames = new UniqueNameSet();
- private final UniqueNameSet componentMethodNames = new UniqueNameSet();
- private final List<CodeBlock> initializations = new ArrayList<>();
- private final List<CodeBlock> componentRequirementInitializations = new ArrayList<>();
- private final Map<ComponentRequirement, String> componentRequirementParameterNames =
- new HashMap<>();
- private final Set<Key> cancellableProducerKeys = new LinkedHashSet<>();
- private final ListMultimap<FieldSpecKind, FieldSpec> fieldSpecsMap =
- MultimapBuilder.enumKeys(FieldSpecKind.class).arrayListValues().build();
- private final ListMultimap<MethodSpecKind, MethodSpec> methodSpecsMap =
- MultimapBuilder.enumKeys(MethodSpecKind.class).arrayListValues().build();
- private final ListMultimap<TypeSpecKind, TypeSpec> typeSpecsMap =
- MultimapBuilder.enumKeys(TypeSpecKind.class).arrayListValues().build();
- private final List<Supplier<TypeSpec>> typeSuppliers = new ArrayList<>();
-
- private ComponentImplementation(
- BindingGraph graph,
- ClassName name,
- SubcomponentNames subcomponentNames,
- CompilerOptions compilerOptions) {
- this.graph = graph;
- this.name = name;
- this.component = classBuilder(name);
- this.subcomponentNames = subcomponentNames;
- this.shardOwner = Optional.empty();
- this.externalReferenceBlock = CodeBlock.of("$T.this", name);
- this.compilerOptions = compilerOptions;
- }
-
- private ComponentImplementation(ComponentImplementation shardOwner, ClassName shardName) {
- this.graph = shardOwner.graph;
- this.name = shardName;
- this.component = classBuilder(shardName);
- this.subcomponentNames = shardOwner.subcomponentNames;
- this.compilerOptions = shardOwner.compilerOptions;
- this.shardOwner = Optional.of(shardOwner);
- String fieldName = UPPER_CAMEL.to(LOWER_CAMEL, name.simpleName());
- String uniqueFieldName = shardOwner.getUniqueFieldName(fieldName);
- this.externalReferenceBlock = CodeBlock.of("$T.this.$N", shardOwner.name, uniqueFieldName);
- shardOwner.addTypeSupplier(() -> generate().build());
- shardOwner.addField(
- FieldSpecKind.COMPONENT_SHARD,
- FieldSpec.builder(name, uniqueFieldName, PRIVATE, FINAL)
- .initializer("new $T()", name)
- .build());
- }
-
- /** Returns a component implementation for a top-level component. */
- public static ComponentImplementation topLevelComponentImplementation(
- BindingGraph graph,
- ClassName name,
- SubcomponentNames subcomponentNames,
- CompilerOptions compilerOptions) {
- return new ComponentImplementation(graph, name, subcomponentNames, compilerOptions);
- }
-
- /** Returns a component implementation that is a child of the current implementation. */
- public ComponentImplementation childComponentImplementation(BindingGraph graph) {
- checkState(!shardOwner.isPresent(), "Shards cannot create child components.");
- ClassName childName = getSubcomponentName(graph.componentDescriptor());
- return new ComponentImplementation(graph, childName, subcomponentNames, compilerOptions);
- }
-
- /** Returns a component implementation that is a shard of the current implementation. */
- public ComponentImplementation shardImplementation(Key key) {
- checkState(!shardOwner.isPresent(), "Shards cannot create other shards.");
- if (!shardsByKey.containsKey(key)) {
- int keysPerShard = compilerOptions.keysPerComponentShard(graph.componentTypeElement());
- if (!shardsByKey.isEmpty() && shardsByKey.size() % keysPerShard == 0) {
- ClassName shardName = name.nestedClass("Shard" + shardsByKey.size() / keysPerShard);
- currentShard = new ComponentImplementation(this, shardName);
- }
- shardsByKey.put(key, currentShard);
- }
- return shardsByKey.get(key);
- }
-
- /** Returns a reference to this compenent when called from a class nested in this component. */
- public CodeBlock externalReferenceBlock() {
- return externalReferenceBlock;
- }
-
- // TODO(ronshapiro): see if we can remove this method and instead inject it in the objects that
- // need it.
- /** Returns the binding graph for the component being generated. */
- public BindingGraph graph() {
- return graph;
- }
-
- /** Returns the descriptor for the component being generated. */
- public ComponentDescriptor componentDescriptor() {
- return graph.componentDescriptor();
- }
-
- /** Returns the name of the component. */
- public ClassName name() {
- return name;
- }
-
- /** Returns whether or not the implementation is nested within another class. */
- public boolean isNested() {
- return name.enclosingClassName() != null;
- }
-
- /**
- * Returns the kind of this component's creator.
- *
- * @throws IllegalStateException if the component has no creator
- */
- private ComponentCreatorKind creatorKind() {
- checkState(componentDescriptor().hasCreator());
- return componentDescriptor()
- .creatorDescriptor()
- .map(ComponentCreatorDescriptor::kind)
- .orElse(BUILDER);
- }
-
- /**
- * Returns the name of the creator class for this component. It will be a sibling of this
- * generated class unless this is a top-level component, in which case it will be nested.
- */
- public ClassName getCreatorName() {
- return isNested()
- ? name.peerClass(subcomponentNames.getCreatorName(componentDescriptor()))
- : name.nestedClass(creatorKind().typeName());
- }
-
- /** Returns the name of the nested implementation class for a child component. */
- private ClassName getSubcomponentName(ComponentDescriptor childDescriptor) {
- checkArgument(
- componentDescriptor().childComponents().contains(childDescriptor),
- "%s is not a child component of %s",
- childDescriptor.typeElement(),
- componentDescriptor().typeElement());
- return name.nestedClass(subcomponentNames.get(childDescriptor) + "Impl");
- }
-
- /**
- * Returns the simple name of the creator implementation class for the given subcomponent creator
- * {@link Key}.
- */
- String getSubcomponentCreatorSimpleName(Key key) {
- return subcomponentNames.getCreatorName(key);
- }
-
- /** Returns {@code true} if {@code type} is accessible from the generated component. */
- boolean isTypeAccessible(TypeMirror type) {
- return isTypeAccessibleFrom(type, name.packageName());
- }
-
- /** Adds the given super type to the component. */
- public void addSupertype(TypeElement supertype) {
- TypeSpecs.addSupertype(component, supertype);
- }
-
- // TODO(dpb): Consider taking FieldSpec, and returning identical FieldSpec with unique name?
- /** Adds the given field to the component. */
- public void addField(FieldSpecKind fieldKind, FieldSpec fieldSpec) {
- fieldSpecsMap.put(fieldKind, fieldSpec);
- }
-
- // TODO(dpb): Consider taking MethodSpec, and returning identical MethodSpec with unique name?
- /** Adds the given method to the component. */
- public void addMethod(MethodSpecKind methodKind, MethodSpec methodSpec) {
- methodSpecsMap.put(methodKind, methodSpec);
- }
-
- /** Adds the given annotation to the component. */
- public void addAnnotation(AnnotationSpec annotation) {
- component.addAnnotation(annotation);
- }
-
- /** Adds the given type to the component. */
- public void addType(TypeSpecKind typeKind, TypeSpec typeSpec) {
- typeSpecsMap.put(typeKind, typeSpec);
- }
-
- /** Adds a {@link Supplier} for the SwitchingProvider for the component. */
- void addTypeSupplier(Supplier<TypeSpec> typeSpecSupplier) {
- typeSuppliers.add(typeSpecSupplier);
- }
-
- /** Adds the given code block to the initialize methods of the component. */
- void addInitialization(CodeBlock codeBlock) {
- initializations.add(codeBlock);
- }
-
- /** Adds the given code block that initializes a {@link ComponentRequirement}. */
- void addComponentRequirementInitialization(CodeBlock codeBlock) {
- componentRequirementInitializations.add(codeBlock);
- }
-
- /**
- * Marks the given key of a producer as one that should have a cancellation statement in the
- * cancellation listener method of the component.
- */
- void addCancellableProducerKey(Key key) {
- cancellableProducerKeys.add(key);
- }
-
- /** Returns a new, unique field name for the component based on the given name. */
- String getUniqueFieldName(String name) {
- return componentFieldNames.getUniqueName(name);
- }
-
- /** Returns a new, unique method name for the component based on the given name. */
- public String getUniqueMethodName(String name) {
- return componentMethodNames.getUniqueName(name);
- }
-
- /** Returns a new, unique method name for a getter method for the given request. */
- String getUniqueMethodName(BindingRequest request) {
- return uniqueMethodName(request, KeyVariableNamer.name(request.key()));
- }
-
- private String uniqueMethodName(BindingRequest request, String bindingName) {
- // This name is intentionally made to match the name for fields in fastInit
- // in order to reduce the constant pool size. b/162004246
- String baseMethodName = bindingName
- + (request.isRequestKind(RequestKind.INSTANCE)
- ? ""
- : UPPER_UNDERSCORE.to(UPPER_CAMEL, request.kindName()));
- return getUniqueMethodName(baseMethodName);
- }
-
- /**
- * Gets the parameter name to use for the given requirement for this component, starting with the
- * given base name if no parameter name has already been selected for the requirement.
- */
- public String getParameterName(ComponentRequirement requirement, String baseName) {
- return componentRequirementParameterNames.computeIfAbsent(
- requirement, r -> getUniqueFieldName(baseName));
- }
-
- /** Claims a new method name for the component. Does nothing if method name already exists. */
- public void claimMethodName(CharSequence name) {
- componentMethodNames.claim(name);
- }
-
- /** Returns the list of {@link CodeBlock}s that need to go in the initialize method. */
- public ImmutableList<CodeBlock> getInitializations() {
- return ImmutableList.copyOf(initializations);
- }
-
- /**
- * Returns a list of {@link CodeBlock}s for initializing {@link ComponentRequirement}s.
- *
- * <p>These initializations are kept separate from {@link #getInitializations()} because they must
- * be executed before the initializations of any framework instance initializations in a
- * superclass implementation that may depend on the instances. We cannot use the same strategy
- * that we use for framework instances (i.e. wrap in a {@link dagger.internal.DelegateFactory} or
- * {@link dagger.producers.internal.DelegateProducer} since the types of these initialized fields
- * have no interface type that we can write a proxy for.
- */
- // TODO(cgdecker): can these be inlined with getInitializations() now that we've turned down
- // ahead-of-time subcomponents?
- public ImmutableList<CodeBlock> getComponentRequirementInitializations() {
- return ImmutableList.copyOf(componentRequirementInitializations);
- }
-
- /**
- * Returns the list of producer {@link Key}s that need cancellation statements in the cancellation
- * listener method.
- */
- public ImmutableList<Key> getCancellableProducerKeys() {
- return ImmutableList.copyOf(cancellableProducerKeys);
- }
-
- /** Generates the component and returns the resulting {@link TypeSpec.Builder}. */
- public TypeSpec.Builder generate() {
- modifiers().forEach(component::addModifiers);
- fieldSpecsMap.asMap().values().forEach(component::addFields);
- methodSpecsMap.asMap().values().forEach(component::addMethods);
- typeSpecsMap.asMap().values().forEach(component::addTypes);
- typeSuppliers.stream().map(Supplier::get).forEach(component::addType);
- return component;
- }
-
- private ImmutableSet<Modifier> modifiers() {
- if (isNested()) {
- return ImmutableSet.of(PRIVATE, FINAL);
- }
- return graph.componentTypeElement().getModifiers().contains(PUBLIC)
- // TODO(ronshapiro): perhaps all generated components should be non-public?
- ? ImmutableSet.of(PUBLIC, FINAL)
- : ImmutableSet.of(FINAL);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentInstanceBindingExpression.java
deleted file mode 100644
index 9fa10c6..0000000
--- a/java/dagger/internal/codegen/writing/ComponentInstanceBindingExpression.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-
-/** A binding expression for the instance of the component itself, i.e. {@code this}. */
-final class ComponentInstanceBindingExpression extends SimpleInvocationBindingExpression {
- private final ClassName componentName;
- private final ContributionBinding binding;
-
- ComponentInstanceBindingExpression(ContributionBinding binding, ClassName componentName) {
- super(binding);
- this.binding = binding;
- this.componentName = componentName;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return Expression.create(
- binding.key().type(),
- componentName.equals(requestingClass)
- ? CodeBlock.of("this")
- : CodeBlock.of("$T.this", componentName));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentMethodBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentMethodBindingExpression.java
deleted file mode 100644
index 7fa9aa3..0000000
--- a/java/dagger/internal/codegen/writing/ComponentMethodBindingExpression.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A binding expression that implements and uses a component method.
- *
- * <p>Dependents of this binding expression will just call the component method.
- */
-final class ComponentMethodBindingExpression extends MethodBindingExpression {
- private final ComponentImplementation componentImplementation;
- private final ComponentMethodDescriptor componentMethod;
-
- ComponentMethodBindingExpression(
- BindingRequest request,
- ContributionBinding binding,
- MethodImplementationStrategy methodImplementationStrategy,
- BindingExpression wrappedBindingExpression,
- ComponentImplementation componentImplementation,
- ComponentMethodDescriptor componentMethod,
- DaggerTypes types) {
- super(
- request,
- binding,
- methodImplementationStrategy,
- wrappedBindingExpression,
- componentImplementation,
- types);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentMethod = checkNotNull(componentMethod);
- }
-
- @Override
- protected CodeBlock getComponentMethodImplementation(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- // There could be several methods on the component for the same request key and kind.
- // Only one should use the BindingMethodImplementation; the others can delegate that one. So
- // use methodImplementation.body() only if componentMethod equals the method for this instance.
-
- // Separately, the method might be defined on a supertype that is also a supertype of some
- // parent component. In that case, the same ComponentMethodDescriptor will be used to add a CMBE
- // for the parent and the child. Only the parent's should use the BindingMethodImplementation;
- // the child's can delegate to the parent. So use methodImplementation.body() only if
- // componentName equals the component for this instance.
- return componentMethod.equals(this.componentMethod) && component.equals(componentImplementation)
- ? methodBodyForComponentMethod(componentMethod)
- : super.getComponentMethodImplementation(componentMethod, component);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- // If a component method returns a primitive, update the expression's type which might be boxed.
- Expression expression = super.getDependencyExpression(requestingClass);
- TypeMirror methodReturnType = componentMethod.methodElement().getReturnType();
- return methodReturnType.getKind().isPrimitive()
- ? Expression.create(methodReturnType, expression.codeBlock())
- : expression;
- }
-
- @Override
- protected void addMethod() {}
-
- @Override
- protected String methodName() {
- return componentMethod.methodElement().getSimpleName().toString();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentProvisionBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentProvisionBindingExpression.java
deleted file mode 100644
index 53914b6..0000000
--- a/java/dagger/internal/codegen/writing/ComponentProvisionBindingExpression.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.Preconditions;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.Expression;
-
-/** A binding expression for component provision methods. */
-final class ComponentProvisionBindingExpression extends SimpleInvocationBindingExpression {
- private final ProvisionBinding binding;
- private final BindingGraph bindingGraph;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final CompilerOptions compilerOptions;
-
- ComponentProvisionBindingExpression(
- ProvisionBinding binding,
- BindingGraph bindingGraph,
- ComponentRequirementExpressions componentRequirementExpressions,
- CompilerOptions compilerOptions) {
- super(binding);
- this.binding = binding;
- this.bindingGraph = checkNotNull(bindingGraph);
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.compilerOptions = checkNotNull(compilerOptions);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- CodeBlock invocation =
- CodeBlock.of(
- "$L.$L()",
- componentRequirementExpressions.getExpression(componentRequirement(), requestingClass),
- binding.bindingElement().get().getSimpleName());
- return Expression.create(
- binding.contributedPrimitiveType().orElse(binding.key().type()),
- maybeCheckForNull(binding, compilerOptions, invocation));
- }
-
- private ComponentRequirement componentRequirement() {
- return bindingGraph
- .componentDescriptor()
- .getDependencyThatDefinesMethod(binding.bindingElement().get());
- }
-
- static CodeBlock maybeCheckForNull(
- ProvisionBinding binding, CompilerOptions compilerOptions, CodeBlock invocation) {
- return binding.shouldCheckForNull(compilerOptions)
- ? CodeBlock.of("$T.checkNotNullFromComponent($L)", Preconditions.class, invocation)
- : invocation;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementBindingExpression.java b/java/dagger/internal/codegen/writing/ComponentRequirementBindingExpression.java
deleted file mode 100644
index 299f279..0000000
--- a/java/dagger/internal/codegen/writing/ComponentRequirementBindingExpression.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-
-/**
- * A binding expression for instances bound with {@link dagger.BindsInstance} and instances of
- * {@linkplain dagger.Component#dependencies() component} and {@linkplain
- * dagger.producers.ProductionComponent#dependencies() production component dependencies}.
- */
-final class ComponentRequirementBindingExpression extends SimpleInvocationBindingExpression {
- private final ComponentRequirement componentRequirement;
- private final ComponentRequirementExpressions componentRequirementExpressions;
-
- ComponentRequirementBindingExpression(
- ContributionBinding binding,
- ComponentRequirement componentRequirement,
- ComponentRequirementExpressions componentRequirementExpressions) {
- super(binding);
- this.componentRequirement = componentRequirement;
- this.componentRequirementExpressions = componentRequirementExpressions;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return Expression.create(
- componentRequirement.type(),
- componentRequirementExpressions.getExpression(componentRequirement, requestingClass));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java b/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
deleted file mode 100644
index 13008b8..0000000
--- a/java/dagger/internal/codegen/writing/ComponentRequirementExpression.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ComponentRequirement;
-
-/**
- * A factory for expressions of {@link ComponentRequirement}s in the generated component. This is
- * <em>not</em> a {@link BindingExpression}, since {@link ComponentRequirement}s do not have a
- * {@link dagger.model.Key}. See {@link ComponentRequirementBindingExpression} for binding
- * expressions that are themselves a component requirement.
- */
-interface ComponentRequirementExpression {
- /**
- * Returns an expression for the {@link ComponentRequirement} to be used when implementing a
- * component method. This may add a field or method to the component in order to reference the
- * component requirement outside of the {@code initialize()} methods.
- */
- CodeBlock getExpression(ClassName requestingClass);
-
- /**
- * Returns an expression for the {@link ComponentRequirement} to be used only within {@code
- * initialize()} methods, where the constructor parameters are available.
- *
- * <p>When accessing this expression from a subcomponent, this may cause a field to be initialized
- * or a method to be added in the component that owns this {@link ComponentRequirement}.
- */
- default CodeBlock getExpressionDuringInitialization(ClassName requestingClass) {
- return getExpression(requestingClass);
- }
-
- /**
- * Returns the expression for the {@link ComponentRequirement} to be used when reimplementing a
- * modifiable module method.
- */
- default CodeBlock getModifiableModuleMethodExpression(ClassName requestingClass) {
- return CodeBlock.of("return $L", getExpression(requestingClass));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java b/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
deleted file mode 100644
index 653a7a2..0000000
--- a/java/dagger/internal/codegen/writing/ComponentRequirementExpressions.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Suppliers.memoize;
-import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.COMPONENT_REQUIREMENT_FIELD;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.google.common.base.Supplier;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import javax.inject.Inject;
-import javax.lang.model.element.TypeElement;
-
-/**
- * A central repository of expressions used to access any {@link ComponentRequirement} available to
- * a component.
- */
-@PerComponentImplementation
-public final class ComponentRequirementExpressions {
-
- // TODO(dpb,ronshapiro): refactor this and ComponentBindingExpressions into a
- // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
- // parents? If so, maybe make ComponentRequirementExpression.Factory create it.
-
- private final Optional<ComponentRequirementExpressions> parent;
- private final Map<ComponentRequirement, ComponentRequirementExpression>
- componentRequirementExpressions = new HashMap<>();
- private final BindingGraph graph;
- private final ComponentImplementation componentImplementation;
- private final ModuleProxies moduleProxies;
-
- // TODO(ronshapiro): give ComponentImplementation a graph() method
- @Inject
- ComponentRequirementExpressions(
- @ParentComponent Optional<ComponentRequirementExpressions> parent,
- BindingGraph graph,
- ComponentImplementation componentImplementation,
- DaggerElements elements,
- ModuleProxies moduleProxies) {
- this.parent = parent;
- this.graph = graph;
- this.componentImplementation = componentImplementation;
- this.moduleProxies = moduleProxies;
- }
-
- /**
- * Returns an expression for the {@code componentRequirement} to be used when implementing a
- * component method. This may add a field or method to the component in order to reference the
- * component requirement outside of the {@code initialize()} methods.
- */
- CodeBlock getExpression(ComponentRequirement componentRequirement, ClassName requestingClass) {
- return getExpression(componentRequirement).getExpression(requestingClass);
- }
-
- /**
- * Returns an expression for the {@code componentRequirement} to be used only within {@code
- * initialize()} methods, where the component constructor parameters are available.
- *
- * <p>When accessing this expression from a subcomponent, this may cause a field to be initialized
- * or a method to be added in the component that owns this {@link ComponentRequirement}.
- */
- CodeBlock getExpressionDuringInitialization(
- ComponentRequirement componentRequirement, ClassName requestingClass) {
- return getExpression(componentRequirement).getExpressionDuringInitialization(requestingClass);
- }
-
- ComponentRequirementExpression getExpression(ComponentRequirement componentRequirement) {
- if (graph.componentRequirements().contains(componentRequirement)) {
- return componentRequirementExpressions.computeIfAbsent(
- componentRequirement, this::createField);
- }
- if (parent.isPresent()) {
- return parent.get().getExpression(componentRequirement);
- }
-
- throw new IllegalStateException(
- "no component requirement expression found for " + componentRequirement);
- }
-
- /** Returns a field for a {@link ComponentRequirement}. */
- private ComponentRequirementExpression createField(ComponentRequirement requirement) {
- if (componentImplementation.componentDescriptor().hasCreator()) {
- return new ComponentParameterField(requirement, componentImplementation, Optional.empty());
- } else if (graph.factoryMethod().isPresent()
- && graph.factoryMethodParameters().containsKey(requirement)) {
- String parameterName =
- graph.factoryMethodParameters().get(requirement).getSimpleName().toString();
- return new ComponentParameterField(
- requirement, componentImplementation, Optional.of(parameterName));
- } else if (requirement.kind().isModule()) {
- return new InstantiableModuleField(requirement, componentImplementation);
- } else {
- throw new AssertionError(
- String.format("Can't create %s in %s", requirement, componentImplementation.name()));
- }
- }
-
- private abstract static class AbstractField implements ComponentRequirementExpression {
- final ComponentRequirement componentRequirement;
- final ComponentImplementation componentImplementation;
- final String fieldName;
- private final Supplier<MemberSelect> field = memoize(this::addField);
-
- private AbstractField(
- ComponentRequirement componentRequirement,
- ComponentImplementation componentImplementation) {
- this.componentRequirement = checkNotNull(componentRequirement);
- this.componentImplementation = checkNotNull(componentImplementation);
- // Note: The field name is being claimed eagerly here even though we don't know at this point
- // whether or not the requirement will even need a field. This is done because:
- // A) ComponentParameterField wants to ensure that it doesn't give the parameter the same name
- // as any field in the component, which requires that it claim a "field name" for itself
- // when naming the parameter.
- // B) The parameter name may be needed before the field name is.
- // C) We want to prefer giving the best name to the field rather than the parameter given its
- // wider scope.
- this.fieldName =
- componentImplementation.getUniqueFieldName(componentRequirement.variableName());
- }
-
- @Override
- public CodeBlock getExpression(ClassName requestingClass) {
- return field.get().getExpressionFor(requestingClass);
- }
-
- private MemberSelect addField() {
- FieldSpec field = createField();
- componentImplementation.addField(COMPONENT_REQUIREMENT_FIELD, field);
- componentImplementation.addComponentRequirementInitialization(fieldInitialization(field));
- return MemberSelect.localField(componentImplementation.name(), fieldName);
- }
-
- private FieldSpec createField() {
- return FieldSpec.builder(TypeName.get(componentRequirement.type()), fieldName, PRIVATE, FINAL)
- .build();
- }
-
- /** Returns the {@link CodeBlock} that initializes the component field during construction. */
- abstract CodeBlock fieldInitialization(FieldSpec componentField);
- }
-
- /**
- * A {@link ComponentRequirementExpression} for {@link ComponentRequirement}s that can be
- * instantiated by the component (i.e. a static class with a no-arg constructor).
- */
- private final class InstantiableModuleField extends AbstractField {
- private final TypeElement moduleElement;
-
- private InstantiableModuleField(
- ComponentRequirement module, ComponentImplementation componentImplementation) {
- super(module, componentImplementation);
- checkArgument(module.kind().isModule());
- this.moduleElement = module.typeElement();
- }
-
- @Override
- CodeBlock fieldInitialization(FieldSpec componentField) {
- return CodeBlock.of(
- "this.$N = $L;",
- componentField,
- moduleProxies.newModuleInstance(moduleElement, componentImplementation.name()));
- }
- }
-
- /**
- * A {@link ComponentRequirementExpression} for {@link ComponentRequirement}s that are passed in
- * as parameters to the component's constructor.
- */
- private static final class ComponentParameterField extends AbstractField {
- private final String parameterName;
-
- private ComponentParameterField(
- ComponentRequirement componentRequirement,
- ComponentImplementation componentImplementation,
- Optional<String> name) {
- super(componentRequirement, componentImplementation);
- // Get the name that the component implementation will use for its parameter for the
- // requirement. If the given name is different than the name of the field created for the
- // requirement (as may be the case when the parameter name is derived from a user-written
- // factory method parameter), just use that as the base name for the parameter. Otherwise,
- // append "Param" to the end of the name to differentiate.
- // In either case, componentImplementation.getParameterName() will ensure that the final name
- // that is used is not the same name as any field in the component even if there's something
- // weird where the component actually has fields named, say, "foo" and "fooParam".
- String baseName = name.filter(n -> !n.equals(fieldName)).orElse(fieldName + "Param");
- this.parameterName = componentImplementation.getParameterName(componentRequirement, baseName);
- }
-
- @Override
- public CodeBlock getExpressionDuringInitialization(ClassName requestingClass) {
- if (componentImplementation.name().equals(requestingClass)) {
- return CodeBlock.of("$L", parameterName);
- } else {
- // requesting this component requirement during initialization of a child component requires
- // it to be accessed from a field and not the parameter (since it is no longer available)
- return getExpression(requestingClass);
- }
- }
-
- @Override
- CodeBlock fieldInitialization(FieldSpec componentField) {
- // Don't checkNotNull here because the parameter may be nullable; if it isn't, the caller
- // should handle checking that before passing the parameter.
- return CodeBlock.of("this.$N = $L;", componentField, parameterName);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/DelegateBindingExpression.java b/java/dagger/internal/codegen/writing/DelegateBindingExpression.java
deleted file mode 100644
index 3361132..0000000
--- a/java/dagger/internal/codegen/writing/DelegateBindingExpression.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
-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.model.BindingKind.DELEGATE;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.BindsTypeChecker;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.RequestKind;
-import javax.lang.model.type.TypeMirror;
-
-/** A {@link dagger.internal.codegen.writing.BindingExpression} for {@code @Binds} methods. */
-final class DelegateBindingExpression extends BindingExpression {
- private final ContributionBinding binding;
- private final RequestKind requestKind;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
- private final BindsTypeChecker bindsTypeChecker;
-
- DelegateBindingExpression(
- ContributionBinding binding,
- RequestKind requestKind,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- DaggerElements elements) {
- this.binding = checkNotNull(binding);
- this.requestKind = checkNotNull(requestKind);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.types = checkNotNull(types);
- this.bindsTypeChecker = new BindsTypeChecker(types, elements);
- }
-
- /**
- * Returns {@code true} if the {@code @Binds} binding's scope is stronger than the scope of the
- * binding it depends on.
- */
- static boolean isBindsScopeStrongerThanDependencyScope(
- ContributionBinding bindsBinding, BindingGraph graph) {
- checkArgument(bindsBinding.kind().equals(DELEGATE));
- Binding dependencyBinding =
- graph.contributionBinding(getOnlyElement(bindsBinding.dependencies()).key());
- ScopeKind bindsScope = ScopeKind.get(bindsBinding);
- ScopeKind dependencyScope = ScopeKind.get(dependencyBinding);
- return bindsScope.isStrongerScopeThan(dependencyScope);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- Expression delegateExpression =
- componentBindingExpressions.getDependencyExpression(
- bindingRequest(getOnlyElement(binding.dependencies()).key(), requestKind),
- requestingClass);
-
- TypeMirror contributedType = binding.contributedType();
- switch (requestKind) {
- case INSTANCE:
- return instanceRequiresCast(delegateExpression, requestingClass)
- ? delegateExpression.castTo(contributedType)
- : delegateExpression;
- default:
- return castToRawTypeIfNecessary(
- delegateExpression, requestType(requestKind, contributedType, types));
- }
- }
-
- private boolean instanceRequiresCast(Expression delegateExpression, ClassName requestingClass) {
- // delegateExpression.type() could be Object if expression is satisfied with a raw
- // Provider's get() method.
- return !bindsTypeChecker.isAssignable(
- delegateExpression.type(), binding.contributedType(), binding.contributionType())
- && isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName());
- }
-
- /**
- * If {@code delegateExpression} can be assigned to {@code desiredType} safely, then {@code
- * delegateExpression} is returned unchanged. If the {@code delegateExpression} is already a raw
- * type, returns {@code delegateExpression} as well, as casting would have no effect. Otherwise,
- * returns a {@link Expression#castTo(TypeMirror) casted} version of {@code delegateExpression}
- * to the raw type of {@code desiredType}.
- */
- // TODO(ronshapiro): this probably can be generalized for usage in InjectionMethods
- private Expression castToRawTypeIfNecessary(
- Expression delegateExpression, TypeMirror desiredType) {
- if (types.isAssignable(delegateExpression.type(), desiredType)) {
- return delegateExpression;
- }
- return delegateExpression.castTo(types.erasure(desiredType));
- }
-
- private enum ScopeKind {
- UNSCOPED,
- SINGLE_CHECK,
- DOUBLE_CHECK,
- ;
-
- static ScopeKind get(Binding binding) {
- return binding
- .scope()
- .map(scope -> scope.isReusable() ? SINGLE_CHECK : DOUBLE_CHECK)
- .orElse(UNSCOPED);
- }
-
- boolean isStrongerScopeThan(ScopeKind other) {
- return this.ordinal() > other.ordinal();
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
deleted file mode 100644
index a7f9556..0000000
--- a/java/dagger/internal/codegen/writing/DelegatingFrameworkInstanceCreationExpression.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.model.DependencyRequest;
-
-/** A framework instance creation expression for a {@link dagger.Binds @Binds} binding. */
-final class DelegatingFrameworkInstanceCreationExpression
- implements FrameworkInstanceCreationExpression {
-
- private final ContributionBinding binding;
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
-
- DelegatingFrameworkInstanceCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- }
-
- @Override
- public CodeBlock creationExpression() {
- DependencyRequest dependency = getOnlyElement(binding.dependencies());
- return CodeBlocks.cast(
- componentBindingExpressions
- .getDependencyExpression(
- bindingRequest(dependency.key(), binding.frameworkType()),
- componentImplementation.name())
- .codeBlock(),
- binding.frameworkType().frameworkClass());
- }
-}
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
deleted file mode 100644
index 5ac1e8f..0000000
--- a/java/dagger/internal/codegen/writing/DependencyMethodProducerCreationExpression.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
-import static dagger.internal.codegen.javapoet.TypeNames.dependencyMethodProducerOf;
-import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-
-/**
- * A {@link dagger.producers.Producer} creation expression 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}.
- */
-// TODO(dpb): Resolve with DependencyMethodProviderCreationExpression.
-final class DependencyMethodProducerCreationExpression
- implements FrameworkInstanceCreationExpression {
- private final ContributionBinding binding;
- private final ComponentImplementation componentImplementation;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final BindingGraph graph;
-
- DependencyMethodProducerCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentRequirementExpressions componentRequirementExpressions,
- BindingGraph graph) {
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.graph = checkNotNull(graph);
- }
-
- @Override
- public CodeBlock creationExpression() {
- ComponentRequirement dependency =
- graph.componentDescriptor().getDependencyThatDefinesMethod(binding.bindingElement().get());
- FieldSpec dependencyField =
- FieldSpec.builder(
- ClassName.get(dependency.typeElement()), dependency.variableName(), PRIVATE, FINAL)
- .initializer(
- componentRequirementExpressions.getExpressionDuringInitialization(
- dependency,
- // This isn't a real class name, but we want the requesting class for the
- // expression to *not* be the same class as the component implementation,
- // because it isn't... it's an anonymous inner class.
- // TODO(cgdecker): If we didn't use an anonymous inner class here but instead
- // generated a named nested class as with
- // DependencyMethodProviderCreationExpression, we wouldn't need to deal with
- // this and might be able to avoid potentially creating an extra field in the
- // component?
- componentImplementation.name().nestedClass("Anonymous")))
- .build();
- // TODO(b/70395982): Explore using a private static type instead of an anonymous class.
- TypeName keyType = TypeName.get(binding.key().type());
- return CodeBlock.of(
- "$L",
- anonymousClassBuilder("")
- .superclass(dependencyMethodProducerOf(keyType))
- .addField(dependencyField)
- .addMethod(
- methodBuilder("callDependencyMethod")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(listenableFutureOf(keyType))
- .addStatement(
- "return $N.$L()",
- dependencyField,
- binding.bindingElement().get().getSimpleName())
- .build())
- .build());
- }
-}
diff --git a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java b/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
deleted file mode 100644
index 5a40c02..0000000
--- a/java/dagger/internal/codegen/writing/DependencyMethodProviderCreationExpression.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.COMPONENT_PROVISION_FACTORY;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.common.MoreTypes;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import javax.lang.model.element.Element;
-
-/**
- * A {@link javax.inject.Provider} creation expression for a provision method on a component's
- * {@linkplain dagger.Component#dependencies()} dependency}.
- */
-// TODO(dpb): Resolve with DependencyMethodProducerCreationExpression.
-final class DependencyMethodProviderCreationExpression
- implements FrameworkInstanceCreationExpression {
-
- private final ComponentImplementation componentImplementation;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final CompilerOptions compilerOptions;
- private final BindingGraph graph;
- private final ContributionBinding binding;
-
- DependencyMethodProviderCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentRequirementExpressions componentRequirementExpressions,
- CompilerOptions compilerOptions,
- BindingGraph graph) {
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentRequirementExpressions = checkNotNull(componentRequirementExpressions);
- this.compilerOptions = checkNotNull(compilerOptions);
- this.graph = checkNotNull(graph);
- }
-
- @Override
- public CodeBlock creationExpression() {
- // TODO(sameb): The Provider.get() throws a very vague NPE. The stack trace doesn't
- // help to figure out what the method or return type is. If we include a string
- // of the return type or method name in the error message, that can defeat obfuscation.
- // We can easily include the raw type (no generics) + annotation type (no values),
- // using .class & String.format -- but that wouldn't be the whole story.
- // What should we do?
- CodeBlock invocation =
- ComponentProvisionBindingExpression.maybeCheckForNull(
- (ProvisionBinding) binding,
- compilerOptions,
- CodeBlock.of(
- "$N.$N()", dependency().variableName(), provisionMethod().getSimpleName()));
- ClassName dependencyClassName = ClassName.get(dependency().typeElement());
- TypeName keyType = TypeName.get(binding.key().type());
- MethodSpec.Builder getMethod =
- methodBuilder("get")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(keyType)
- .addStatement("return $L", invocation);
- if (binding.nullableType().isPresent()) {
- getMethod.addAnnotation(ClassName.get(MoreTypes.asTypeElement(binding.nullableType().get())));
- }
- componentImplementation.addType(
- COMPONENT_PROVISION_FACTORY,
- classBuilder(factoryClassName())
- .addSuperinterface(providerOf(keyType))
- .addModifiers(PRIVATE, STATIC)
- .addField(dependencyClassName, dependency().variableName(), PRIVATE, FINAL)
- .addMethod(
- constructorBuilder()
- .addParameter(dependencyClassName, dependency().variableName())
- .addStatement("this.$1L = $1L", dependency().variableName())
- .build())
- .addMethod(getMethod.build())
- .build());
- return CodeBlock.of(
- "new $T($L)",
- factoryClassName(),
- componentRequirementExpressions.getExpressionDuringInitialization(
- dependency(), componentImplementation.name()));
- }
-
- private ClassName factoryClassName() {
- String factoryName =
- ClassName.get(dependency().typeElement()).toString().replace('.', '_')
- + "_"
- + binding.bindingElement().get().getSimpleName();
- return componentImplementation.name().nestedClass(factoryName);
- }
-
- private ComponentRequirement dependency() {
- return graph.componentDescriptor().getDependencyThatDefinesMethod(provisionMethod());
- }
-
- private Element provisionMethod() {
- return binding.bindingElement().get();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java
deleted file mode 100644
index 6e5dca8..0000000
--- a/java/dagger/internal/codegen/writing/DerivedFromFrameworkInstanceBindingExpression.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-
-/** A binding expression that depends on a framework instance. */
-final class DerivedFromFrameworkInstanceBindingExpression extends BindingExpression {
-
- private final BindingRequest frameworkRequest;
- private final RequestKind requestKind;
- private final FrameworkType frameworkType;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
-
- DerivedFromFrameworkInstanceBindingExpression(
- Key key,
- FrameworkType frameworkType,
- RequestKind requestKind,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types) {
- this.frameworkRequest = bindingRequest(key, frameworkType);
- this.requestKind = checkNotNull(requestKind);
- this.frameworkType = checkNotNull(frameworkType);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.types = checkNotNull(types);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return frameworkType.to(
- requestKind,
- componentBindingExpressions.getDependencyExpression(frameworkRequest, requestingClass),
- types);
- }
-
- @Override
- Expression getDependencyExpressionForComponentMethod(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- Expression frameworkInstance =
- componentBindingExpressions.getDependencyExpressionForComponentMethod(
- frameworkRequest, componentMethod, component);
- return frameworkType.to(requestKind, frameworkInstance, types);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/FactoryGenerator.java b/java/dagger/internal/codegen/writing/FactoryGenerator.java
deleted file mode 100644
index 70edd1a..0000000
--- a/java/dagger/internal/codegen/writing/FactoryGenerator.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2014 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Maps.transformValues;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameters;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.DELEGATE;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
-import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
-import static dagger.internal.codegen.binding.SourceFiles.frameworkFieldUsages;
-import static dagger.internal.codegen.binding.SourceFiles.frameworkTypeUsageStatement;
-import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-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.writing.GwtCompatibility.gwtIncompatibleAnnotation;
-import static dagger.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;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.Factory;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import java.util.List;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-
-/**
- * Generates {@link Factory} implementations from {@link ProvisionBinding} instances for {@link
- * Inject} constructors.
- */
-public final class FactoryGenerator extends SourceFileGenerator<ProvisionBinding> {
- private final DaggerTypes types;
- private final CompilerOptions compilerOptions;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- FactoryGenerator(
- Filer filer,
- SourceVersion sourceVersion,
- DaggerTypes types,
- DaggerElements elements,
- CompilerOptions compilerOptions,
- KotlinMetadataUtil metadataUtil) {
- super(filer, elements, sourceVersion);
- this.types = types;
- this.compilerOptions = compilerOptions;
- this.metadataUtil = metadataUtil;
- }
-
- @Override
- public ClassName nameGeneratedType(ProvisionBinding binding) {
- return generatedClassNameForBinding(binding);
- }
-
- @Override
- public Element originatingElement(ProvisionBinding binding) {
- // we only create factories for bindings that have a binding element
- return binding.bindingElement().get();
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(ProvisionBinding binding) {
- // We don't want to write out resolved bindings -- we want to write out the generic version.
- checkArgument(!binding.unresolved().isPresent());
- checkArgument(binding.bindingElement().isPresent());
-
- if (binding.factoryCreationStrategy().equals(DELEGATE)) {
- return Optional.empty();
- }
-
- return Optional.of(factoryBuilder(binding));
- }
-
- private TypeSpec.Builder factoryBuilder(ProvisionBinding binding) {
- TypeSpec.Builder factoryBuilder =
- classBuilder(nameGeneratedType(binding))
- .addModifiers(PUBLIC, FINAL)
- .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
-
- factoryTypeName(binding).ifPresent(factoryBuilder::addSuperinterface);
- addConstructorAndFields(binding, factoryBuilder);
- factoryBuilder.addMethod(getMethod(binding));
- addCreateMethod(binding, factoryBuilder);
-
- factoryBuilder.addMethod(ProvisionMethod.create(binding, compilerOptions, metadataUtil));
- gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
-
- return factoryBuilder;
- }
-
- private void addConstructorAndFields(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
- if (binding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)) {
- return;
- }
- // TODO(bcorso): Make the constructor private?
- MethodSpec.Builder constructor = constructorBuilder().addModifiers(PUBLIC);
- constructorParams(binding).forEach(
- param -> {
- constructor.addParameter(param).addStatement("this.$1N = $1N", param);
- factoryBuilder.addField(
- FieldSpec.builder(param.type, param.name, PRIVATE, FINAL).build());
- });
- factoryBuilder.addMethod(constructor.build());
- }
-
- private ImmutableList<ParameterSpec> constructorParams(ProvisionBinding binding) {
- ImmutableList.Builder<ParameterSpec> params = ImmutableList.builder();
- moduleParameter(binding).ifPresent(params::add);
- frameworkFields(binding).values().forEach(field -> params.add(toParameter(field)));
- return params.build();
- }
-
- private Optional<ParameterSpec> moduleParameter(ProvisionBinding binding) {
- if (binding.requiresModuleInstance()) {
- // TODO(bcorso, dpb): Should this use contributingModule()?
- TypeName type = TypeName.get(binding.bindingTypeElement().get().asType());
- return Optional.of(ParameterSpec.builder(type, "module").build());
- }
- return Optional.empty();
- }
-
- private ImmutableMap<DependencyRequest, FieldSpec> frameworkFields(ProvisionBinding binding) {
- UniqueNameSet uniqueFieldNames = new UniqueNameSet();
- // TODO(bcorso, dpb): Add a test for the case when a Factory parameter is named "module".
- moduleParameter(binding).ifPresent(module -> uniqueFieldNames.claim(module.name));
- return ImmutableMap.copyOf(
- transformValues(
- generateBindingFieldsForDependencies(binding),
- field ->
- FieldSpec.builder(
- field.type(), uniqueFieldNames.getUniqueName(field.name()), PRIVATE, FINAL)
- .build()));
- }
-
- private void addCreateMethod(ProvisionBinding binding, TypeSpec.Builder factoryBuilder) {
- // If constructing a factory for @Inject or @Provides bindings, we use a static create method
- // so that generated components can avoid having to refer to the generic types
- // of the factory. (Otherwise they may have visibility problems referring to the types.)
- MethodSpec.Builder createMethodBuilder =
- methodBuilder("create")
- .addModifiers(PUBLIC, STATIC)
- .returns(parameterizedGeneratedTypeNameForBinding(binding))
- .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
-
- switch (binding.factoryCreationStrategy()) {
- case SINGLETON_INSTANCE:
- FieldSpec.Builder instanceFieldBuilder =
- FieldSpec.builder(nameGeneratedType(binding), "INSTANCE", PRIVATE, STATIC, FINAL)
- .initializer("new $T()", nameGeneratedType(binding));
-
- if (!bindingTypeElementTypeVariableNames(binding).isEmpty()) {
- // If the factory has type parameters, ignore them in the field declaration & initializer
- instanceFieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
- createMethodBuilder.addAnnotation(suppressWarnings(UNCHECKED));
- }
-
- ClassName instanceHolderName = nameGeneratedType(binding).nestedClass("InstanceHolder");
- createMethodBuilder.addStatement("return $T.INSTANCE", instanceHolderName);
- factoryBuilder.addType(
- TypeSpec.classBuilder(instanceHolderName)
- .addModifiers(PRIVATE, STATIC, FINAL)
- .addField(instanceFieldBuilder.build())
- .build());
- break;
- case CLASS_CONSTRUCTOR:
- List<ParameterSpec> params = constructorParams(binding);
- createMethodBuilder.addParameters(params);
- createMethodBuilder.addStatement(
- "return new $T($L)",
- parameterizedGeneratedTypeNameForBinding(binding),
- makeParametersCodeBlock(Lists.transform(params, input -> CodeBlock.of("$N", input))));
- break;
- default:
- throw new AssertionError();
- }
- factoryBuilder.addMethod(createMethodBuilder.build());
- }
-
- private MethodSpec getMethod(ProvisionBinding binding) {
- TypeName providedTypeName = providedTypeName(binding);
- MethodSpec.Builder getMethod =
- methodBuilder("get")
- .addModifiers(PUBLIC)
- .returns(providedTypeName)
- .addParameters(
- // The 'get' method for an assisted injection type takes in the assisted parameters.
- assistedParameters(binding).stream()
- .map(ParameterSpec::get)
- .collect(toImmutableList()));
-
- if (factoryTypeName(binding).isPresent()) {
- getMethod.addAnnotation(Override.class);
- }
-
- ImmutableMap<DependencyRequest, FieldSpec> frameworkFields = frameworkFields(binding);
- CodeBlock invokeNewInstance =
- ProvisionMethod.invoke(
- binding,
- request ->
- frameworkTypeUsageStatement(
- CodeBlock.of("$N", frameworkFields.get(request)), request.kind()),
- nameGeneratedType(binding),
- moduleParameter(binding).map(module -> CodeBlock.of("$N", module)),
- compilerOptions,
- metadataUtil);
-
- if (binding.kind().equals(PROVISION)) {
- binding
- .nullableType()
- .ifPresent(nullableType -> CodeBlocks.addAnnotation(getMethod, nullableType));
- getMethod.addStatement("return $L", invokeNewInstance);
- } else if (!binding.injectionSites().isEmpty()) {
- CodeBlock instance = CodeBlock.of("instance");
- getMethod
- .addStatement("$T $L = $L", providedTypeName, instance, invokeNewInstance)
- .addCode(
- InjectionSiteMethod.invokeAll(
- binding.injectionSites(),
- nameGeneratedType(binding),
- instance,
- binding.key().type(),
- frameworkFieldUsages(binding.dependencies(), frameworkFields)::get,
- types,
- metadataUtil))
- .addStatement("return $L", instance);
- } else {
- getMethod.addStatement("return $L", invokeNewInstance);
- }
- return getMethod.build();
- }
-
- private static TypeName providedTypeName(ProvisionBinding binding) {
- return TypeName.get(binding.contributedType());
- }
-
- private static Optional<TypeName> factoryTypeName(ProvisionBinding binding) {
- return binding.kind() == BindingKind.ASSISTED_INJECTION
- ? Optional.empty()
- : Optional.of(factoryOf(providedTypeName(binding)));
- }
-
- private static ParameterSpec toParameter(FieldSpec field) {
- return ParameterSpec.builder(field.type, field.name).build();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java b/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
deleted file mode 100644
index c17ff8e..0000000
--- a/java/dagger/internal/codegen/writing/FrameworkFieldInitializer.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.FRAMEWORK_FIELD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.google.auto.common.MoreTypes;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.DelegateFactory;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkField;
-import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.model.BindingKind;
-import dagger.producers.internal.DelegateProducer;
-import java.util.Optional;
-
-/**
- * An object that can initialize a framework-type component field for a binding. An instance should
- * be created for each field.
- */
-class FrameworkFieldInitializer implements FrameworkInstanceSupplier {
-
- /**
- * An object that can determine the expression to use to assign to the component field for a
- * binding.
- */
- interface FrameworkInstanceCreationExpression {
- /** Returns the expression to use to assign to the component field for the binding. */
- CodeBlock creationExpression();
-
- /**
- * Returns the framework class to use for the field, if different from the one implied by the
- * binding. This implementation returns {@link Optional#empty()}.
- */
- default Optional<ClassName> alternativeFrameworkClass() {
- return Optional.empty();
- }
-
- /**
- * Returns {@code true} if instead of using {@link #creationExpression()} to create a framework
- * instance, a case in {@link InnerSwitchingProviders} should be created for this binding.
- */
- // TODO(ronshapiro): perhaps this isn't the right approach. Instead of saying "Use
- // SetFactory.EMPTY because you will only get 1 class for all types of bindings that use
- // SetFactory", maybe we should still use an inner switching provider but the same switching
- // provider index for all cases.
- default boolean useInnerSwitchingProvider() {
- return true;
- }
- }
-
- private final ComponentImplementation componentImplementation;
- private final ContributionBinding binding;
- private final FrameworkInstanceCreationExpression frameworkInstanceCreationExpression;
- private FieldSpec fieldSpec;
- private InitializationState fieldInitializationState = InitializationState.UNINITIALIZED;
-
- FrameworkFieldInitializer(
- ComponentImplementation componentImplementation,
- ContributionBinding binding,
- FrameworkInstanceCreationExpression frameworkInstanceCreationExpression) {
- this.componentImplementation = checkNotNull(componentImplementation);
- this.binding = checkNotNull(binding);
- this.frameworkInstanceCreationExpression = checkNotNull(frameworkInstanceCreationExpression);
- }
-
- /**
- * Returns the {@link MemberSelect} for the framework field, and adds the field and its
- * initialization code to the component if it's needed and not already added.
- */
- @Override
- public final MemberSelect memberSelect() {
- initializeField();
- return MemberSelect.localField(componentImplementation.name(), checkNotNull(fieldSpec).name);
- }
-
- /** Adds the field and its initialization code to the component. */
- private void initializeField() {
- switch (fieldInitializationState) {
- case UNINITIALIZED:
- // Change our state in case we are recursively invoked via initializeBindingExpression
- fieldInitializationState = InitializationState.INITIALIZING;
- CodeBlock.Builder codeBuilder = CodeBlock.builder();
- CodeBlock fieldInitialization = frameworkInstanceCreationExpression.creationExpression();
- CodeBlock initCode = CodeBlock.of("this.$N = $L;", getOrCreateField(), fieldInitialization);
-
- if (fieldInitializationState == InitializationState.DELEGATED) {
- codeBuilder.add(
- "$T.setDelegate($N, $L);", delegateType(), fieldSpec, fieldInitialization);
- } else {
- codeBuilder.add(initCode);
- }
- componentImplementation.addInitialization(codeBuilder.build());
-
- fieldInitializationState = InitializationState.INITIALIZED;
- break;
-
- case INITIALIZING:
- // We were recursively invoked, so create a delegate factory instead
- fieldInitializationState = InitializationState.DELEGATED;
- componentImplementation.addInitialization(
- CodeBlock.of("this.$N = new $T<>();", getOrCreateField(), delegateType()));
- break;
-
- case DELEGATED:
- case INITIALIZED:
- break;
- }
- }
-
- /**
- * Adds a field representing the resolved bindings, optionally forcing it to use a particular
- * binding type (instead of the type the resolved bindings would typically use).
- */
- private FieldSpec getOrCreateField() {
- if (fieldSpec != null) {
- return fieldSpec;
- }
- boolean useRawType = !componentImplementation.isTypeAccessible(binding.key().type());
- FrameworkField contributionBindingField =
- FrameworkField.forBinding(
- binding, frameworkInstanceCreationExpression.alternativeFrameworkClass());
-
- TypeName fieldType =
- useRawType ? contributionBindingField.type().rawType : contributionBindingField.type();
-
- if (binding.kind() == BindingKind.ASSISTED_INJECTION) {
- // An assisted injection factory doesn't extend Provider, so we reference the generated
- // factory type directly (i.e. Foo_Factory<T> instead of Provider<Foo<T>>).
- TypeName[] typeParameters =
- MoreTypes.asDeclared(binding.key().type()).getTypeArguments().stream()
- .map(TypeName::get)
- .toArray(TypeName[]::new);
- fieldType =
- typeParameters.length == 0
- ? generatedClassNameForBinding(binding)
- : ParameterizedTypeName.get(generatedClassNameForBinding(binding), typeParameters);
- }
-
- FieldSpec.Builder contributionField =
- FieldSpec.builder(
- fieldType, componentImplementation.getUniqueFieldName(contributionBindingField.name()));
- contributionField.addModifiers(PRIVATE);
- if (useRawType) {
- contributionField.addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES));
- }
-
- fieldSpec = contributionField.build();
- componentImplementation.addField(FRAMEWORK_FIELD, fieldSpec);
-
- return fieldSpec;
- }
-
- private Class<?> delegateType() {
- return isProvider() ? DelegateFactory.class : DelegateProducer.class;
- }
-
- private boolean isProvider() {
- return binding.bindingType().equals(BindingType.PROVISION)
- && frameworkInstanceCreationExpression
- .alternativeFrameworkClass()
- .map(TypeNames.PROVIDER::equals)
- .orElse(true);
- }
-
- /** Initialization state for a factory field. */
- private enum InitializationState {
- /** The field is {@code null}. */
- UNINITIALIZED,
-
- /**
- * The field's dependencies are being set up. If the field is needed in this state, use a {@link
- * DelegateFactory}.
- */
- INITIALIZING,
-
- /**
- * The field's dependencies are being set up, but the field can be used because it has already
- * been set to a {@link DelegateFactory}.
- */
- DELEGATED,
-
- /** The field is set to an undelegated factory. */
- INITIALIZED;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/FrameworkInstanceBindingExpression.java
deleted file mode 100644
index 56a6ef3..0000000
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceBindingExpression.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression that uses a {@link FrameworkType} field. */
-abstract class FrameworkInstanceBindingExpression extends BindingExpression {
- private final ContributionBinding binding;
- private final FrameworkInstanceSupplier frameworkInstanceSupplier;
- private final DaggerTypes types;
- private final DaggerElements elements;
-
- FrameworkInstanceBindingExpression(
- ContributionBinding binding,
- FrameworkInstanceSupplier frameworkInstanceSupplier,
- DaggerTypes types,
- DaggerElements elements) {
- this.binding = checkNotNull(binding);
- this.frameworkInstanceSupplier = checkNotNull(frameworkInstanceSupplier);
- this.types = checkNotNull(types);
- this.elements = checkNotNull(elements);
- }
-
- /**
- * The expression for the framework instance for this binding. The field will be {@link
- * ComponentImplementation#addInitialization(CodeBlock) initialized} and {@link
- * ComponentImplementation#addField(ComponentImplementation.FieldSpecKind, FieldSpec) added} to
- * the component the first time this method is invoked.
- */
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- MemberSelect memberSelect = frameworkInstanceSupplier.memberSelect();
- TypeMirror expressionType =
- isTypeAccessibleFrom(binding.contributedType(), requestingClass.packageName())
- || isInlinedFactoryCreation(memberSelect)
- ? types.wrapType(binding.contributedType(), frameworkType().frameworkClass())
- : rawFrameworkType();
- return Expression.create(expressionType, memberSelect.getExpressionFor(requestingClass));
- }
-
- /** Returns the framework type for the binding. */
- protected abstract FrameworkType frameworkType();
-
- /**
- * Returns {@code true} if a factory is created inline each time it is requested. For example, in
- * the initialization {@code this.fooProvider = Foo_Factory.create(Bar_Factory.create());}, {@code
- * Bar_Factory} is considered to be inline.
- *
- * <p>This is used in {@link #getDependencyExpression(ClassName)} when determining the type of a
- * factory. Normally if the {@link ContributionBinding#contributedType()} is not accessible from
- * the component, the type of the expression will be a raw {@link javax.inject.Provider}. However,
- * if the factory is created inline, even if contributed type is not accessible, javac will still
- * be able to determine the type that is returned from the {@code Foo_Factory.create()} method.
- */
- private static boolean isInlinedFactoryCreation(MemberSelect memberSelect) {
- return memberSelect.staticMember();
- }
-
- private DeclaredType rawFrameworkType() {
- return types.getDeclaredType(elements.getTypeElement(frameworkType().frameworkClass()));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/FrameworkInstanceSupplier.java b/java/dagger/internal/codegen/writing/FrameworkInstanceSupplier.java
deleted file mode 100644
index cc0e136..0000000
--- a/java/dagger/internal/codegen/writing/FrameworkInstanceSupplier.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-/** An object that supplies a {@link MemberSelect} for a framework instance. */
-interface FrameworkInstanceSupplier {
- /** Returns a {@link MemberSelect}, with possible side effects on the first call. */
- MemberSelect memberSelect();
-}
diff --git a/java/dagger/internal/codegen/writing/GwtCompatibility.java b/java/dagger/internal/codegen/writing/GwtCompatibility.java
deleted file mode 100644
index 2df6a99..0000000
--- a/java/dagger/internal/codegen/writing/GwtCompatibility.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.squareup.javapoet.AnnotationSpec;
-import dagger.internal.codegen.binding.Binding;
-import java.util.Optional;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.Name;
-
-final class GwtCompatibility {
-
- /**
- * Returns a {@code @GwtIncompatible} annotation that is applied to {@code binding}'s {@link
- * Binding#bindingElement()} or any enclosing type.
- */
- static Optional<AnnotationSpec> gwtIncompatibleAnnotation(Binding binding) {
- checkArgument(binding.bindingElement().isPresent());
- Element element = binding.bindingElement().get();
- while (element != null) {
- Optional<AnnotationSpec> gwtIncompatible =
- element
- .getAnnotationMirrors()
- .stream()
- .filter(annotation -> isGwtIncompatible(annotation))
- .map(AnnotationSpec::get)
- .findFirst();
- if (gwtIncompatible.isPresent()) {
- return gwtIncompatible;
- }
- element = element.getEnclosingElement();
- }
- return Optional.empty();
- }
-
- private static boolean isGwtIncompatible(AnnotationMirror annotation) {
- Name simpleName = annotation.getAnnotationType().asElement().getSimpleName();
- return simpleName.contentEquals("GwtIncompatible");
- }
-}
diff --git a/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java b/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java
deleted file mode 100644
index 5a4b6f1..0000000
--- a/java/dagger/internal/codegen/writing/HjarSourceFileGenerator.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import java.util.Optional;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.Modifier;
-
-/**
- * A source file generator that only writes the relevant code necessary for Bazel to create a
- * correct header (ABI) jar.
- */
-public final class HjarSourceFileGenerator<T> extends SourceFileGenerator<T> {
- private final SourceFileGenerator<T> delegate;
-
- private HjarSourceFileGenerator(SourceFileGenerator<T> delegate) {
- super(delegate);
- this.delegate = delegate;
- }
-
- public static <T> SourceFileGenerator<T> wrap(SourceFileGenerator<T> delegate) {
- return new HjarSourceFileGenerator<>(delegate);
- }
-
- @Override
- public ClassName nameGeneratedType(T input) {
- return delegate.nameGeneratedType(input);
- }
-
- @Override
- public Element originatingElement(T input) {
- return delegate.originatingElement(input);
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(T input) {
- return delegate.write(input).map(completeType -> skeletonType(completeType.build()));
- }
-
- private TypeSpec.Builder skeletonType(TypeSpec completeType) {
- TypeSpec.Builder skeleton =
- classBuilder(completeType.name)
- .addSuperinterfaces(completeType.superinterfaces)
- .addTypeVariables(completeType.typeVariables)
- .addModifiers(completeType.modifiers.toArray(new Modifier[0]))
- .addAnnotations(completeType.annotations);
-
- if (!completeType.superclass.equals(ClassName.OBJECT)) {
- skeleton.superclass(completeType.superclass);
- }
-
- completeType.methodSpecs.stream()
- .filter(method -> !method.modifiers.contains(PRIVATE) || method.isConstructor())
- .map(this::skeletonMethod)
- .forEach(skeleton::addMethod);
-
- completeType.fieldSpecs.stream()
- .filter(field -> !field.modifiers.contains(PRIVATE))
- .map(this::skeletonField)
- .forEach(skeleton::addField);
-
- completeType.typeSpecs.stream()
- .map(type -> skeletonType(type).build())
- .forEach(skeleton::addType);
-
- return skeleton;
- }
-
- private MethodSpec skeletonMethod(MethodSpec completeMethod) {
- MethodSpec.Builder skeleton =
- completeMethod.isConstructor()
- ? constructorBuilder()
- : methodBuilder(completeMethod.name).returns(completeMethod.returnType);
-
- if (completeMethod.isConstructor()) {
- // Code in Turbine must (for technical reasons in javac) have a valid super() call for
- // constructors, otherwise javac will bark, and Turbine has no way to avoid this. So we retain
- // constructor method bodies if they do exist
- skeleton.addCode(completeMethod.code);
- }
-
- return skeleton
- .addModifiers(completeMethod.modifiers)
- .addTypeVariables(completeMethod.typeVariables)
- .addParameters(completeMethod.parameters)
- .addExceptions(completeMethod.exceptions)
- .varargs(completeMethod.varargs)
- .addAnnotations(completeMethod.annotations)
- .build();
- }
-
- private FieldSpec skeletonField(FieldSpec completeField) {
- return FieldSpec.builder(
- completeField.type,
- completeField.name,
- completeField.modifiers.toArray(new Modifier[0]))
- .addAnnotations(completeField.annotations)
- .build();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ImmediateFutureBindingExpression.java b/java/dagger/internal/codegen/writing/ImmediateFutureBindingExpression.java
deleted file mode 100644
index dcd02fa..0000000
--- a/java/dagger/internal/codegen/writing/ImmediateFutureBindingExpression.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import javax.lang.model.SourceVersion;
-
-final class ImmediateFutureBindingExpression extends BindingExpression {
- private final Key key;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
- private final SourceVersion sourceVersion;
-
- ImmediateFutureBindingExpression(
- Key key,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- SourceVersion sourceVersion) {
- this.key = key;
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- this.types = checkNotNull(types);
- this.sourceVersion = checkNotNull(sourceVersion);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return Expression.create(
- types.wrapType(key.type(), ListenableFuture.class),
- CodeBlock.of("$T.immediateFuture($L)", Futures.class, instanceExpression(requestingClass)));
- }
-
- private CodeBlock instanceExpression(ClassName requestingClass) {
- Expression expression =
- componentBindingExpressions.getDependencyExpression(
- bindingRequest(key, RequestKind.INSTANCE), requestingClass);
- if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
- // Java 7 type inference is not as strong as in Java 8, and therefore some generated code must
- // cast.
- //
- // For example, javac7 cannot detect that Futures.immediateFuture(ImmutableSet.of("T"))
- // can safely be assigned to ListenableFuture<Set<T>>.
- if (!types.isSameType(expression.type(), key.type())) {
- return CodeBlock.of(
- "($T) $L", types.accessibleType(key.type(), requestingClass), expression.codeBlock());
- }
- }
- return expression.codeBlock();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java b/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
deleted file mode 100644
index d527359..0000000
--- a/java/dagger/internal/codegen/writing/InaccessibleMapKeyProxyGenerator.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.MapKeys;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-
-/**
- * Generates a class that exposes a non-{@code public} {@link
- * ContributionBinding#mapKeyAnnotation()} @MapKey} annotation.
- */
-public final class InaccessibleMapKeyProxyGenerator
- extends SourceFileGenerator<ContributionBinding> {
- private final DaggerTypes types;
- private final DaggerElements elements;
-
- @Inject
- InaccessibleMapKeyProxyGenerator(
- Filer filer, DaggerTypes types, DaggerElements elements, SourceVersion sourceVersion) {
- super(filer, elements, sourceVersion);
- this.types = types;
- this.elements = elements;
- }
-
- @Override
- public ClassName nameGeneratedType(ContributionBinding binding) {
- return MapKeys.mapKeyProxyClassName(binding);
- }
-
- @Override
- public Element originatingElement(ContributionBinding binding) {
- // a map key is only ever present on bindings that have a binding element
- return binding.bindingElement().get();
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(ContributionBinding binding) {
- return MapKeys.mapKeyFactoryMethod(binding, types, elements)
- .map(
- method ->
- classBuilder(nameGeneratedType(binding))
- .addModifiers(PUBLIC, FINAL)
- .addMethod(constructorBuilder().addModifiers(PRIVATE).build())
- .addMethod(method));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/InjectionMethods.java b/java/dagger/internal/codegen/writing/InjectionMethods.java
deleted file mode 100644
index 7cebc10..0000000
--- a/java/dagger/internal/codegen/writing/InjectionMethods.java
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.auto.common.MoreElements.asVariable;
-import static com.google.common.base.CaseFormat.LOWER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.base.RequestKinds.requestTypeName;
-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;
-import static dagger.internal.codegen.binding.SourceFiles.protectAgainstKeywords;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toConcatenatedCodeBlock;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
-import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
-import static dagger.internal.codegen.langmodel.Accessibility.isRawTypeAccessible;
-import static dagger.internal.codegen.langmodel.Accessibility.isRawTypePubliclyAccessible;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static java.util.stream.Collectors.toList;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-import static javax.lang.model.type.TypeKind.VOID;
-
-import com.google.auto.common.MoreElements;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-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.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeVariableName;
-import dagger.internal.Preconditions;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.AssistedInjectionAnnotations;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.extension.DaggerCollectors;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import dagger.model.RequestKind;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Function;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Parameterizable;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-/** Convenience methods for creating and invoking {@link InjectionMethod}s. */
-final class InjectionMethods {
-
- /**
- * A method that returns an object from a {@code @Provides} method or an {@code @Inject}ed
- * constructor. Its parameters match the dependency requests for constructor and members
- * injection.
- *
- * <p>For {@code @Provides} methods named "foo", the method name is "proxyFoo". For example:
- *
- * <pre><code>
- * abstract class FooModule {
- * {@literal @Provides} static Foo provideFoo(Bar bar, Baz baz) { … }
- * }
- *
- * public static proxyProvideFoo(Bar bar, Baz baz) { … }
- * </code></pre>
- *
- * <p>For {@code @Inject}ed constructors, the method name is "newFoo". For example:
- *
- * <pre><code>
- * class Foo {
- * {@literal @Inject} Foo(Bar bar) {}
- * }
- *
- * public static Foo newFoo(Bar bar) { … }
- * </code></pre>
- */
- static final class ProvisionMethod {
- // These names are already defined in factories and shouldn't be used for the proxy method name.
- private static final ImmutableSet<String> BANNED_PROXY_NAMES = ImmutableSet.of("get", "create");
-
- /**
- * Returns a method that invokes the binding's {@linkplain ProvisionBinding#bindingElement()
- * constructor} and injects the instance's members.
- */
- static MethodSpec create(
- ProvisionBinding binding,
- CompilerOptions compilerOptions,
- KotlinMetadataUtil metadataUtil) {
- ExecutableElement element = asExecutable(binding.bindingElement().get());
- switch (element.getKind()) {
- case CONSTRUCTOR:
- return constructorProxy(element);
- case METHOD:
- return methodProxy(
- element,
- methodName(element),
- InstanceCastPolicy.IGNORE,
- CheckNotNullPolicy.get(binding, compilerOptions),
- metadataUtil);
- default:
- throw new AssertionError(element);
- }
- }
-
- /**
- * Invokes the injection method for {@code binding}, with the dependencies transformed with the
- * {@code dependencyUsage} function.
- */
- static CodeBlock invoke(
- ProvisionBinding binding,
- Function<DependencyRequest, CodeBlock> dependencyUsage,
- ClassName requestingClass,
- Optional<CodeBlock> moduleReference,
- CompilerOptions compilerOptions,
- KotlinMetadataUtil metadataUtil) {
- ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
- moduleReference.ifPresent(arguments::add);
- invokeArguments(binding, dependencyUsage, requestingClass).forEach(arguments::add);
-
- ClassName enclosingClass = generatedClassNameForBinding(binding);
- MethodSpec methodSpec = create(binding, compilerOptions, metadataUtil);
- return invokeMethod(methodSpec, arguments.build(), enclosingClass, requestingClass);
- }
-
- static ImmutableList<CodeBlock> invokeArguments(
- ProvisionBinding binding,
- Function<DependencyRequest, CodeBlock> dependencyUsage,
- ClassName requestingClass) {
- ImmutableMap<VariableElement, DependencyRequest> dependencyRequestMap =
- binding.provisionDependencies().stream()
- .collect(
- toImmutableMap(
- request -> MoreElements.asVariable(request.requestElement().get()),
- request -> request));
-
- ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
- for (VariableElement parameter :
- asExecutable(binding.bindingElement().get()).getParameters()) {
- if (AssistedInjectionAnnotations.isAssistedParameter(parameter)) {
- arguments.add(CodeBlock.of("$L", parameter.getSimpleName()));
- } else if (dependencyRequestMap.containsKey(parameter)) {
- DependencyRequest request = dependencyRequestMap.get(parameter);
- arguments.add(
- injectionMethodArgument(request, dependencyUsage.apply(request), requestingClass));
- } else {
- throw new AssertionError("Unexpected parameter: " + parameter);
- }
- }
-
- return arguments.build();
- }
-
- private static MethodSpec constructorProxy(ExecutableElement constructor) {
- TypeElement enclosingType = MoreElements.asType(constructor.getEnclosingElement());
- MethodSpec.Builder builder =
- methodBuilder(methodName(constructor))
- .addModifiers(PUBLIC, STATIC)
- .varargs(constructor.isVarArgs())
- .returns(TypeName.get(enclosingType.asType()));
-
- copyTypeParameters(builder, enclosingType);
- copyThrows(builder, constructor);
-
- CodeBlock arguments =
- copyParameters(builder, new UniqueNameSet(), constructor.getParameters());
- return builder.addStatement("return new $T($L)", enclosingType, arguments).build();
- }
-
- /**
- * Returns {@code true} if injecting an instance of {@code binding} from {@code callingPackage}
- * requires the use of an injection method.
- */
- static boolean requiresInjectionMethod(
- ProvisionBinding binding, CompilerOptions compilerOptions, ClassName requestingClass) {
- ExecutableElement method = MoreElements.asExecutable(binding.bindingElement().get());
- return !binding.injectionSites().isEmpty()
- || binding.shouldCheckForNull(compilerOptions)
- || !isElementAccessibleFrom(method, requestingClass.packageName())
- // This check should be removable once we drop support for -source 7
- || method.getParameters().stream()
- .map(VariableElement::asType)
- .anyMatch(type -> !isRawTypeAccessible(type, requestingClass.packageName()));
- }
-
- /**
- * Returns the name of the {@code static} method that wraps {@code method}. For methods that are
- * associated with {@code @Inject} constructors, the method will also inject all {@link
- * InjectionSite}s.
- */
- private static String methodName(ExecutableElement method) {
- switch (method.getKind()) {
- case CONSTRUCTOR:
- return "newInstance";
- case METHOD:
- String methodName = method.getSimpleName().toString();
- return BANNED_PROXY_NAMES.contains(methodName)
- ? "proxy" + LOWER_CAMEL.to(UPPER_CAMEL, methodName)
- : methodName;
- default:
- throw new AssertionError(method);
- }
- }
- }
-
- /**
- * A static method that injects one member of an instance of a type. Its first parameter is an
- * instance of the type to be injected. The remaining parameters match the dependency requests for
- * the injection site.
- *
- * <p>Example:
- *
- * <pre><code>
- * class Foo {
- * {@literal @Inject} Bar bar;
- * {@literal @Inject} void setThings(Baz baz, Qux qux) {}
- * }
- *
- * public static injectBar(Foo instance, Bar bar) { … }
- * public static injectSetThings(Foo instance, Baz baz, Qux qux) { … }
- * </code></pre>
- */
- static final class InjectionSiteMethod {
- /**
- * When a type has an inaccessible member from a supertype (e.g. an @Inject field in a parent
- * that's in a different package), a method in the supertype's package must be generated to give
- * the subclass's members injector a way to inject it. Each potentially inaccessible member
- * receives its own method, as the subclass may need to inject them in a different order from
- * the parent class.
- */
- static MethodSpec create(InjectionSite injectionSite, KotlinMetadataUtil metadataUtil) {
- String methodName = methodName(injectionSite);
- switch (injectionSite.kind()) {
- case METHOD:
- return methodProxy(
- asExecutable(injectionSite.element()),
- methodName,
- InstanceCastPolicy.CAST_IF_NOT_PUBLIC,
- CheckNotNullPolicy.IGNORE,
- metadataUtil);
- case FIELD:
- Optional<AnnotationMirror> qualifier =
- injectionSite.dependencies().stream()
- // methods for fields have a single dependency request
- .collect(DaggerCollectors.onlyElement())
- .key()
- .qualifier();
- return fieldProxy(asVariable(injectionSite.element()), methodName, qualifier);
- }
- throw new AssertionError(injectionSite);
- }
-
- /**
- * Invokes each of the injection methods for {@code injectionSites}, with the dependencies
- * transformed using the {@code dependencyUsage} function.
- *
- * @param instanceType the type of the {@code instance} parameter
- */
- static CodeBlock invokeAll(
- ImmutableSet<InjectionSite> injectionSites,
- ClassName generatedTypeName,
- CodeBlock instanceCodeBlock,
- TypeMirror instanceType,
- Function<DependencyRequest, CodeBlock> dependencyUsage,
- DaggerTypes types,
- KotlinMetadataUtil metadataUtil) {
- return injectionSites.stream()
- .map(
- injectionSite -> {
- TypeMirror injectSiteType =
- types.erasure(injectionSite.element().getEnclosingElement().asType());
-
- // If instance has been declared as Object because it is not accessible from the
- // component, but the injectionSite is in a supertype of instanceType that is
- // publicly accessible, the InjectionSiteMethod will request the actual type and not
- // Object as the first parameter. If so, cast to the supertype which is accessible
- // from within generatedTypeName
- CodeBlock maybeCastedInstance =
- !types.isSubtype(instanceType, injectSiteType)
- && isTypeAccessibleFrom(injectSiteType, generatedTypeName.packageName())
- ? CodeBlock.of("($T) $L", injectSiteType, instanceCodeBlock)
- : instanceCodeBlock;
- return CodeBlock.of(
- "$L;",
- invoke(
- injectionSite,
- generatedTypeName,
- maybeCastedInstance,
- dependencyUsage,
- metadataUtil));
- })
- .collect(toConcatenatedCodeBlock());
- }
-
- /**
- * Invokes the injection method for {@code injectionSite}, with the dependencies transformed
- * using the {@code dependencyUsage} function.
- */
- private static CodeBlock invoke(
- InjectionSite injectionSite,
- ClassName generatedTypeName,
- CodeBlock instanceCodeBlock,
- Function<DependencyRequest, CodeBlock> dependencyUsage,
- KotlinMetadataUtil metadataUtil) {
- ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
- arguments.add(instanceCodeBlock);
- if (!injectionSite.dependencies().isEmpty()) {
- arguments.addAll(
- injectionSite.dependencies().stream().map(dependencyUsage).collect(toList()));
- }
-
- ClassName enclosingClass =
- membersInjectorNameForType(asType(injectionSite.element().getEnclosingElement()));
- MethodSpec methodSpec = create(injectionSite, metadataUtil);
- return invokeMethod(methodSpec, arguments.build(), enclosingClass, generatedTypeName);
- }
-
- /*
- * TODO(ronshapiro): this isn't perfect, as collisions could still exist. Some examples:
- *
- * - @Inject void members() {} will generate a method that conflicts with the instance
- * method `injectMembers(T)`
- * - Adding the index could conflict with another member:
- * @Inject void a(Object o) {}
- * @Inject void a(String s) {}
- * @Inject void a1(String s) {}
- *
- * Here, Method a(String) will add the suffix "1", which will conflict with the method
- * generated for a1(String)
- * - Members named "members" or "methods" could also conflict with the {@code static} injection
- * method.
- */
- private static String methodName(InjectionSite injectionSite) {
- int index = injectionSite.indexAmongAtInjectMembersWithSameSimpleName();
- String indexString = index == 0 ? "" : String.valueOf(index + 1);
- return "inject"
- + LOWER_CAMEL.to(UPPER_CAMEL, injectionSite.element().getSimpleName().toString())
- + indexString;
- }
- }
-
- private static CodeBlock injectionMethodArgument(
- DependencyRequest dependency, CodeBlock argument, ClassName generatedTypeName) {
- TypeMirror keyType = dependency.key().type();
- CodeBlock.Builder codeBlock = CodeBlock.builder();
- if (!isRawTypeAccessible(keyType, generatedTypeName.packageName())
- && isTypeAccessibleFrom(keyType, generatedTypeName.packageName())) {
- if (!dependency.kind().equals(RequestKind.INSTANCE)) {
- TypeName usageTypeName = accessibleType(dependency);
- codeBlock.add("($T) ($T)", usageTypeName, rawTypeName(usageTypeName));
- } else if (dependency.requestElement().get().asType().getKind().equals(TypeKind.TYPEVAR)) {
- codeBlock.add("($T)", keyType);
- }
- }
- return codeBlock.add(argument).build();
- }
-
- /**
- * Returns the parameter type for {@code dependency}. If the raw type is not accessible, returns
- * {@link Object}.
- */
- private static TypeName accessibleType(DependencyRequest dependency) {
- TypeName typeName = requestTypeName(dependency.kind(), accessibleType(dependency.key().type()));
- return dependency
- .requestElement()
- .map(element -> element.asType().getKind().isPrimitive())
- .orElse(false)
- ? typeName.unbox()
- : typeName;
- }
-
- /**
- * Returns the accessible type for {@code type}. If the raw type is not accessible, returns {@link
- * Object}.
- */
- private static TypeName accessibleType(TypeMirror type) {
- return isRawTypePubliclyAccessible(type) ? TypeName.get(type) : TypeName.OBJECT;
- }
-
- private enum InstanceCastPolicy {
- CAST_IF_NOT_PUBLIC, IGNORE;
-
- boolean useObjectType(TypeMirror instanceType) {
- return this == CAST_IF_NOT_PUBLIC && !isRawTypePubliclyAccessible(instanceType);
- }
- }
-
- private enum CheckNotNullPolicy {
- IGNORE, CHECK_FOR_NULL;
-
- CodeBlock checkForNull(CodeBlock maybeNull) {
- return this.equals(IGNORE)
- ? maybeNull
- : CodeBlock.of("$T.checkNotNullFromProvides($L)", Preconditions.class, maybeNull);
- }
-
- static CheckNotNullPolicy get(ProvisionBinding binding, CompilerOptions compilerOptions) {
- return binding.shouldCheckForNull(compilerOptions) ? CHECK_FOR_NULL : IGNORE;
- }
- }
-
- private static MethodSpec methodProxy(
- ExecutableElement method,
- String methodName,
- InstanceCastPolicy instanceCastPolicy,
- CheckNotNullPolicy checkNotNullPolicy,
- KotlinMetadataUtil metadataUtil) {
- MethodSpec.Builder builder =
- methodBuilder(methodName).addModifiers(PUBLIC, STATIC).varargs(method.isVarArgs());
-
- TypeElement enclosingType = asType(method.getEnclosingElement());
- boolean isMethodInKotlinObject = metadataUtil.isObjectClass(enclosingType);
- boolean isMethodInKotlinCompanionObject = metadataUtil.isCompanionObjectClass(enclosingType);
- UniqueNameSet parameterNameSet = new UniqueNameSet();
- CodeBlock instance;
- if (isMethodInKotlinCompanionObject || method.getModifiers().contains(STATIC)) {
- instance = CodeBlock.of("$T", rawTypeName(TypeName.get(enclosingType.asType())));
- } else if (isMethodInKotlinObject) {
- // Call through the singleton instance.
- // See: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods
- instance = CodeBlock.of("$T.INSTANCE", rawTypeName(TypeName.get(enclosingType.asType())));
- } else {
- copyTypeParameters(builder, enclosingType);
- boolean useObject = instanceCastPolicy.useObjectType(enclosingType.asType());
- instance = copyInstance(builder, parameterNameSet, enclosingType.asType(), useObject);
- }
- CodeBlock arguments = copyParameters(builder, parameterNameSet, method.getParameters());
- CodeBlock invocation =
- checkNotNullPolicy.checkForNull(
- CodeBlock.of("$L.$L($L)", instance, method.getSimpleName(), arguments));
-
- copyTypeParameters(builder, method);
- copyThrows(builder, method);
-
- if (method.getReturnType().getKind().equals(VOID)) {
- return builder.addStatement("$L", invocation).build();
- } else {
- getNullableType(method)
- .ifPresent(annotation -> CodeBlocks.addAnnotation(builder, annotation));
- return builder
- .returns(TypeName.get(method.getReturnType()))
- .addStatement("return $L", invocation).build();
- }
- }
-
- private static MethodSpec fieldProxy(
- VariableElement field, String methodName, Optional<AnnotationMirror> qualifierAnnotation) {
- MethodSpec.Builder builder =
- methodBuilder(methodName)
- .addModifiers(PUBLIC, STATIC)
- .addAnnotation(
- AnnotationSpec.builder(TypeNames.INJECTED_FIELD_SIGNATURE)
- .addMember("value", "$S", memberInjectedFieldSignatureForVariable(field))
- .build());
-
- qualifierAnnotation.map(AnnotationSpec::get).ifPresent(builder::addAnnotation);
-
- TypeElement enclosingType = asType(field.getEnclosingElement());
- copyTypeParameters(builder, enclosingType);
-
- boolean useObject = !isRawTypePubliclyAccessible(enclosingType.asType());
- UniqueNameSet parameterNameSet = new UniqueNameSet();
- CodeBlock instance = copyInstance(builder, parameterNameSet, enclosingType.asType(), useObject);
- CodeBlock argument = copyParameters(builder, parameterNameSet, ImmutableList.of(field));
- return builder.addStatement("$L.$L = $L", instance, field.getSimpleName(), argument).build();
- }
-
- private static CodeBlock invokeMethod(
- MethodSpec methodSpec,
- ImmutableList<CodeBlock> parameters,
- ClassName enclosingClass,
- ClassName requestingClass) {
- checkArgument(methodSpec.parameters.size() == parameters.size());
- CodeBlock parameterBlock = makeParametersCodeBlock(parameters);
- return enclosingClass.equals(requestingClass)
- ? CodeBlock.of("$L($L)", methodSpec.name, parameterBlock)
- : CodeBlock.of("$T.$L($L)", enclosingClass, methodSpec.name, parameterBlock);
- }
-
- private static void copyTypeParameters(
- MethodSpec.Builder methodBuilder, Parameterizable element) {
- element.getTypeParameters().stream()
- .map(TypeVariableName::get)
- .forEach(methodBuilder::addTypeVariable);
- }
-
- private static void copyThrows(MethodSpec.Builder methodBuilder, ExecutableElement method) {
- method.getThrownTypes().stream().map(TypeName::get).forEach(methodBuilder::addException);
- }
-
- private static CodeBlock copyParameters(
- MethodSpec.Builder methodBuilder,
- UniqueNameSet parameterNameSet,
- List<? extends VariableElement> parameters) {
- return parameters.stream()
- .map(
- parameter -> {
- String name =
- parameterNameSet.getUniqueName(validJavaName(parameter.getSimpleName()));
- TypeMirror type = parameter.asType();
- boolean useObject = !isRawTypePubliclyAccessible(type);
- return copyParameter(methodBuilder, type, name, useObject);
- })
- .collect(toParametersCodeBlock());
- }
-
- private static CodeBlock copyParameter(
- MethodSpec.Builder methodBuilder, TypeMirror type, String name, boolean useObject) {
- TypeName typeName = useObject ? TypeName.OBJECT : TypeName.get(type);
- methodBuilder.addParameter(ParameterSpec.builder(typeName, name).build());
- return useObject ? CodeBlock.of("($T) $L", type, name) : CodeBlock.of("$L", name);
- }
-
- private static CodeBlock copyInstance(
- MethodSpec.Builder methodBuilder,
- UniqueNameSet parameterNameSet,
- TypeMirror type,
- boolean useObject) {
- CodeBlock instance =
- copyParameter(methodBuilder, type, parameterNameSet.getUniqueName("instance"), useObject);
- // If we had to cast the instance add an extra parenthesis incase we're calling a method on it.
- return useObject ? CodeBlock.of("($L)", instance) : instance;
- }
-
- private static String validJavaName(CharSequence name) {
- if (SourceVersion.isIdentifier(name)) {
- return protectAgainstKeywords(name.toString());
- }
-
- StringBuilder newName = new StringBuilder(name.length());
- char firstChar = name.charAt(0);
- if (!Character.isJavaIdentifierStart(firstChar)) {
- newName.append('_');
- }
-
- name.chars().forEach(c -> newName.append(Character.isJavaIdentifierPart(c) ? c : '_'));
- return newName.toString();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java b/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
deleted file mode 100644
index b5135b0..0000000
--- a/java/dagger/internal/codegen/writing/InjectionOrProvisionProviderCreationExpression.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.model.BindingKind.INJECTION;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import javax.inject.Provider;
-
-/**
- * A {@link Provider} creation expression for an {@link javax.inject.Inject @Inject}-constructed
- * class or a {@link dagger.Provides @Provides}-annotated module method.
- */
-// TODO(dpb): Resolve with ProducerCreationExpression.
-final class InjectionOrProvisionProviderCreationExpression
- implements FrameworkInstanceCreationExpression {
-
- private final ContributionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
-
- InjectionOrProvisionProviderCreationExpression(
- ContributionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- }
-
- @Override
- public CodeBlock creationExpression() {
- CodeBlock createFactory =
- CodeBlock.of(
- "$T.create($L)",
- generatedClassNameForBinding(binding),
- componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
-
- // When scoping a parameterized factory for an @Inject class, Java 7 cannot always infer the
- // type properly, so cast to a raw framework type before scoping.
- if (binding.kind().equals(INJECTION)
- && binding.unresolved().isPresent()
- && binding.scope().isPresent()) {
- return CodeBlocks.cast(createFactory, Provider.class);
- } else {
- return createFactory;
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/InnerSwitchingProviders.java b/java/dagger/internal/codegen/writing/InnerSwitchingProviders.java
deleted file mode 100644
index c2f9893..0000000
--- a/java/dagger/internal/codegen/writing/InnerSwitchingProviders.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.model.RequestKind.INSTANCE;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Generates {@linkplain BindingExpression binding expressions} for a binding that is represented by
- * an inner {@code SwitchingProvider} class.
- */
-final class InnerSwitchingProviders extends SwitchingProviders {
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
-
- InnerSwitchingProviders(
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types) {
- super(componentImplementation, types);
- this.componentBindingExpressions = componentBindingExpressions;
- this.types = types;
- }
-
- /**
- * Returns the binding expression for a binding that satisfies a {@link Provider} requests with a
- * inner {@code SwitchingProvider} class.
- */
- BindingExpression newBindingExpression(ContributionBinding binding) {
- return new BindingExpression() {
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return getProviderExpression(new SwitchCase(binding, requestingClass));
- }
- };
- }
-
- @Override
- protected TypeSpec createSwitchingProviderType(TypeSpec.Builder builder) {
- return builder
- .addModifiers(PRIVATE, FINAL)
- .addField(TypeName.INT, "id", PRIVATE, FINAL)
- .addMethod(
- constructorBuilder()
- .addParameter(TypeName.INT, "id")
- .addStatement("this.id = id")
- .build())
- .build();
- }
-
- private final class SwitchCase implements SwitchingProviders.SwitchCase {
- private final ContributionBinding binding;
- private final ClassName requestingClass;
-
- SwitchCase(ContributionBinding binding, ClassName requestingClass) {
- this.binding = binding;
- this.requestingClass = requestingClass;
- }
-
- @Override
- public Key key() {
- return binding.key();
- }
-
- @Override
- public Expression getProviderExpression(ClassName switchingProviderClass, int switchId) {
- TypeMirror instanceType = types.accessibleType(binding.contributedType(), requestingClass);
- return Expression.create(
- types.wrapType(instanceType, Provider.class),
- CodeBlock.of("new $T<>($L)", switchingProviderClass, switchId));
- }
-
- @Override
- public Expression getReturnExpression(ClassName switchingProviderClass) {
- return componentBindingExpressions.getDependencyExpression(
- bindingRequest(binding.key(), INSTANCE), switchingProviderClass);
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java
deleted file mode 100644
index a7d6685..0000000
--- a/java/dagger/internal/codegen/writing/InstanceFactoryCreationExpression.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.InstanceFactory;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import java.util.function.Supplier;
-
-/**
- * A {@link FrameworkInstanceCreationExpression} that creates an {@link InstanceFactory} for an
- * instance.
- */
-final class InstanceFactoryCreationExpression implements FrameworkInstanceCreationExpression {
-
- private final boolean nullable;
- private final Supplier<CodeBlock> instanceExpression;
-
- InstanceFactoryCreationExpression(Supplier<CodeBlock> instanceExpression) {
- this(false, instanceExpression);
- }
-
- InstanceFactoryCreationExpression(boolean nullable, Supplier<CodeBlock> instanceExpression) {
- this.nullable = nullable;
- this.instanceExpression = checkNotNull(instanceExpression);
- }
-
- @Override
- public CodeBlock creationExpression() {
- return CodeBlock.of(
- "$T.$L($L)",
- InstanceFactory.class,
- nullable ? "createNullable" : "create",
- instanceExpression.get());
- }
-
- @Override
- public boolean useInnerSwitchingProvider() {
- return false;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MapBindingExpression.java b/java/dagger/internal/codegen/writing/MapBindingExpression.java
deleted file mode 100644
index 255e85d..0000000
--- a/java/dagger/internal/codegen/writing/MapBindingExpression.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-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.model.BindingKind.MULTIBOUND_MAP;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.MapBuilder;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.DependencyRequest;
-import java.util.Collections;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/** A {@link BindingExpression} for multibound maps. */
-final class MapBindingExpression extends SimpleInvocationBindingExpression {
- /** Maximum number of key-value pairs that can be passed to ImmutableMap.of(K, V, K, V, ...). */
- private static final int MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS = 5;
-
- private final ProvisionBinding binding;
- private final ImmutableMap<DependencyRequest, ContributionBinding> dependencies;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
- private final DaggerElements elements;
-
- MapBindingExpression(
- ProvisionBinding binding,
- BindingGraph graph,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- DaggerElements elements) {
- super(binding);
- this.binding = binding;
- BindingKind bindingKind = this.binding.kind();
- checkArgument(bindingKind.equals(MULTIBOUND_MAP), bindingKind);
- this.componentBindingExpressions = componentBindingExpressions;
- this.types = types;
- this.elements = elements;
- this.dependencies =
- Maps.toMap(binding.dependencies(), dep -> graph.contributionBinding(dep.key()));
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- // TODO(ronshapiro): We should also make an ImmutableMap version of MapFactory
- boolean isImmutableMapAvailable = isImmutableMapAvailable();
- // TODO(ronshapiro, gak): Use Maps.immutableEnumMap() if it's available?
- if (isImmutableMapAvailable && dependencies.size() <= MAX_IMMUTABLE_MAP_OF_KEY_VALUE_PAIRS) {
- return Expression.create(
- immutableMapType(),
- CodeBlock.builder()
- .add("$T.", ImmutableMap.class)
- .add(maybeTypeParameters(requestingClass))
- .add(
- "of($L)",
- dependencies
- .keySet()
- .stream()
- .map(dependency -> keyAndValueExpression(dependency, requestingClass))
- .collect(toParametersCodeBlock()))
- .build());
- }
- switch (dependencies.size()) {
- case 0:
- return collectionsStaticFactoryInvocation(requestingClass, CodeBlock.of("emptyMap()"));
- case 1:
- return collectionsStaticFactoryInvocation(
- requestingClass,
- CodeBlock.of(
- "singletonMap($L)",
- keyAndValueExpression(getOnlyElement(dependencies.keySet()), requestingClass)));
- default:
- CodeBlock.Builder instantiation = CodeBlock.builder();
- instantiation
- .add("$T.", isImmutableMapAvailable ? ImmutableMap.class : MapBuilder.class)
- .add(maybeTypeParameters(requestingClass));
- if (isImmutableMapBuilderWithExpectedSizeAvailable()) {
- instantiation.add("builderWithExpectedSize($L)", dependencies.size());
- } else if (isImmutableMapAvailable) {
- instantiation.add("builder()");
- } else {
- instantiation.add("newMapBuilder($L)", dependencies.size());
- }
- for (DependencyRequest dependency : dependencies.keySet()) {
- instantiation.add(".put($L)", keyAndValueExpression(dependency, requestingClass));
- }
- return Expression.create(
- isImmutableMapAvailable ? immutableMapType() : binding.key().type(),
- instantiation.add(".build()").build());
- }
- }
-
- private DeclaredType immutableMapType() {
- MapType mapType = MapType.from(binding.key());
- return types.getDeclaredType(
- elements.getTypeElement(ImmutableMap.class), mapType.keyType(), mapType.valueType());
- }
-
- private CodeBlock keyAndValueExpression(DependencyRequest dependency, ClassName requestingClass) {
- return CodeBlock.of(
- "$L, $L",
- getMapKeyExpression(dependencies.get(dependency), requestingClass, elements),
- componentBindingExpressions
- .getDependencyExpression(bindingRequest(dependency), requestingClass)
- .codeBlock());
- }
-
- private Expression collectionsStaticFactoryInvocation(
- ClassName requestingClass, CodeBlock methodInvocation) {
- return Expression.create(
- binding.key().type(),
- CodeBlock.builder()
- .add("$T.", Collections.class)
- .add(maybeTypeParameters(requestingClass))
- .add(methodInvocation)
- .build());
- }
-
- private CodeBlock maybeTypeParameters(ClassName requestingClass) {
- TypeMirror bindingKeyType = binding.key().type();
- MapType mapType = MapType.from(binding.key());
- return isTypeAccessibleFrom(bindingKeyType, requestingClass.packageName())
- ? CodeBlock.of("<$T, $T>", mapType.keyType(), mapType.valueType())
- : CodeBlock.of("");
- }
-
- private boolean isImmutableMapBuilderWithExpectedSizeAvailable() {
- if (isImmutableMapAvailable()) {
- return methodsIn(elements.getTypeElement(ImmutableMap.class).getEnclosedElements())
- .stream()
- .anyMatch(method -> method.getSimpleName().contentEquals("builderWithExpectedSize"));
- }
- return false;
- }
-
- private boolean isImmutableMapAvailable() {
- return elements.getTypeElement(ImmutableMap.class) != null;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
deleted file mode 100644
index 104d48a..0000000
--- a/java/dagger/internal/codegen/writing/MapFactoryCreationExpression.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.MapKeys.getMapKeyExpression;
-import static dagger.internal.codegen.binding.SourceFiles.mapFactoryClassName;
-
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.base.MapType;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.DependencyRequest;
-import dagger.producers.Produced;
-import dagger.producers.Producer;
-import javax.inject.Provider;
-import javax.lang.model.type.TypeMirror;
-
-/** A factory creation expression for a multibound map. */
-final class MapFactoryCreationExpression extends MultibindingFactoryCreationExpression {
-
- private final ComponentImplementation componentImplementation;
- private final BindingGraph graph;
- private final ContributionBinding binding;
- private final DaggerElements elements;
-
- MapFactoryCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions,
- BindingGraph graph,
- DaggerElements elements) {
- super(binding, componentImplementation, componentBindingExpressions);
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.graph = checkNotNull(graph);
- this.elements = checkNotNull(elements);
- }
-
- @Override
- public CodeBlock creationExpression() {
- CodeBlock.Builder builder = CodeBlock.builder().add("$T.", mapFactoryClassName(binding));
- if (!useRawType()) {
- MapType mapType = MapType.from(binding.key().type());
- // TODO(ronshapiro): either inline this into mapFactoryClassName, or add a
- // mapType.unwrappedValueType() method that doesn't require a framework type
- TypeMirror valueType = mapType.valueType();
- for (Class<?> frameworkClass :
- ImmutableSet.of(Provider.class, Producer.class, Produced.class)) {
- if (mapType.valuesAreTypeOf(frameworkClass)) {
- valueType = mapType.unwrappedValueType(frameworkClass);
- break;
- }
- }
- builder.add("<$T, $T>", mapType.keyType(), valueType);
- }
-
- builder.add("builder($L)", binding.dependencies().size());
-
- for (DependencyRequest dependency : binding.dependencies()) {
- ContributionBinding contributionBinding = graph.contributionBinding(dependency.key());
- builder.add(
- ".put($L, $L)",
- getMapKeyExpression(contributionBinding, componentImplementation.name(), elements),
- multibindingDependencyExpression(dependency));
- }
- builder.add(".build()");
-
- return builder.build();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MemberSelect.java b/java/dagger/internal/codegen/writing/MemberSelect.java
deleted file mode 100644
index b04e21b..0000000
--- a/java/dagger/internal/codegen/writing/MemberSelect.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.ContributionBinding.FactoryCreationStrategy.SINGLETON_INSTANCE;
-import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.MAP_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static javax.lang.model.type.TypeKind.DECLARED;
-
-import com.google.auto.common.MoreTypes;
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeVariableName;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import java.util.List;
-import java.util.Optional;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * Represents a {@link com.sun.source.tree.MemberSelectTree} as a {@link CodeBlock}.
- */
-abstract class MemberSelect {
-
- /**
- * Returns a {@link MemberSelect} that accesses the field given by {@code fieldName} owned by
- * {@code owningClass}. In this context "local" refers to the fact that the field is owned by the
- * type (or an enclosing type) from which the code block will be used. The returned
- * {@link MemberSelect} will not be valid for accessing the field from a different class
- * (regardless of accessibility).
- */
- static MemberSelect localField(ClassName owningClass, String fieldName) {
- return new LocalField(owningClass, fieldName);
- }
-
- private static final class LocalField extends MemberSelect {
- final String fieldName;
-
- LocalField(ClassName owningClass, String fieldName) {
- super(owningClass, false);
- this.fieldName = checkNotNull(fieldName);
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- return owningClass().equals(usingClass)
- ? CodeBlock.of("$N", fieldName)
- : CodeBlock.of("$T.this.$N", owningClass(), fieldName);
- }
- }
-
- /**
- * Returns a {@link MemberSelect} that accesses the method given by {@code methodName} owned by
- * {@code owningClass}. In this context "local" refers to the fact that the method is owned by the
- * type (or an enclosing type) from which the code block will be used. The returned {@link
- * MemberSelect} will not be valid for accessing the method from a different class (regardless of
- * accessibility).
- */
- static MemberSelect localMethod(ClassName owningClass, String methodName) {
- return new LocalMethod(owningClass, methodName);
- }
-
- private static final class LocalMethod extends MemberSelect {
- final String methodName;
-
- LocalMethod(ClassName owningClass, String methodName) {
- super(owningClass, false);
- this.methodName = checkNotNull(methodName);
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- return owningClass().equals(usingClass)
- ? CodeBlock.of("$N()", methodName)
- : CodeBlock.of("$T.this.$N()", owningClass(), methodName);
- }
- }
-
- /**
- * If {@code resolvedBindings} is an unscoped provision binding with no factory arguments or a
- * no-op members injection binding, then we don't need a field to hold its factory. In that case,
- * this method returns the static member select that returns the factory or no-op members
- * injector.
- */
- static Optional<MemberSelect> staticFactoryCreation(ContributionBinding contributionBinding) {
- if (contributionBinding.factoryCreationStrategy().equals(SINGLETON_INSTANCE)
- && !contributionBinding.scope().isPresent()) {
- switch (contributionBinding.kind()) {
- case MULTIBOUND_MAP:
- return Optional.of(emptyMapFactory(contributionBinding));
-
- case MULTIBOUND_SET:
- return Optional.of(emptySetFactory(contributionBinding));
-
- case INJECTION:
- case PROVISION:
- TypeMirror keyType = contributionBinding.key().type();
- if (keyType.getKind().equals(DECLARED)) {
- ImmutableList<TypeVariableName> typeVariables =
- bindingTypeElementTypeVariableNames(contributionBinding);
- if (!typeVariables.isEmpty()) {
- List<? extends TypeMirror> typeArguments =
- ((DeclaredType) keyType).getTypeArguments();
- return Optional.of(
- MemberSelect.parameterizedFactoryCreateMethod(
- generatedClassNameForBinding(contributionBinding), typeArguments));
- }
- }
- // fall through
-
- default:
- return Optional.of(
- new StaticMethod(
- generatedClassNameForBinding(contributionBinding), CodeBlock.of("create()")));
- }
- }
-
- return Optional.empty();
- }
-
- /**
- * Returns a {@link MemberSelect} for the instance of a {@code create()} method on a factory. This
- * only applies for factories that do not have any dependencies.
- */
- private static MemberSelect parameterizedFactoryCreateMethod(
- ClassName owningClass, List<? extends TypeMirror> parameters) {
- return new ParameterizedStaticMethod(
- owningClass, ImmutableList.copyOf(parameters), CodeBlock.of("create()"), FACTORY);
- }
-
- private static final class StaticMethod extends MemberSelect {
- final CodeBlock methodCodeBlock;
-
- StaticMethod(ClassName owningClass, CodeBlock methodCodeBlock) {
- super(owningClass, true);
- this.methodCodeBlock = checkNotNull(methodCodeBlock);
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- return owningClass().equals(usingClass)
- ? methodCodeBlock
- : CodeBlock.of("$T.$L", owningClass(), methodCodeBlock);
- }
- }
-
- /** A {@link MemberSelect} for a factory of an empty map. */
- private static MemberSelect emptyMapFactory(ContributionBinding contributionBinding) {
- BindingType bindingType = contributionBinding.bindingType();
- ImmutableList<TypeMirror> typeParameters =
- ImmutableList.copyOf(
- MoreTypes.asDeclared(contributionBinding.key().type()).getTypeArguments());
- if (bindingType.equals(BindingType.PRODUCTION)) {
- return new ParameterizedStaticMethod(
- PRODUCERS, typeParameters, CodeBlock.of("emptyMapProducer()"), PRODUCER);
- } else {
- return new ParameterizedStaticMethod(
- MAP_FACTORY, typeParameters, CodeBlock.of("emptyMapProvider()"), PROVIDER);
- }
- }
-
- /**
- * A static member select for an empty set factory. Calls {@link
- * dagger.internal.SetFactory#empty()}, {@link dagger.producers.internal.SetProducer#empty()}, or
- * {@link dagger.producers.internal.SetOfProducedProducer#empty()}, depending on the set bindings.
- */
- private static MemberSelect emptySetFactory(ContributionBinding binding) {
- return new ParameterizedStaticMethod(
- setFactoryClassName(binding),
- ImmutableList.of(SetType.from(binding.key()).elementType()),
- CodeBlock.of("empty()"),
- FACTORY);
- }
-
- private static final class ParameterizedStaticMethod extends MemberSelect {
- final ImmutableList<TypeMirror> typeParameters;
- final CodeBlock methodCodeBlock;
- final ClassName rawReturnType;
-
- ParameterizedStaticMethod(
- ClassName owningClass,
- ImmutableList<TypeMirror> typeParameters,
- CodeBlock methodCodeBlock,
- ClassName rawReturnType) {
- super(owningClass, true);
- this.typeParameters = typeParameters;
- this.methodCodeBlock = methodCodeBlock;
- this.rawReturnType = rawReturnType;
- }
-
- @Override
- CodeBlock getExpressionFor(ClassName usingClass) {
- boolean accessible = true;
- for (TypeMirror typeParameter : typeParameters) {
- accessible &= isTypeAccessibleFrom(typeParameter, usingClass.packageName());
- }
-
- if (accessible) {
- return CodeBlock.of(
- "$T.<$L>$L",
- owningClass(),
- typeParameters.stream().map(CodeBlocks::type).collect(toParametersCodeBlock()),
- methodCodeBlock);
- } else {
- return CodeBlock.of("(($T) $T.$L)", rawReturnType, owningClass(), methodCodeBlock);
- }
- }
- }
-
- private final ClassName owningClass;
- private final boolean staticMember;
-
- MemberSelect(ClassName owningClass, boolean staticMemeber) {
- this.owningClass = owningClass;
- this.staticMember = staticMemeber;
- }
-
- /** Returns the class that owns the member being selected. */
- ClassName owningClass() {
- return owningClass;
- }
-
- /**
- * Returns true if the member being selected is static and does not require an instance of
- * {@link #owningClass()}.
- */
- boolean staticMember() {
- return staticMember;
- }
-
- /**
- * Returns a {@link CodeBlock} suitable for accessing the member from the given {@code
- * usingClass}.
- */
- abstract CodeBlock getExpressionFor(ClassName usingClass);
-}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionBindingExpression.java b/java/dagger/internal/codegen/writing/MembersInjectionBindingExpression.java
deleted file mode 100644
index abf9d03..0000000
--- a/java/dagger/internal/codegen/writing/MembersInjectionBindingExpression.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static javax.lang.model.type.TypeKind.VOID;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.ParameterSpec;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import javax.lang.model.element.ExecutableElement;
-
-/**
- * A binding expression for members injection component methods. See {@link
- * MembersInjectionMethods}.
- */
-final class MembersInjectionBindingExpression extends BindingExpression {
- private final MembersInjectionBinding binding;
- private final MembersInjectionMethods membersInjectionMethods;
-
- MembersInjectionBindingExpression(
- MembersInjectionBinding binding, MembersInjectionMethods membersInjectionMethods) {
- this.binding = binding;
- this.membersInjectionMethods = membersInjectionMethods;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- throw new UnsupportedOperationException(binding.toString());
- }
-
- // TODO(ronshapiro): This class doesn't need to be a BindingExpression, as
- // getDependencyExpression() should never be called for members injection methods. It's probably
- // better suited as a method on MembersInjectionMethods
- @Override
- protected CodeBlock getComponentMethodImplementation(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- ExecutableElement methodElement = componentMethod.methodElement();
- ParameterSpec parameter = ParameterSpec.get(getOnlyElement(methodElement.getParameters()));
-
- if (binding.injectionSites().isEmpty()) {
- return methodElement.getReturnType().getKind().equals(VOID)
- ? CodeBlock.of("")
- : CodeBlock.of("return $N;", parameter);
- } else {
- return methodElement.getReturnType().getKind().equals(VOID)
- ? CodeBlock.of("$L;", membersInjectionInvocation(parameter))
- : CodeBlock.of("return $L;", membersInjectionInvocation(parameter));
- }
- }
-
- CodeBlock membersInjectionInvocation(ParameterSpec target) {
- return CodeBlock.of("$N($N)", membersInjectionMethods.getOrCreate(binding.key()), target);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java b/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
deleted file mode 100644
index 3d602b3..0000000
--- a/java/dagger/internal/codegen/writing/MembersInjectionMethods.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.MEMBERS_INJECTION_METHOD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.model.Key;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** Manages the member injection methods for a component. */
-final class MembersInjectionMethods {
- private final Map<Key, MethodSpec> membersInjectionMethods = new LinkedHashMap<>();
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions bindingExpressions;
- private final BindingGraph graph;
- private final DaggerElements elements;
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
-
- MembersInjectionMethods(
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions bindingExpressions,
- BindingGraph graph,
- DaggerElements elements,
- DaggerTypes types,
- KotlinMetadataUtil metadataUtil) {
- this.componentImplementation = checkNotNull(componentImplementation);
- this.bindingExpressions = checkNotNull(bindingExpressions);
- this.graph = checkNotNull(graph);
- this.elements = checkNotNull(elements);
- this.types = checkNotNull(types);
- this.metadataUtil = metadataUtil;
- }
-
- /**
- * Returns the members injection {@link MethodSpec} for the given {@link Key}, creating it if
- * necessary.
- */
- MethodSpec getOrCreate(Key key) {
- return reentrantComputeIfAbsent(membersInjectionMethods, key, this::membersInjectionMethod);
- }
-
- private MethodSpec membersInjectionMethod(Key key) {
- Binding binding =
- graph.membersInjectionBinding(key).isPresent()
- ? graph.membersInjectionBinding(key).get()
- : graph.contributionBinding(key);
- TypeMirror keyType = binding.key().type();
- TypeMirror membersInjectedType =
- isTypeAccessibleFrom(keyType, componentImplementation.name().packageName())
- ? keyType
- : elements.getTypeElement(Object.class).asType();
- TypeName membersInjectedTypeName = TypeName.get(membersInjectedType);
- Name bindingTypeName = binding.bindingTypeElement().get().getSimpleName();
- // TODO(ronshapiro): include type parameters in this name e.g. injectFooOfT, and outer class
- // simple names Foo.Builder -> injectFooBuilder
- String methodName = componentImplementation.getUniqueMethodName("inject" + bindingTypeName);
- ParameterSpec parameter = ParameterSpec.builder(membersInjectedTypeName, "instance").build();
- MethodSpec.Builder methodBuilder =
- methodBuilder(methodName)
- .addModifiers(PRIVATE)
- .returns(membersInjectedTypeName)
- .addParameter(parameter);
- TypeElement canIgnoreReturnValue =
- elements.getTypeElement("com.google.errorprone.annotations.CanIgnoreReturnValue");
- if (canIgnoreReturnValue != null) {
- methodBuilder.addAnnotation(ClassName.get(canIgnoreReturnValue));
- }
- CodeBlock instance = CodeBlock.of("$N", parameter);
- methodBuilder.addCode(
- InjectionSiteMethod.invokeAll(
- injectionSites(binding),
- componentImplementation.name(),
- instance,
- membersInjectedType,
- request ->
- bindingExpressions
- .getDependencyArgumentExpression(request, componentImplementation.name())
- .codeBlock(),
- types,
- metadataUtil));
- methodBuilder.addStatement("return $L", instance);
-
- MethodSpec method = methodBuilder.build();
- componentImplementation.addMethod(MEMBERS_INJECTION_METHOD, method);
- return method;
- }
-
- private static ImmutableSet<InjectionSite> injectionSites(Binding binding) {
- if (binding instanceof ProvisionBinding) {
- return ((ProvisionBinding) binding).injectionSites();
- } else if (binding instanceof MembersInjectionBinding) {
- return ((MembersInjectionBinding) binding).injectionSites();
- }
- throw new IllegalArgumentException(binding.key().toString());
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java b/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
deleted file mode 100644
index df618b0..0000000
--- a/java/dagger/internal/codegen/writing/MembersInjectorGenerator.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2014 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.writing;
-
-import static com.google.common.base.Preconditions.checkState;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedInjectedConstructors;
-import static dagger.internal.codegen.binding.InjectionAnnotations.injectedConstructors;
-import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
-import static dagger.internal.codegen.binding.SourceFiles.frameworkFieldUsages;
-import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
-import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
-import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.membersInjectorOf;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-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.MembersInjector;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.FrameworkField;
-import dagger.internal.codegen.binding.MembersInjectionBinding;
-import dagger.internal.codegen.binding.MembersInjectionBinding.InjectionSite;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.internal.codegen.writing.InjectionMethods.InjectionSiteMethod;
-import dagger.model.DependencyRequest;
-import java.util.Map.Entry;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-
-/**
- * Generates {@link MembersInjector} implementations from {@link MembersInjectionBinding} instances.
- */
-public final class MembersInjectorGenerator extends SourceFileGenerator<MembersInjectionBinding> {
- private final DaggerTypes types;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- MembersInjectorGenerator(
- Filer filer,
- DaggerElements elements,
- DaggerTypes types,
- SourceVersion sourceVersion,
- KotlinMetadataUtil metadataUtil) {
- super(filer, elements, sourceVersion);
- this.types = types;
- this.metadataUtil = metadataUtil;
- }
-
- @Override
- public ClassName nameGeneratedType(MembersInjectionBinding binding) {
- return membersInjectorNameForType(binding.membersInjectedType());
- }
-
- @Override
- public Element originatingElement(MembersInjectionBinding binding) {
- return binding.membersInjectedType();
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(MembersInjectionBinding binding) {
- // Empty members injection bindings are special and don't need source files.
- if (binding.injectionSites().isEmpty()) {
- return Optional.empty();
- }
-
- // Members injectors for classes with no local injection sites and no @Inject
- // constructor are unused.
- if (!binding.hasLocalInjectionSites()
- && injectedConstructors(binding.membersInjectedType()).isEmpty()
- && assistedInjectedConstructors(binding.membersInjectedType()).isEmpty()) {
- return Optional.empty();
- }
-
-
- // We don't want to write out resolved bindings -- we want to write out the generic version.
- checkState(
- !binding.unresolved().isPresent(),
- "tried to generate a MembersInjector for a binding of a resolved generic type: %s",
- binding);
-
- ClassName generatedTypeName = nameGeneratedType(binding);
- ImmutableList<TypeVariableName> typeParameters = bindingTypeElementTypeVariableNames(binding);
- TypeSpec.Builder injectorTypeBuilder =
- classBuilder(generatedTypeName)
- .addModifiers(PUBLIC, FINAL)
- .addTypeVariables(typeParameters);
-
- TypeName injectedTypeName = TypeName.get(binding.key().type());
- TypeName implementedType = membersInjectorOf(injectedTypeName);
- injectorTypeBuilder.addSuperinterface(implementedType);
-
- MethodSpec.Builder injectMembersBuilder =
- methodBuilder("injectMembers")
- .addModifiers(PUBLIC)
- .addAnnotation(Override.class)
- .addParameter(injectedTypeName, "instance");
-
- ImmutableMap<DependencyRequest, FrameworkField> fields =
- generateBindingFieldsForDependencies(binding);
-
- ImmutableMap.Builder<DependencyRequest, FieldSpec> dependencyFieldsBuilder =
- ImmutableMap.builder();
-
- MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PUBLIC);
-
- // We use a static create method so that generated components can avoid having
- // to refer to the generic types of the factory.
- // (Otherwise they may have visibility problems referring to the types.)
- MethodSpec.Builder createMethodBuilder =
- methodBuilder("create")
- .returns(implementedType)
- .addModifiers(PUBLIC, STATIC)
- .addTypeVariables(typeParameters);
-
- createMethodBuilder.addCode(
- "return new $T(", parameterizedGeneratedTypeNameForBinding(binding));
- ImmutableList.Builder<CodeBlock> constructorInvocationParameters = ImmutableList.builder();
-
- boolean usesRawFrameworkTypes = false;
- UniqueNameSet fieldNames = new UniqueNameSet();
- for (Entry<DependencyRequest, FrameworkField> fieldEntry : fields.entrySet()) {
- DependencyRequest dependency = fieldEntry.getKey();
- FrameworkField bindingField = fieldEntry.getValue();
-
- // If the dependency type is not visible to this members injector, then use the raw framework
- // type for the field.
- boolean useRawFrameworkType =
- !isTypeAccessibleFrom(dependency.key().type(), generatedTypeName.packageName());
-
- String fieldName = fieldNames.getUniqueName(bindingField.name());
- TypeName fieldType = useRawFrameworkType ? bindingField.type().rawType : bindingField.type();
- FieldSpec.Builder fieldBuilder = FieldSpec.builder(fieldType, fieldName, PRIVATE, FINAL);
- ParameterSpec.Builder parameterBuilder = ParameterSpec.builder(fieldType, fieldName);
-
- // If we're using the raw type for the field, then suppress the injectMembers method's
- // unchecked-type warning and the field's and the constructor and create-method's
- // parameters' raw-type warnings.
- if (useRawFrameworkType) {
- usesRawFrameworkTypes = true;
- fieldBuilder.addAnnotation(suppressWarnings(RAWTYPES));
- parameterBuilder.addAnnotation(suppressWarnings(RAWTYPES));
- }
- constructorBuilder.addParameter(parameterBuilder.build());
- createMethodBuilder.addParameter(parameterBuilder.build());
-
- FieldSpec field = fieldBuilder.build();
- injectorTypeBuilder.addField(field);
- constructorBuilder.addStatement("this.$1N = $1N", field);
- dependencyFieldsBuilder.put(dependency, field);
- constructorInvocationParameters.add(CodeBlock.of("$N", field));
- }
-
- createMethodBuilder.addCode(
- constructorInvocationParameters.build().stream().collect(toParametersCodeBlock()));
- createMethodBuilder.addCode(");");
-
- injectorTypeBuilder.addMethod(constructorBuilder.build());
- injectorTypeBuilder.addMethod(createMethodBuilder.build());
-
- ImmutableMap<DependencyRequest, FieldSpec> dependencyFields = dependencyFieldsBuilder.build();
-
- injectMembersBuilder.addCode(
- InjectionSiteMethod.invokeAll(
- binding.injectionSites(),
- generatedTypeName,
- CodeBlock.of("instance"),
- binding.key().type(),
- frameworkFieldUsages(binding.dependencies(), dependencyFields)::get,
- types,
- metadataUtil));
-
- if (usesRawFrameworkTypes) {
- injectMembersBuilder.addAnnotation(suppressWarnings(UNCHECKED));
- }
- injectorTypeBuilder.addMethod(injectMembersBuilder.build());
-
- for (InjectionSite injectionSite : binding.injectionSites()) {
- if (injectionSite.element().getEnclosingElement().equals(binding.membersInjectedType())) {
- injectorTypeBuilder.addMethod(InjectionSiteMethod.create(injectionSite, metadataUtil));
- }
- }
-
- gwtIncompatibleAnnotation(binding).ifPresent(injectorTypeBuilder::addAnnotation);
-
- return Optional.of(injectorTypeBuilder);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java b/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
deleted file mode 100644
index 534c057..0000000
--- a/java/dagger/internal/codegen/writing/MembersInjectorProviderCreationExpression.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.SourceFiles.membersInjectorNameForType;
-import static dagger.internal.codegen.javapoet.TypeNames.INSTANCE_FACTORY;
-import static dagger.internal.codegen.javapoet.TypeNames.MEMBERS_INJECTORS;
-
-import com.google.auto.common.MoreTypes;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
-
-/** A {@code Provider<MembersInjector<Foo>>} creation expression. */
-final class MembersInjectorProviderCreationExpression
- implements FrameworkInstanceCreationExpression {
-
- private final ComponentBindingExpressions componentBindingExpressions;
- private final ProvisionBinding binding;
-
- MembersInjectorProviderCreationExpression(
- ProvisionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- }
-
- @Override
- public CodeBlock creationExpression() {
- TypeMirror membersInjectedType =
- getOnlyElement(MoreTypes.asDeclared(binding.key().type()).getTypeArguments());
-
- boolean castThroughRawType = false;
- CodeBlock membersInjector;
- if (binding.injectionSites().isEmpty()) {
- membersInjector = CodeBlock.of("$T.<$T>noOp()", MEMBERS_INJECTORS, membersInjectedType);
- } else {
- TypeElement injectedTypeElement = MoreTypes.asTypeElement(membersInjectedType);
- while (!hasLocalInjectionSites(injectedTypeElement)) {
- // Cast through a raw type since we're going to be using the MembersInjector for the
- // parent type.
- castThroughRawType = true;
- injectedTypeElement = MoreTypes.asTypeElement(injectedTypeElement.getSuperclass());
- }
-
- membersInjector = CodeBlock.of(
- "$T.create($L)",
- membersInjectorNameForType(injectedTypeElement),
- componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
- }
-
- // TODO(ronshapiro): consider adding a MembersInjectorBindingExpression to return this directly
- // (as it's rarely requested as a Provider).
- CodeBlock providerExpression = CodeBlock.of("$T.create($L)", INSTANCE_FACTORY, membersInjector);
- // If needed we cast through raw type around the InstanceFactory type as opposed to the
- // MembersInjector since we end up with an InstanceFactory<MembersInjector> as opposed to a
- // InstanceFactory<MembersInjector<Foo>> and that becomes unassignable. To fix it would require
- // a second cast. If we just cast to the raw type InstanceFactory though, that becomes
- // assignable.
- return castThroughRawType
- ? CodeBlock.of("($T) $L", INSTANCE_FACTORY, providerExpression) : providerExpression;
- }
-
- private boolean hasLocalInjectionSites(TypeElement injectedTypeElement) {
- return binding.injectionSites()
- .stream()
- .anyMatch(
- injectionSite ->
- injectionSite.element().getEnclosingElement().equals(injectedTypeElement));
- }
-
- @Override
- public boolean useInnerSwitchingProvider() {
- return !binding.injectionSites().isEmpty();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MethodBindingExpression.java b/java/dagger/internal/codegen/writing/MethodBindingExpression.java
deleted file mode 100644
index 9c0c74a..0000000
--- a/java/dagger/internal/codegen/writing/MethodBindingExpression.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameterSpecs;
-import static dagger.internal.codegen.javapoet.CodeBlocks.parameterNames;
-import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.PRIVATE_METHOD_SCOPED_FIELD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.VOLATILE;
-
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.DoubleCheck;
-import dagger.internal.MemoizedSentinel;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkField;
-import dagger.internal.codegen.binding.KeyVariableNamer;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-import dagger.model.RequestKind;
-import java.util.Optional;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression that wraps another in a nullary method on the component. */
-abstract class MethodBindingExpression extends BindingExpression {
- private final BindingRequest request;
- private final ContributionBinding binding;
- private final BindingMethodImplementation bindingMethodImplementation;
- private final ComponentImplementation componentImplementation;
- private final ProducerEntryPointView producerEntryPointView;
- private final BindingExpression wrappedBindingExpression;
- private final DaggerTypes types;
-
- protected MethodBindingExpression(
- BindingRequest request,
- ContributionBinding binding,
- MethodImplementationStrategy methodImplementationStrategy,
- BindingExpression wrappedBindingExpression,
- ComponentImplementation componentImplementation,
- DaggerTypes types) {
- this.request = checkNotNull(request);
- this.binding = checkNotNull(binding);
- this.bindingMethodImplementation = bindingMethodImplementation(methodImplementationStrategy);
- this.wrappedBindingExpression = checkNotNull(wrappedBindingExpression);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.producerEntryPointView = new ProducerEntryPointView(types);
- this.types = checkNotNull(types);
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- if (request.frameworkType().isPresent()) {
- // Initializing a framework instance that participates in a cycle requires that the underlying
- // FrameworkInstanceBindingExpression is invoked in order for a cycle to be detected properly.
- // When a MethodBindingExpression wraps a FrameworkInstanceBindingExpression, the wrapped
- // expression will only be invoked once to implement the method body. This is a hack to work
- // around that weirdness - methodImplementation.body() will invoke the framework instance
- // initialization again in case the field is not fully initialized.
- // TODO(b/121196706): use a less hacky approach to fix this bug
- Object unused = methodBody();
- }
-
- addMethod();
-
- CodeBlock methodCall =
- binding.kind() == BindingKind.ASSISTED_INJECTION
- // Private methods for assisted injection take assisted parameters as input.
- ? CodeBlock.of(
- "$N($L)", methodName(), parameterNames(assistedParameterSpecs(binding, types)))
- : CodeBlock.of("$N()", methodName());
-
- return Expression.create(
- returnType(),
- requestingClass.equals(componentImplementation.name())
- ? methodCall
- : CodeBlock.of("$L.$L", componentImplementation.externalReferenceBlock(), methodCall));
- }
-
- @Override
- Expression getDependencyExpressionForComponentMethod(ComponentMethodDescriptor componentMethod,
- ComponentImplementation component) {
- return producerEntryPointView
- .getProducerEntryPointField(this, componentMethod, component)
- .orElseGet(
- () -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
- }
-
- /** Adds the method to the component (if necessary) the first time it's called. */
- protected abstract void addMethod();
-
- /** Returns the name of the method to call. */
- protected abstract String methodName();
-
- /** The method's body. */
- protected final CodeBlock methodBody() {
- return implementation(
- wrappedBindingExpression.getDependencyExpression(componentImplementation.name())
- ::codeBlock);
- }
-
- /** The method's body if this method is a component method. */
- protected final CodeBlock methodBodyForComponentMethod(
- ComponentMethodDescriptor componentMethod) {
- return implementation(
- wrappedBindingExpression.getDependencyExpressionForComponentMethod(
- componentMethod, componentImplementation)
- ::codeBlock);
- }
-
- private CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- return bindingMethodImplementation.implementation(simpleBindingExpression);
- }
-
- private BindingMethodImplementation bindingMethodImplementation(
- MethodImplementationStrategy methodImplementationStrategy) {
- switch (methodImplementationStrategy) {
- case SIMPLE:
- return new SimpleMethodImplementation();
- case SINGLE_CHECK:
- return new SingleCheckedMethodImplementation();
- case DOUBLE_CHECK:
- return new DoubleCheckedMethodImplementation();
- }
- throw new AssertionError(methodImplementationStrategy);
- }
-
- /** Returns the return type for the dependency request. */
- protected TypeMirror returnType() {
- if (request.isRequestKind(RequestKind.INSTANCE)
- && binding.contributedPrimitiveType().isPresent()) {
- return binding.contributedPrimitiveType().get();
- }
-
- if (matchingComponentMethod().isPresent()) {
- // Component methods are part of the user-defined API, and thus we must use the user-defined
- // type.
- return matchingComponentMethod().get().resolvedReturnType(types);
- }
-
- TypeMirror requestedType = request.requestedType(binding.contributedType(), types);
- return types.accessibleType(requestedType, componentImplementation.name());
- }
-
- private Optional<ComponentMethodDescriptor> matchingComponentMethod() {
- return componentImplementation.componentDescriptor().firstMatchingComponentMethod(request);
- }
-
- /** Strateg for implementing the body of this method. */
- enum MethodImplementationStrategy {
- SIMPLE,
- SINGLE_CHECK,
- DOUBLE_CHECK,
- ;
- }
-
- private abstract static class BindingMethodImplementation {
- /**
- * Returns the method body, which contains zero or more statements (including semicolons).
- *
- * <p>If the implementation has a non-void return type, the body will also include the {@code
- * return} statement.
- *
- * @param simpleBindingExpression the expression to retrieve an instance of this binding without
- * the wrapping method.
- */
- abstract CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression);
- }
-
- /** Returns the {@code wrappedBindingExpression} directly. */
- private static final class SimpleMethodImplementation extends BindingMethodImplementation {
- @Override
- CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- return CodeBlock.of("return $L;", simpleBindingExpression.get());
- }
- }
-
- /**
- * Defines a method body for single checked caching of the given {@code wrappedBindingExpression}.
- */
- private final class SingleCheckedMethodImplementation extends BindingMethodImplementation {
- private final Supplier<FieldSpec> field = Suppliers.memoize(this::createField);
-
- @Override
- CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- String fieldExpression = field.get().name.equals("local") ? "this.local" : field.get().name;
-
- CodeBlock.Builder builder = CodeBlock.builder()
- .addStatement("Object local = $N", fieldExpression);
-
- if (isNullable()) {
- builder.beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class);
- } else {
- builder.beginControlFlow("if (local == null)");
- }
-
- return builder
- .addStatement("local = $L", simpleBindingExpression.get())
- .addStatement("$N = ($T) local", fieldExpression, returnType())
- .endControlFlow()
- .addStatement("return ($T) local", returnType())
- .build();
- }
-
- FieldSpec createField() {
- String name =
- componentImplementation.getUniqueFieldName(
- request.isRequestKind(RequestKind.INSTANCE)
- ? KeyVariableNamer.name(binding.key())
- : FrameworkField.forBinding(binding, Optional.empty()).name());
-
- FieldSpec.Builder builder = FieldSpec.builder(fieldType(), name, PRIVATE, VOLATILE);
- if (isNullable()) {
- builder.initializer("new $T()", MemoizedSentinel.class);
- }
-
- FieldSpec field = builder.build();
- componentImplementation.addField(PRIVATE_METHOD_SCOPED_FIELD, field);
- return field;
- }
-
- TypeName fieldType() {
- if (isNullable()) {
- // Nullable instances use `MemoizedSentinel` instead of `null` as the initialization value,
- // so the field type must accept that and the return type
- return TypeName.OBJECT;
- }
- TypeName returnType = TypeName.get(returnType());
- return returnType.isPrimitive() ? returnType.box() : returnType;
- }
-
- private boolean isNullable() {
- return request.isRequestKind(RequestKind.INSTANCE) && binding.isNullable();
- }
- }
-
- /**
- * Defines a method body for double checked caching of the given {@code wrappedBindingExpression}.
- */
- private final class DoubleCheckedMethodImplementation extends BindingMethodImplementation {
- private final Supplier<String> fieldName = Suppliers.memoize(this::createField);
-
- @Override
- CodeBlock implementation(Supplier<CodeBlock> simpleBindingExpression) {
- String fieldExpression = fieldName.get().equals("local") ? "this.local" : fieldName.get();
- return CodeBlock.builder()
- .addStatement("$T local = $L", TypeName.OBJECT, fieldExpression)
- .beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
- .beginControlFlow("synchronized (local)")
- .addStatement("local = $L", fieldExpression)
- .beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
- .addStatement("local = $L", simpleBindingExpression.get())
- .addStatement("$1L = $2T.reentrantCheck($1L, local)", fieldExpression, DoubleCheck.class)
- .endControlFlow()
- .endControlFlow()
- .endControlFlow()
- .addStatement("return ($T) local", returnType())
- .build();
- }
-
- private String createField() {
- String name =
- componentImplementation.getUniqueFieldName(KeyVariableNamer.name(binding.key()));
- componentImplementation.addField(
- PRIVATE_METHOD_SCOPED_FIELD,
- FieldSpec.builder(TypeName.OBJECT, name, PRIVATE, VOLATILE)
- .initializer("new $T()", MemoizedSentinel.class)
- .build());
- return name;
- }
- }
-
-}
diff --git a/java/dagger/internal/codegen/writing/ModuleGenerator.java b/java/dagger/internal/codegen/writing/ModuleGenerator.java
deleted file mode 100644
index afd0e99..0000000
--- a/java/dagger/internal/codegen/writing/ModuleGenerator.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import dagger.internal.codegen.base.SourceFileGenerator;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifier for a {@link SourceFileGenerator} for modules. */
-@Qualifier
-@Retention(RUNTIME)
-public @interface ModuleGenerator {}
diff --git a/java/dagger/internal/codegen/writing/ModuleProxies.java b/java/dagger/internal/codegen/writing/ModuleProxies.java
deleted file mode 100644
index fcd9b56..0000000
--- a/java/dagger/internal/codegen/writing/ModuleProxies.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.langmodel.Accessibility.isElementAccessibleFrom;
-import static javax.lang.model.element.Modifier.ABSTRACT;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-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 com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.binding.ModuleKind;
-import dagger.internal.codegen.binding.SourceFiles;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.Accessibility;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.TypeElement;
-
-/** Convenience methods for generating and using module constructor proxy methods. */
-public final class ModuleProxies {
-
- private final DaggerElements elements;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- public ModuleProxies(DaggerElements elements, KotlinMetadataUtil metadataUtil) {
- this.elements = elements;
- this.metadataUtil = metadataUtil;
- }
-
- /** Generates a {@code public static} proxy method for constructing module instances. */
- // TODO(dpb): See if this can become a SourceFileGenerator<ModuleDescriptor> instead. Doing so may
- // cause ModuleProcessingStep to defer elements multiple times.
- public static final class ModuleConstructorProxyGenerator
- extends SourceFileGenerator<TypeElement> {
-
- private final ModuleProxies moduleProxies;
- private final KotlinMetadataUtil metadataUtil;
-
- @Inject
- ModuleConstructorProxyGenerator(
- Filer filer,
- DaggerElements elements,
- SourceVersion sourceVersion,
- ModuleProxies moduleProxies,
- KotlinMetadataUtil metadataUtil) {
- super(filer, elements, sourceVersion);
- this.moduleProxies = moduleProxies;
- this.metadataUtil = metadataUtil;
- }
-
- @Override
- public ClassName nameGeneratedType(TypeElement moduleElement) {
- return moduleProxies.constructorProxyTypeName(moduleElement);
- }
-
- @Override
- public Element originatingElement(TypeElement moduleElement) {
- return moduleElement;
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(TypeElement moduleElement) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
- return moduleProxies.nonPublicNullaryConstructor(moduleElement).isPresent()
- ? Optional.of(buildProxy(moduleElement))
- : Optional.empty();
- }
-
- private TypeSpec.Builder buildProxy(TypeElement moduleElement) {
- return classBuilder(nameGeneratedType(moduleElement))
- .addModifiers(PUBLIC, FINAL)
- .addMethod(constructorBuilder().addModifiers(PRIVATE).build())
- .addMethod(
- methodBuilder("newInstance")
- .addModifiers(PUBLIC, STATIC)
- .returns(ClassName.get(moduleElement))
- .addStatement("return new $T()", moduleElement)
- .build());
- }
- }
-
- /** The name of the class that hosts the module constructor proxy method. */
- private ClassName constructorProxyTypeName(TypeElement moduleElement) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
- ClassName moduleClassName = ClassName.get(moduleElement);
- return moduleClassName
- .topLevelClassName()
- .peerClass(SourceFiles.classFileName(moduleClassName) + "_Proxy");
- }
-
- /**
- * The module constructor being proxied. A proxy is generated if it is not publicly accessible and
- * has no arguments. If an implicit reference to the enclosing class exists, or the module is
- * abstract, no proxy method can be generated.
- */
- private Optional<ExecutableElement> nonPublicNullaryConstructor(TypeElement moduleElement) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
- if (moduleElement.getModifiers().contains(ABSTRACT)
- || (moduleElement.getNestingKind().isNested()
- && !moduleElement.getModifiers().contains(STATIC))) {
- return Optional.empty();
- }
- return constructorsIn(elements.getAllMembers(moduleElement)).stream()
- .filter(constructor -> !Accessibility.isElementPubliclyAccessible(constructor))
- .filter(constructor -> !constructor.getModifiers().contains(PRIVATE))
- .filter(constructor -> constructor.getParameters().isEmpty())
- .findAny();
- }
-
- /**
- * Returns a code block that creates a new module instance, either by invoking the nullary
- * constructor if it's accessible from {@code requestingClass} or else by invoking the
- * constructor's generated proxy method.
- */
- public CodeBlock newModuleInstance(TypeElement moduleElement, ClassName requestingClass) {
- ModuleKind.checkIsModule(moduleElement, metadataUtil);
- String packageName = requestingClass.packageName();
- return nonPublicNullaryConstructor(moduleElement)
- .filter(constructor -> !isElementAccessibleFrom(constructor, packageName))
- .map(
- constructor ->
- CodeBlock.of("$T.newInstance()", constructorProxyTypeName(moduleElement)))
- .orElse(CodeBlock.of("new $T()", moduleElement));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
deleted file mode 100644
index 64e008e..0000000
--- a/java/dagger/internal/codegen/writing/MultibindingFactoryCreationExpression.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.model.DependencyRequest;
-
-/** An abstract factory creation expression for multibindings. */
-abstract class MultibindingFactoryCreationExpression
- implements FrameworkInstanceCreationExpression {
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final ContributionBinding binding;
-
- MultibindingFactoryCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- }
-
- /** Returns the expression for a dependency of this multibinding. */
- protected final CodeBlock multibindingDependencyExpression(DependencyRequest dependency) {
- CodeBlock expression =
- componentBindingExpressions
- .getDependencyExpression(
- BindingRequest.bindingRequest(dependency.key(), binding.frameworkType()),
- componentImplementation.name())
- .codeBlock();
-
- return useRawType()
- ? CodeBlocks.cast(expression, binding.frameworkType().frameworkClass())
- : expression;
- }
-
- /** The binding request for this framework instance. */
- protected final BindingRequest bindingRequest() {
- return BindingRequest.bindingRequest(binding.key(), binding.frameworkType());
- }
-
- /**
- * Returns true if the {@linkplain ContributionBinding#key() key type} is inaccessible from the
- * component, and therefore a raw type must be used.
- */
- protected final boolean useRawType() {
- return !componentImplementation.isTypeAccessible(binding.key().type());
- }
-
- @Override
- public final boolean useInnerSwitchingProvider() {
- return !binding.dependencies().isEmpty();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/OptionalBindingExpression.java b/java/dagger/internal/codegen/writing/OptionalBindingExpression.java
deleted file mode 100644
index 4faf3fa..0000000
--- a/java/dagger/internal/codegen/writing/OptionalBindingExpression.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.base.OptionalType;
-import dagger.internal.codegen.base.OptionalType.OptionalKind;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-
-/** A binding expression for optional bindings. */
-final class OptionalBindingExpression extends SimpleInvocationBindingExpression {
- private final ProvisionBinding binding;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
- private final SourceVersion sourceVersion;
-
- @Inject
- OptionalBindingExpression(
- ProvisionBinding binding,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- SourceVersion sourceVersion) {
- super(binding);
- this.binding = binding;
- this.componentBindingExpressions = componentBindingExpressions;
- this.types = types;
- this.sourceVersion = sourceVersion;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- OptionalType optionalType = OptionalType.from(binding.key());
- OptionalKind optionalKind = optionalType.kind();
- if (binding.dependencies().isEmpty()) {
- if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
- // When compiling with -source 7, javac's type inference isn't strong enough to detect
- // Futures.immediateFuture(Optional.absent()) for keys that aren't Object. It also has
- // issues
- // when used as an argument to some members injection proxy methods (see
- // https://github.com/google/dagger/issues/916)
- if (isTypeAccessibleFrom(binding.key().type(), requestingClass.packageName())) {
- return Expression.create(
- binding.key().type(), optionalKind.parameterizedAbsentValueExpression(optionalType));
- }
- }
- return Expression.create(binding.key().type(), optionalKind.absentValueExpression());
- }
- DependencyRequest dependency = getOnlyElement(binding.dependencies());
-
- CodeBlock dependencyExpression =
- componentBindingExpressions
- .getDependencyExpression(bindingRequest(dependency), requestingClass)
- .codeBlock();
-
- // If the dependency type is inaccessible, then we have to use Optional.<Object>of(...), or else
- // we will get "incompatible types: inference variable has incompatible bounds.
- return isTypeAccessibleFrom(dependency.key().type(), requestingClass.packageName())
- ? Expression.create(
- binding.key().type(), optionalKind.presentExpression(dependencyExpression))
- : Expression.create(
- types.erasure(binding.key().type()),
- optionalKind.presentObjectExpression(dependencyExpression));
- }
-
- @Override
- boolean requiresMethodEncapsulation() {
- // TODO(dpb): Maybe require it for present bindings.
- return false;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/OptionalFactories.java b/java/dagger/internal/codegen/writing/OptionalFactories.java
deleted file mode 100644
index 2d80963..0000000
--- a/java/dagger/internal/codegen/writing/OptionalFactories.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (C) 2016 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.writing;
-
-import static com.google.common.base.CaseFormat.UPPER_CAMEL;
-import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.anonymousClassBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.base.RequestKinds.requestTypeName;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.RAWTYPES;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.TypeNames.PROVIDER;
-import static dagger.internal.codegen.javapoet.TypeNames.abstractProducerOf;
-import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.ABSENT_OPTIONAL_FIELD;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.ABSENT_OPTIONAL_METHOD;
-import static dagger.internal.codegen.writing.ComponentImplementation.TypeSpecKind.PRESENT_FACTORY;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-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 com.squareup.javapoet.TypeVariableName;
-import dagger.internal.InstanceFactory;
-import dagger.internal.Preconditions;
-import dagger.internal.codegen.base.OptionalType;
-import dagger.internal.codegen.base.OptionalType.OptionalKind;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.model.RequestKind;
-import dagger.producers.Producer;
-import dagger.producers.internal.Producers;
-import java.util.Comparator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeMap;
-import java.util.concurrent.Executor;
-import javax.inject.Inject;
-import javax.inject.Provider;
-
-/** The nested class and static methods required by the component to implement optional bindings. */
-// TODO(dpb): Name members simply if a component uses only one of Guava or JDK Optional.
-@PerGeneratedFile
-final class OptionalFactories {
- private final ComponentImplementation componentImplementation;
-
- @Inject OptionalFactories(@TopLevel ComponentImplementation componentImplementation) {
- this.componentImplementation = componentImplementation;
- }
-
- /**
- * The factory classes that implement {@code Provider<Optional<T>>} or {@code
- * Producer<Optional<T>>} for present optional bindings for a given kind of dependency request
- * within the component.
- *
- * <p>The key is the {@code Provider<Optional<T>>} type.
- */
- private final Map<PresentFactorySpec, TypeSpec> presentFactoryClasses =
- new TreeMap<>(
- Comparator.comparing(PresentFactorySpec::valueKind)
- .thenComparing(PresentFactorySpec::frameworkType)
- .thenComparing(PresentFactorySpec::optionalKind));
-
- /**
- * The static methods that return a {@code Provider<Optional<T>>} that always returns an absent
- * value.
- */
- private final Map<OptionalKind, MethodSpec> absentOptionalProviderMethods = new TreeMap<>();
-
- /**
- * The static fields for {@code Provider<Optional<T>>} objects that always return an absent value.
- */
- private final Map<OptionalKind, FieldSpec> absentOptionalProviderFields = new TreeMap<>();
-
- /**
- * Returns an expression that calls a static method that returns a {@code Provider<Optional<T>>}
- * for absent optional bindings.
- */
- CodeBlock absentOptionalProvider(ContributionBinding binding) {
- verify(
- binding.bindingType().equals(BindingType.PROVISION),
- "Absent optional bindings should be provisions: %s",
- binding);
- OptionalKind optionalKind = OptionalType.from(binding.key()).kind();
- return CodeBlock.of(
- "$N()",
- absentOptionalProviderMethods.computeIfAbsent(
- optionalKind,
- kind -> {
- MethodSpec method = absentOptionalProviderMethod(kind);
- componentImplementation.addMethod(ABSENT_OPTIONAL_METHOD, method);
- return method;
- }));
- }
-
- /**
- * Creates a method specification for a {@code Provider<Optional<T>>} that always returns an
- * absent value.
- */
- private MethodSpec absentOptionalProviderMethod(OptionalKind optionalKind) {
- TypeVariableName typeVariable = TypeVariableName.get("T");
- return methodBuilder(
- String.format(
- "absent%sProvider", UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind.name())))
- .addModifiers(PRIVATE, STATIC)
- .addTypeVariable(typeVariable)
- .returns(providerOf(optionalKind.of(typeVariable)))
- .addJavadoc(
- "Returns a {@link $T} that returns {@code $L}.",
- Provider.class,
- optionalKind.absentValueExpression())
- .addCode("$L // safe covariant cast\n", AnnotationSpecs.suppressWarnings(UNCHECKED))
- .addCode(
- "$1T provider = ($1T) $2N;",
- providerOf(optionalKind.of(typeVariable)),
- absentOptionalProviderFields.computeIfAbsent(
- optionalKind,
- kind -> {
- FieldSpec field = absentOptionalProviderField(kind);
- componentImplementation.addField(ABSENT_OPTIONAL_FIELD, field);
- return field;
- }))
- .addCode("return provider;")
- .build();
- }
-
- /**
- * Creates a field specification for a {@code Provider<Optional<T>>} that always returns an absent
- * value.
- */
- private FieldSpec absentOptionalProviderField(OptionalKind optionalKind) {
- return FieldSpec.builder(
- PROVIDER,
- String.format("ABSENT_%s_PROVIDER", optionalKind.name()),
- PRIVATE,
- STATIC,
- FINAL)
- .addAnnotation(AnnotationSpecs.suppressWarnings(RAWTYPES))
- .initializer("$T.create($L)", InstanceFactory.class, optionalKind.absentValueExpression())
- .addJavadoc(
- "A {@link $T} that returns {@code $L}.",
- Provider.class,
- optionalKind.absentValueExpression())
- .build();
- }
-
- /** Information about the type of a factory for present bindings. */
- @AutoValue
- abstract static class PresentFactorySpec {
- /** Whether the factory is a {@link Provider} or a {@link Producer}. */
- abstract FrameworkType frameworkType();
-
- /** What kind of {@code Optional} is returned. */
- abstract OptionalKind optionalKind();
-
- /** The kind of request satisfied by the value of the {@code Optional}. */
- abstract RequestKind valueKind();
-
- /** The type variable for the factory class. */
- TypeVariableName typeVariable() {
- return TypeVariableName.get("T");
- }
-
- /** The type contained by the {@code Optional}. */
- TypeName valueType() {
- return requestTypeName(valueKind(), typeVariable());
- }
-
- /** The type provided or produced by the factory. */
- ParameterizedTypeName optionalType() {
- return optionalKind().of(valueType());
- }
-
- /** The type of the factory. */
- ParameterizedTypeName factoryType() {
- return frameworkType().frameworkClassOf(optionalType());
- }
-
- /** The type of the delegate provider or producer. */
- ParameterizedTypeName delegateType() {
- return frameworkType().frameworkClassOf(typeVariable());
- }
-
- /** Returns the superclass the generated factory should have, if any. */
- Optional<ParameterizedTypeName> superclass() {
- switch (frameworkType()) {
- case PRODUCER_NODE:
- // TODO(cgdecker): This probably isn't a big issue for now, but it's possible this
- // shouldn't be an AbstractProducer:
- // - As AbstractProducer, it'll only call the delegate's get() method once and then cache
- // that result (essentially) rather than calling the delegate's get() method each time
- // its get() method is called (which was what it did before the cancellation change).
- // - It's not 100% clear to me whether the view-creation methods should return a view of
- // the same view created by the delegate or if they should just return their own views.
- return Optional.of(abstractProducerOf(optionalType()));
- default:
- return Optional.empty();
- }
- }
-
- /** Returns the superinterface the generated factory should have, if any. */
- Optional<ParameterizedTypeName> superinterface() {
- switch (frameworkType()) {
- case PROVIDER:
- return Optional.of(factoryType());
- default:
- return Optional.empty();
- }
- }
-
- /** Returns the name of the factory method to generate. */
- String factoryMethodName() {
- switch (frameworkType()) {
- case PROVIDER:
- return "get";
- case PRODUCER_NODE:
- return "compute";
- }
- throw new AssertionError(frameworkType());
- }
-
- /** The name of the factory class. */
- String factoryClassName() {
- return new StringBuilder("Present")
- .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, optionalKind().name()))
- .append(UPPER_UNDERSCORE.to(UPPER_CAMEL, valueKind().toString()))
- .append(frameworkType().frameworkClass().getSimpleName())
- .toString();
- }
-
- private static PresentFactorySpec of(ContributionBinding binding) {
- return new AutoValue_OptionalFactories_PresentFactorySpec(
- FrameworkType.forBindingType(binding.bindingType()),
- OptionalType.from(binding.key()).kind(),
- getOnlyElement(binding.dependencies()).kind());
- }
- }
-
- /**
- * Returns an expression for an instance of a nested class that implements {@code
- * Provider<Optional<T>>} or {@code Producer<Optional<T>>} for a present optional binding, where
- * {@code T} represents dependency requests of that kind.
- *
- * <ul>
- * <li>If {@code optionalRequestKind} is {@link RequestKind#INSTANCE}, the class implements
- * {@code ProviderOrProducer<Optional<T>>}.
- * <li>If {@code optionalRequestKind} is {@link RequestKind#PROVIDER}, the class implements
- * {@code Provider<Optional<Provider<T>>>}.
- * <li>If {@code optionalRequestKind} is {@link RequestKind#LAZY}, the class implements {@code
- * Provider<Optional<Lazy<T>>>}.
- * <li>If {@code optionalRequestKind} is {@link RequestKind#PROVIDER_OF_LAZY}, the class
- * implements {@code Provider<Optional<Provider<Lazy<T>>>>}.
- * <li>If {@code optionalRequestKind} is {@link RequestKind#PRODUCER}, the class implements
- * {@code Producer<Optional<Producer<T>>>}.
- * <li>If {@code optionalRequestKind} is {@link RequestKind#PRODUCED}, the class implements
- * {@code Producer<Optional<Produced<T>>>}.
- * </ul>
- *
- * @param delegateFactory an expression for a {@link Provider} or {@link Producer} of the
- * underlying type
- */
- CodeBlock presentOptionalFactory(ContributionBinding binding, CodeBlock delegateFactory) {
- return CodeBlock.of(
- "$N.of($L)",
- presentFactoryClasses.computeIfAbsent(
- PresentFactorySpec.of(binding),
- spec -> {
- TypeSpec type = presentOptionalFactoryClass(spec);
- componentImplementation.addType(PRESENT_FACTORY, type);
- return type;
- }),
- delegateFactory);
- }
-
- private TypeSpec presentOptionalFactoryClass(PresentFactorySpec spec) {
- FieldSpec delegateField =
- FieldSpec.builder(spec.delegateType(), "delegate", PRIVATE, FINAL).build();
- ParameterSpec delegateParameter = ParameterSpec.builder(delegateField.type, "delegate").build();
- TypeSpec.Builder factoryClassBuilder =
- classBuilder(spec.factoryClassName())
- .addTypeVariable(spec.typeVariable())
- .addModifiers(PRIVATE, STATIC, FINAL)
- .addJavadoc(
- "A {@code $T} that uses a delegate {@code $T}.",
- spec.factoryType(),
- delegateField.type);
-
- spec.superclass().ifPresent(factoryClassBuilder::superclass);
- spec.superinterface().ifPresent(factoryClassBuilder::addSuperinterface);
-
- return factoryClassBuilder
- .addField(delegateField)
- .addMethod(
- constructorBuilder()
- .addModifiers(PRIVATE)
- .addParameter(delegateParameter)
- .addCode(
- "this.$N = $T.checkNotNull($N);",
- delegateField,
- Preconditions.class,
- delegateParameter)
- .build())
- .addMethod(presentOptionalFactoryGetMethod(spec, delegateField))
- .addMethod(
- methodBuilder("of")
- .addModifiers(PRIVATE, STATIC)
- .addTypeVariable(spec.typeVariable())
- .returns(spec.factoryType())
- .addParameter(delegateParameter)
- .addCode(
- "return new $L<$T>($N);",
- spec.factoryClassName(),
- spec.typeVariable(),
- delegateParameter)
- .build())
- .build();
- }
-
- private MethodSpec presentOptionalFactoryGetMethod(
- PresentFactorySpec spec, FieldSpec delegateField) {
- MethodSpec.Builder getMethodBuilder =
- methodBuilder(spec.factoryMethodName()).addAnnotation(Override.class).addModifiers(PUBLIC);
-
- switch (spec.frameworkType()) {
- case PROVIDER:
- return getMethodBuilder
- .returns(spec.optionalType())
- .addCode(
- "return $L;",
- spec.optionalKind()
- .presentExpression(
- FrameworkType.PROVIDER.to(
- spec.valueKind(), CodeBlock.of("$N", delegateField))))
- .build();
-
- case PRODUCER_NODE:
- getMethodBuilder.returns(listenableFutureOf(spec.optionalType()));
-
- switch (spec.valueKind()) {
- case FUTURE: // return a ListenableFuture<Optional<ListenableFuture<T>>>
- case PRODUCER: // return a ListenableFuture<Optional<Producer<T>>>
- return getMethodBuilder
- .addCode(
- "return $T.immediateFuture($L);",
- Futures.class,
- spec.optionalKind()
- .presentExpression(
- FrameworkType.PRODUCER_NODE.to(
- spec.valueKind(), CodeBlock.of("$N", delegateField))))
- .build();
-
- case INSTANCE: // return a ListenableFuture<Optional<T>>
- return getMethodBuilder
- .addCode(
- "return $L;",
- transformFutureToOptional(
- spec.optionalKind(),
- spec.typeVariable(),
- CodeBlock.of("$N.get()", delegateField)))
- .build();
-
- case PRODUCED: // return a ListenableFuture<Optional<Produced<T>>>
- return getMethodBuilder
- .addCode(
- "return $L;",
- transformFutureToOptional(
- spec.optionalKind(),
- spec.valueType(),
- CodeBlock.of(
- "$T.createFutureProduced($N.get())", Producers.class, delegateField)))
- .build();
-
- default:
- throw new UnsupportedOperationException(
- spec.factoryType() + " objects are not supported");
- }
- }
- throw new AssertionError(spec.frameworkType());
- }
-
- /**
- * An expression that uses {@link Futures#transform(ListenableFuture, Function, Executor)} to
- * transform a {@code ListenableFuture<inputType>} into a {@code
- * ListenableFuture<Optional<inputType>>}.
- *
- * @param inputFuture an expression of type {@code ListenableFuture<inputType>}
- */
- private static CodeBlock transformFutureToOptional(
- OptionalKind optionalKind, TypeName inputType, CodeBlock inputFuture) {
- return CodeBlock.of(
- "$T.transform($L, $L, $T.directExecutor())",
- Futures.class,
- inputFuture,
- anonymousClassBuilder("")
- .addSuperinterface(
- ParameterizedTypeName.get(
- ClassName.get(Function.class), inputType, optionalKind.of(inputType)))
- .addMethod(
- methodBuilder("apply")
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .returns(optionalKind.of(inputType))
- .addParameter(inputType, "input")
- .addCode("return $L;", optionalKind.presentExpression(CodeBlock.of("input")))
- .build())
- .build(),
- MoreExecutors.class);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java b/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
deleted file mode 100644
index 593921e..0000000
--- a/java/dagger/internal/codegen/writing/OptionalFactoryInstanceCreationExpression.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-
-/**
- * A {@link FrameworkInstanceCreationExpression} for {@link dagger.model.BindingKind#OPTIONAL
- * optional bindings}.
- */
-final class OptionalFactoryInstanceCreationExpression
- implements FrameworkInstanceCreationExpression {
- private final OptionalFactories optionalFactories;
- private final ContributionBinding binding;
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
-
- OptionalFactoryInstanceCreationExpression(
- OptionalFactories optionalFactories,
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
- this.optionalFactories = optionalFactories;
- this.binding = binding;
- this.componentImplementation = componentImplementation;
- this.componentBindingExpressions = componentBindingExpressions;
- }
-
- @Override
- public CodeBlock creationExpression() {
- return binding.dependencies().isEmpty()
- ? optionalFactories.absentOptionalProvider(binding)
- : optionalFactories.presentOptionalFactory(
- binding,
- componentBindingExpressions
- .getDependencyExpression(
- bindingRequest(
- getOnlyElement(binding.dependencies()).key(), binding.frameworkType()),
- componentImplementation.name())
- .codeBlock());
- }
-
- @Override
- public boolean useInnerSwitchingProvider() {
- // Share providers for empty optionals from OptionalFactories so we don't have numerous
- // switch cases that all return Optional.empty().
- return !binding.dependencies().isEmpty();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ParentComponent.java b/java/dagger/internal/codegen/writing/ParentComponent.java
deleted file mode 100644
index 20b946e..0000000
--- a/java/dagger/internal/codegen/writing/ParentComponent.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * A {@link Qualifier} for bindings that are associated with a component implementation's parent
- * component.
- */
-@Retention(RUNTIME)
-@Qualifier
-public @interface ParentComponent {}
diff --git a/java/dagger/internal/codegen/writing/PerComponentImplementation.java b/java/dagger/internal/codegen/writing/PerComponentImplementation.java
deleted file mode 100644
index 80888df..0000000
--- a/java/dagger/internal/codegen/writing/PerComponentImplementation.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/** A {@link Scope} that encompasses a single component implementation. */
-@Retention(RUNTIME)
-@Scope
-public @interface PerComponentImplementation {}
diff --git a/java/dagger/internal/codegen/writing/PerGeneratedFile.java b/java/dagger/internal/codegen/writing/PerGeneratedFile.java
deleted file mode 100644
index c1fcaf7..0000000
--- a/java/dagger/internal/codegen/writing/PerGeneratedFile.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Scope;
-
-/**
- * A {@link Scope} that encompasses a top-level component implementation and any of its inner
- * descendant component implementations in the same generated file.
- */
-@Retention(RUNTIME)
-@Scope
-public @interface PerGeneratedFile {}
diff --git a/java/dagger/internal/codegen/writing/PrivateMethodBindingExpression.java b/java/dagger/internal/codegen/writing/PrivateMethodBindingExpression.java
deleted file mode 100644
index b6502ea..0000000
--- a/java/dagger/internal/codegen/writing/PrivateMethodBindingExpression.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.assistedParameterSpecs;
-import static dagger.internal.codegen.writing.ComponentImplementation.MethodSpecKind.PRIVATE_METHOD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.google.common.collect.ImmutableList;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.BindingRequest;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.BindingKind;
-
-/**
- * A binding expression that wraps the dependency expressions in a private, no-arg method.
- *
- * <p>Dependents of this binding expression will just call the no-arg private method.
- */
-final class PrivateMethodBindingExpression extends MethodBindingExpression {
- private final ContributionBinding binding;
- private final BindingRequest request;
- private final ComponentImplementation componentImplementation;
- private final CompilerOptions compilerOptions;
- private final DaggerTypes types;
- private String methodName;
-
- PrivateMethodBindingExpression(
- BindingRequest request,
- ContributionBinding binding,
- MethodImplementationStrategy methodImplementationStrategy,
- BindingExpression wrappedBindingExpression,
- ComponentImplementation componentImplementation,
- DaggerTypes types,
- CompilerOptions compilerOptions) {
- super(
- request,
- binding,
- methodImplementationStrategy,
- wrappedBindingExpression,
- componentImplementation,
- types);
- this.binding = binding;
- this.request = checkNotNull(request);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.compilerOptions = checkNotNull(compilerOptions);
- this.types = types;
- }
-
- @Override
- protected void addMethod() {
- if (methodName == null) {
- // Have to set methodName field before implementing the method in order to handle recursion.
- methodName = componentImplementation.getUniqueMethodName(request);
-
- // TODO(bcorso): Fix the order that these generated methods are written to the component.
- componentImplementation.addMethod(
- PRIVATE_METHOD,
- methodBuilder(methodName)
- .addModifiers(PRIVATE)
- .addParameters(
- // Private methods for assisted injection take assisted parameters as input.
- binding.kind() == BindingKind.ASSISTED_INJECTION
- ? assistedParameterSpecs(binding, types)
- : ImmutableList.of())
- .returns(TypeName.get(returnType()))
- .addCode(methodBody())
- .build());
- }
- }
-
- @Override
- protected String methodName() {
- checkState(methodName != null, "addMethod() must be called before methodName()");
- return methodName;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ProducerCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
deleted file mode 100644
index 0d1ccf3..0000000
--- a/java/dagger/internal/codegen/writing/ProducerCreationExpression.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-
-/**
- * A {@link dagger.producers.Producer} creation expression for a {@link
- * dagger.producers.Produces @Produces}-annotated module method.
- */
-// TODO(dpb): Resolve with InjectionOrProvisionProviderCreationExpression.
-final class ProducerCreationExpression implements FrameworkInstanceCreationExpression {
-
- private final ComponentBindingExpressions componentBindingExpressions;
- private final ContributionBinding binding;
-
- ProducerCreationExpression(
- ContributionBinding binding, ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- }
-
- @Override
- public CodeBlock creationExpression() {
- return CodeBlock.of(
- "$T.create($L)",
- generatedClassNameForBinding(binding),
- componentBindingExpressions.getCreateMethodArgumentsCodeBlock(binding));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ProducerEntryPointView.java b/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
deleted file mode 100644
index c58f4e0..0000000
--- a/java/dagger/internal/codegen/writing/ProducerEntryPointView.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static dagger.internal.codegen.writing.ComponentImplementation.FieldSpecKind.FRAMEWORK_FIELD;
-import static javax.lang.model.element.Modifier.PRIVATE;
-
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.RequestKind;
-import dagger.producers.Producer;
-import dagger.producers.internal.CancellationListener;
-import dagger.producers.internal.Producers;
-import java.util.Optional;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A factory of {@linkplain Producers#entryPointViewOf(Producer, CancellationListener) entry point
- * views} of {@link Producer}s.
- */
-final class ProducerEntryPointView {
- private final DaggerTypes types;
-
- ProducerEntryPointView(DaggerTypes types) {
- this.types = types;
- }
-
- /**
- * Returns an expression for an {@linkplain Producers#entryPointViewOf(Producer,
- * CancellationListener) entry point view} of a producer if the component method returns a {@link
- * Producer} or {@link com.google.common.util.concurrent.ListenableFuture}.
- *
- * <p>This is intended to be a replacement implementation for {@link
- * dagger.internal.codegen.writing.BindingExpression#getDependencyExpressionForComponentMethod(ComponentMethodDescriptor,
- * ComponentImplementation)}, and in cases where {@link Optional#empty()} is returned, callers
- * should call {@code super.getDependencyExpressionForComponentMethod()}.
- */
- Optional<Expression> getProducerEntryPointField(
- BindingExpression producerExpression,
- ComponentMethodDescriptor componentMethod,
- ComponentImplementation component) {
- if (component.componentDescriptor().isProduction()
- && (componentMethod.dependencyRequest().get().kind().equals(RequestKind.FUTURE)
- || componentMethod.dependencyRequest().get().kind().equals(RequestKind.PRODUCER))) {
- return Optional.of(
- Expression.create(
- fieldType(componentMethod),
- "$N",
- createField(producerExpression, componentMethod, component)));
- } else {
- // If the component isn't a production component, it won't implement CancellationListener and
- // as such we can't create an entry point. But this binding must also just be a Producer from
- // Provider anyway in that case, so there shouldn't be an issue.
- // TODO(b/116855531): Is it really intended that a non-production component can have Producer
- // entry points?
- return Optional.empty();
- }
- }
-
- private FieldSpec createField(
- BindingExpression producerExpression,
- ComponentMethodDescriptor componentMethod,
- ComponentImplementation component) {
- // TODO(cgdecker): Use a FrameworkFieldInitializer for this?
- // Though I don't think we need the once-only behavior of that, since I think
- // getComponentMethodImplementation will only be called once anyway
- String methodName = componentMethod.methodElement().getSimpleName().toString();
- FieldSpec field =
- FieldSpec.builder(
- TypeName.get(fieldType(componentMethod)),
- component.getUniqueFieldName(methodName + "EntryPoint"),
- PRIVATE)
- .build();
- component.addField(FRAMEWORK_FIELD, field);
-
- CodeBlock fieldInitialization =
- CodeBlock.of(
- "this.$N = $T.entryPointViewOf($L, this);",
- field,
- Producers.class,
- producerExpression.getDependencyExpression(component.name()).codeBlock());
- component.addInitialization(fieldInitialization);
-
- return field;
- }
-
- // TODO(cgdecker): Can we use producerExpression.getDependencyExpression().type() instead of
- // needing to (re)compute this?
- private TypeMirror fieldType(ComponentMethodDescriptor componentMethod) {
- return types.wrapType(componentMethod.dependencyRequest().get().key().type(), Producer.class);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java b/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
deleted file mode 100644
index 5e52923..0000000
--- a/java/dagger/internal/codegen/writing/ProducerFactoryGenerator.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2014 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.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verifyNotNull;
-import static com.squareup.javapoet.ClassName.OBJECT;
-import static com.squareup.javapoet.MethodSpec.constructorBuilder;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.binding.SourceFiles.bindingTypeElementTypeVariableNames;
-import static dagger.internal.codegen.binding.SourceFiles.generateBindingFieldsForDependencies;
-import static dagger.internal.codegen.binding.SourceFiles.generatedClassNameForBinding;
-import static dagger.internal.codegen.binding.SourceFiles.parameterizedGeneratedTypeNameForBinding;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.FUTURE_RETURN_VALUE_IGNORED;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.FUTURES;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCERS;
-import static dagger.internal.codegen.javapoet.TypeNames.PRODUCER_TOKEN;
-import static dagger.internal.codegen.javapoet.TypeNames.VOID_CLASS;
-import static dagger.internal.codegen.javapoet.TypeNames.listOf;
-import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
-import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
-import static dagger.internal.codegen.writing.GwtCompatibility.gwtIncompatibleAnnotation;
-import static java.util.stream.Collectors.joining;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PROTECTED;
-import static javax.lang.model.element.Modifier.PUBLIC;
-import static javax.lang.model.element.Modifier.STATIC;
-
-import 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.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import com.squareup.javapoet.TypeSpec;
-import dagger.internal.codegen.base.SourceFileGenerator;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.Binding;
-import dagger.internal.codegen.binding.FrameworkField;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.internal.codegen.binding.ProductionBinding;
-import dagger.internal.codegen.binding.SourceFiles;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.AnnotationSpecs;
-import dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.model.DependencyRequest;
-import dagger.model.Key;
-import dagger.model.RequestKind;
-import dagger.producers.Producer;
-import dagger.producers.internal.AbstractProducesMethodProducer;
-import dagger.producers.internal.Producers;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Optional;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.type.TypeMirror;
-
-/** Generates {@link Producer} implementations from {@link ProductionBinding} instances. */
-public final class ProducerFactoryGenerator extends SourceFileGenerator<ProductionBinding> {
- private final CompilerOptions compilerOptions;
- private final KeyFactory keyFactory;
-
- @Inject
- ProducerFactoryGenerator(
- Filer filer,
- DaggerElements elements,
- SourceVersion sourceVersion,
- CompilerOptions compilerOptions,
- KeyFactory keyFactory) {
- super(filer, elements, sourceVersion);
- this.compilerOptions = compilerOptions;
- this.keyFactory = keyFactory;
- }
-
- @Override
- public ClassName nameGeneratedType(ProductionBinding binding) {
- return generatedClassNameForBinding(binding);
- }
-
- @Override
- public Element originatingElement(ProductionBinding binding) {
- // we only create factories for bindings that have a binding element
- return binding.bindingElement().get();
- }
-
- @Override
- public Optional<TypeSpec.Builder> write(ProductionBinding binding) {
- // We don't want to write out resolved bindings -- we want to write out the generic version.
- checkArgument(!binding.unresolved().isPresent());
- checkArgument(binding.bindingElement().isPresent());
-
- TypeName providedTypeName = TypeName.get(binding.contributedType());
- TypeName futureTypeName = listenableFutureOf(providedTypeName);
-
- ClassName generatedTypeName = nameGeneratedType(binding);
- TypeSpec.Builder factoryBuilder =
- classBuilder(generatedTypeName)
- .addModifiers(PUBLIC, FINAL)
- .addTypeVariables(bindingTypeElementTypeVariableNames(binding));
-
- UniqueNameSet uniqueFieldNames = new UniqueNameSet();
- ImmutableMap.Builder<DependencyRequest, FieldSpec> fieldsBuilder = ImmutableMap.builder();
-
- MethodSpec.Builder constructorBuilder = constructorBuilder().addModifiers(PRIVATE);
-
- Optional<FieldSpec> moduleField =
- binding.requiresModuleInstance()
- ? Optional.of(
- addFieldAndConstructorParameter(
- factoryBuilder,
- constructorBuilder,
- uniqueFieldNames.getUniqueName("module"),
- TypeName.get(binding.bindingTypeElement().get().asType())))
- : Optional.empty();
-
- List<CodeBlock> frameworkFieldAssignments = new ArrayList<>();
-
- String executorParameterName = null;
- String monitorParameterName = null;
- ImmutableMap<DependencyRequest, FrameworkField> bindingFieldsForDependencies =
- generateBindingFieldsForDependencies(binding);
- for (Entry<DependencyRequest, FrameworkField> entry : bindingFieldsForDependencies.entrySet()) {
- DependencyRequest dependency = entry.getKey();
- Key key = dependency.key();
- FrameworkField bindingField = entry.getValue();
- String fieldName = uniqueFieldNames.getUniqueName(bindingField.name());
- if (key.equals(keyFactory.forProductionImplementationExecutor())) {
- executorParameterName = fieldName;
- constructorBuilder.addParameter(bindingField.type(), executorParameterName);
- } else if (key.equals(keyFactory.forProductionComponentMonitor())) {
- monitorParameterName = fieldName;
- constructorBuilder.addParameter(bindingField.type(), monitorParameterName);
- } else {
- FieldSpec field =
- addFieldAndConstructorParameter(
- factoryBuilder, constructorBuilder, fieldName, bindingField.type());
- fieldsBuilder.put(dependency, field);
- frameworkFieldAssignments.add(fieldAssignment(field, bindingField.type()));
- }
- }
- ImmutableMap<DependencyRequest, FieldSpec> fields = fieldsBuilder.build();
-
- constructorBuilder.addStatement(
- "super($N, $L, $N)",
- verifyNotNull(monitorParameterName),
- producerTokenConstruction(generatedTypeName, binding),
- verifyNotNull(executorParameterName));
-
- if (binding.requiresModuleInstance()) {
- assignField(constructorBuilder, moduleField.get(), null);
- }
-
- constructorBuilder.addCode(CodeBlock.join(frameworkFieldAssignments, "\n"));
-
- MethodSpec.Builder collectDependenciesBuilder =
- methodBuilder("collectDependencies").addAnnotation(Override.class).addModifiers(PROTECTED);
-
- ImmutableList<DependencyRequest> asyncDependencies = asyncDependencies(binding);
- for (DependencyRequest dependency : asyncDependencies) {
- TypeName futureType = listenableFutureOf(asyncDependencyType(dependency));
- CodeBlock futureAccess = CodeBlock.of("$N.get()", fields.get(dependency));
- collectDependenciesBuilder.addStatement(
- "$T $L = $L",
- futureType,
- dependencyFutureName(dependency),
- dependency.kind().equals(RequestKind.PRODUCED)
- ? CodeBlock.of("$T.createFutureProduced($L)", PRODUCERS, futureAccess)
- : futureAccess);
- }
- FutureTransform futureTransform = FutureTransform.create(fields, binding, asyncDependencies);
-
- collectDependenciesBuilder
- .returns(listenableFutureOf(futureTransform.applyArgType()))
- .addStatement("return $L", futureTransform.futureCodeBlock());
-
- MethodSpec.Builder callProducesMethod =
- methodBuilder("callProducesMethod")
- .returns(futureTypeName)
- .addAnnotation(Override.class)
- .addModifiers(PUBLIC)
- .addParameter(futureTransform.applyArgType(), futureTransform.applyArgName())
- .addExceptions(getThrownTypeNames(binding.thrownTypes()))
- .addCode(
- getInvocationCodeBlock(
- binding, providedTypeName, futureTransform.parameterCodeBlocks()));
- if (futureTransform.hasUncheckedCast()) {
- callProducesMethod.addAnnotation(AnnotationSpecs.suppressWarnings(UNCHECKED));
- }
-
- MethodSpec constructor = constructorBuilder.build();
- factoryBuilder
- .superclass(
- ParameterizedTypeName.get(
- ClassName.get(AbstractProducesMethodProducer.class),
- futureTransform.applyArgType(),
- providedTypeName))
- .addMethod(constructor)
- .addMethod(staticFactoryMethod(binding, constructor))
- .addMethod(collectDependenciesBuilder.build())
- .addMethod(callProducesMethod.build());
-
- gwtIncompatibleAnnotation(binding).ifPresent(factoryBuilder::addAnnotation);
-
- // TODO(gak): write a sensible toString
- return Optional.of(factoryBuilder);
- }
-
- private MethodSpec staticFactoryMethod(ProductionBinding binding, MethodSpec constructor) {
- return MethodSpec.methodBuilder("create")
- .addModifiers(PUBLIC, STATIC)
- .returns(parameterizedGeneratedTypeNameForBinding(binding))
- .addTypeVariables(bindingTypeElementTypeVariableNames(binding))
- .addParameters(constructor.parameters)
- .addStatement(
- "return new $T($L)",
- parameterizedGeneratedTypeNameForBinding(binding),
- constructor.parameters.stream()
- .map(p -> CodeBlock.of("$N", p.name))
- .collect(toParametersCodeBlock()))
- .build();
- }
-
- // TODO(ronshapiro): consolidate versions of these
- private static FieldSpec addFieldAndConstructorParameter(
- TypeSpec.Builder typeBuilder,
- MethodSpec.Builder constructorBuilder,
- String variableName,
- TypeName variableType) {
- FieldSpec field = FieldSpec.builder(variableType, variableName, PRIVATE, FINAL).build();
- typeBuilder.addField(field);
- constructorBuilder.addParameter(field.type, field.name);
- return field;
- }
-
- private static CodeBlock fieldAssignment(FieldSpec field, ParameterizedTypeName type) {
- CodeBlock.Builder statement = CodeBlock.builder();
- if (type != null && type.rawType.equals(TypeNames.PRODUCER)) {
- statement.addStatement(
- "this.$1N = $2T.nonCancellationPropagatingViewOf($1N)", field, Producers.class);
- } else {
- statement.addStatement("this.$1N = $1N", field);
- }
- return statement.build();
- }
-
- private static void assignField(
- MethodSpec.Builder constructorBuilder, FieldSpec field, ParameterizedTypeName type) {
- if (type != null && type.rawType.equals(TypeNames.PRODUCER)) {
- constructorBuilder.addStatement(
- "this.$1N = $2T.nonCancellationPropagatingViewOf($1N)", field, Producers.class);
- } else {
- constructorBuilder.addStatement("this.$1N = $1N", field);
- }
- }
-
- /** Returns a list of dependencies that are generated asynchronously. */
- private static ImmutableList<DependencyRequest> asyncDependencies(Binding binding) {
- return binding.dependencies().stream()
- .filter(ProducerFactoryGenerator::isAsyncDependency)
- .collect(toImmutableList());
- }
-
- private CodeBlock producerTokenConstruction(
- ClassName generatedTypeName, ProductionBinding binding) {
- CodeBlock producerTokenArgs =
- compilerOptions.writeProducerNameInToken()
- ? CodeBlock.of(
- "$S",
- String.format(
- "%s#%s",
- ClassName.get(binding.bindingTypeElement().get()),
- binding.bindingElement().get().getSimpleName()))
- : CodeBlock.of("$T.class", generatedTypeName);
- return CodeBlock.of("$T.create($L)", PRODUCER_TOKEN, producerTokenArgs);
- }
-
- /** Returns a name of the variable representing this dependency's future. */
- private static String dependencyFutureName(DependencyRequest dependency) {
- return dependency.requestElement().get().getSimpleName() + "Future";
- }
-
- /** Represents the transformation of an input future by a producer method. */
- abstract static class FutureTransform {
- protected final ImmutableMap<DependencyRequest, FieldSpec> fields;
- protected final ProductionBinding binding;
-
- FutureTransform(ImmutableMap<DependencyRequest, FieldSpec> fields, ProductionBinding binding) {
- this.fields = fields;
- this.binding = binding;
- }
-
- /** The code block representing the future that should be transformed. */
- abstract CodeBlock futureCodeBlock();
-
- /** The type of the argument to the apply method. */
- abstract TypeName applyArgType();
-
- /** The name of the argument to the apply method */
- abstract String applyArgName();
-
- /** The code blocks to be passed to the produces method itself. */
- abstract ImmutableList<CodeBlock> parameterCodeBlocks();
-
- /** Whether the transform method has an unchecked cast. */
- boolean hasUncheckedCast() {
- return false;
- }
-
- CodeBlock frameworkTypeUsageStatement(DependencyRequest dependency) {
- return SourceFiles.frameworkTypeUsageStatement(
- CodeBlock.of("$N", fields.get(dependency)), dependency.kind());
- }
-
- static FutureTransform create(
- ImmutableMap<DependencyRequest, FieldSpec> fields,
- ProductionBinding binding,
- ImmutableList<DependencyRequest> asyncDependencies) {
- if (asyncDependencies.isEmpty()) {
- return new NoArgFutureTransform(fields, binding);
- } else if (asyncDependencies.size() == 1) {
- return new SingleArgFutureTransform(
- fields, binding, Iterables.getOnlyElement(asyncDependencies));
- } else {
- return new MultiArgFutureTransform(fields, binding, asyncDependencies);
- }
- }
- }
-
- static final class NoArgFutureTransform extends FutureTransform {
- NoArgFutureTransform(
- ImmutableMap<DependencyRequest, FieldSpec> fields, ProductionBinding binding) {
- super(fields, binding);
- }
-
- @Override
- CodeBlock futureCodeBlock() {
- return CodeBlock.of("$T.<$T>immediateFuture(null)", FUTURES, VOID_CLASS);
- }
-
- @Override
- TypeName applyArgType() {
- return VOID_CLASS;
- }
-
- @Override
- String applyArgName() {
- return "ignoredVoidArg";
- }
-
- @Override
- ImmutableList<CodeBlock> parameterCodeBlocks() {
- return binding.explicitDependencies().stream()
- .map(this::frameworkTypeUsageStatement)
- .collect(toImmutableList());
- }
- }
-
- static final class SingleArgFutureTransform extends FutureTransform {
- private final DependencyRequest asyncDependency;
-
- SingleArgFutureTransform(
- ImmutableMap<DependencyRequest, FieldSpec> fields,
- ProductionBinding binding,
- DependencyRequest asyncDependency) {
- super(fields, binding);
- this.asyncDependency = asyncDependency;
- }
-
- @Override
- CodeBlock futureCodeBlock() {
- return CodeBlock.of("$L", dependencyFutureName(asyncDependency));
- }
-
- @Override
- TypeName applyArgType() {
- return asyncDependencyType(asyncDependency);
- }
-
- @Override
- String applyArgName() {
- String argName = asyncDependency.requestElement().get().getSimpleName().toString();
- if (argName.equals("module")) {
- return "moduleArg";
- }
- return argName;
- }
-
- @Override
- ImmutableList<CodeBlock> parameterCodeBlocks() {
- ImmutableList.Builder<CodeBlock> parameterCodeBlocks = ImmutableList.builder();
- for (DependencyRequest dependency : binding.explicitDependencies()) {
- // We really want to compare instances here, because asyncDependency is an element in the
- // set binding.dependencies().
- if (dependency == asyncDependency) {
- parameterCodeBlocks.add(CodeBlock.of("$L", applyArgName()));
- } else {
- parameterCodeBlocks.add(frameworkTypeUsageStatement(dependency));
- }
- }
- return parameterCodeBlocks.build();
- }
- }
-
- static final class MultiArgFutureTransform extends FutureTransform {
- private final ImmutableList<DependencyRequest> asyncDependencies;
-
- MultiArgFutureTransform(
- ImmutableMap<DependencyRequest, FieldSpec> fields,
- ProductionBinding binding,
- ImmutableList<DependencyRequest> asyncDependencies) {
- super(fields, binding);
- this.asyncDependencies = asyncDependencies;
- }
-
- @Override
- CodeBlock futureCodeBlock() {
- return CodeBlock.of(
- "$T.<$T>allAsList($L)",
- FUTURES,
- OBJECT,
- asyncDependencies
- .stream()
- .map(ProducerFactoryGenerator::dependencyFutureName)
- .collect(joining(", ")));
- }
-
- @Override
- TypeName applyArgType() {
- return listOf(OBJECT);
- }
-
- @Override
- String applyArgName() {
- return "args";
- }
-
- @Override
- ImmutableList<CodeBlock> parameterCodeBlocks() {
- int argIndex = 0;
- ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder();
- for (DependencyRequest dependency : binding.explicitDependencies()) {
- if (isAsyncDependency(dependency)) {
- codeBlocks.add(
- CodeBlock.of(
- "($T) $L.get($L)", asyncDependencyType(dependency), applyArgName(), argIndex));
- argIndex++;
- } else {
- codeBlocks.add(frameworkTypeUsageStatement(dependency));
- }
- }
- return codeBlocks.build();
- }
-
- @Override
- boolean hasUncheckedCast() {
- return true;
- }
- }
-
- private static boolean isAsyncDependency(DependencyRequest dependency) {
- switch (dependency.kind()) {
- case INSTANCE:
- case PRODUCED:
- return true;
- default:
- return false;
- }
- }
-
- private static TypeName asyncDependencyType(DependencyRequest dependency) {
- TypeName keyName = TypeName.get(dependency.key().type());
- switch (dependency.kind()) {
- case INSTANCE:
- return keyName;
- case PRODUCED:
- return producedOf(keyName);
- default:
- throw new AssertionError();
- }
- }
-
- /**
- * Creates a code block for the invocation of the producer method from the module, which should be
- * used entirely within a method body.
- *
- * @param binding The binding to generate the invocation code block for.
- * @param providedTypeName The type name that should be provided by this producer.
- * @param parameterCodeBlocks The code blocks for all the parameters to the producer method.
- */
- private CodeBlock getInvocationCodeBlock(
- ProductionBinding binding,
- TypeName providedTypeName,
- ImmutableList<CodeBlock> parameterCodeBlocks) {
- CodeBlock moduleCodeBlock =
- CodeBlock.of(
- "$L.$L($L)",
- binding.requiresModuleInstance()
- ? "module"
- : CodeBlock.of("$T", ClassName.get(binding.bindingTypeElement().get())),
- binding.bindingElement().get().getSimpleName(),
- makeParametersCodeBlock(parameterCodeBlocks));
-
- final CodeBlock returnCodeBlock;
- switch (binding.productionKind().get()) {
- case IMMEDIATE:
- returnCodeBlock =
- CodeBlock.of("$T.<$T>immediateFuture($L)", FUTURES, providedTypeName, moduleCodeBlock);
- break;
- case FUTURE:
- returnCodeBlock = moduleCodeBlock;
- break;
- case SET_OF_FUTURE:
- returnCodeBlock = CodeBlock.of("$T.allAsSet($L)", PRODUCERS, moduleCodeBlock);
- break;
- default:
- throw new AssertionError();
- }
- return CodeBlock.of("return $L;", returnCodeBlock);
- }
-
- /**
- * Converts the list of thrown types into type names.
- *
- * @param thrownTypes the list of thrown types.
- */
- private FluentIterable<? extends TypeName> getThrownTypeNames(
- Iterable<? extends TypeMirror> thrownTypes) {
- return FluentIterable.from(thrownTypes).transform(TypeName::get);
- }
-
- @Override
- protected ImmutableSet<Suppression> warningSuppressions() {
- // TODO(beder): examine if we can remove this or prevent subtypes of Future from being produced
- return ImmutableSet.of(FUTURE_RETURN_VALUE_IGNORED);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java b/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
deleted file mode 100644
index 9b0d4e8..0000000
--- a/java/dagger/internal/codegen/writing/ProducerFromProviderCreationExpression.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.TypeNames;
-import dagger.internal.codegen.writing.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
-import dagger.model.RequestKind;
-import dagger.producers.Producer;
-import java.util.Optional;
-
-/** An {@link Producer} creation expression for provision bindings. */
-final class ProducerFromProviderCreationExpression implements FrameworkInstanceCreationExpression {
- private final ContributionBinding binding;
- private final ComponentImplementation componentImplementation;
- private final ComponentBindingExpressions componentBindingExpressions;
-
- ProducerFromProviderCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions) {
- this.binding = checkNotNull(binding);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.componentBindingExpressions = checkNotNull(componentBindingExpressions);
- }
-
- @Override
- public CodeBlock creationExpression() {
- return FrameworkType.PROVIDER.to(
- RequestKind.PRODUCER,
- componentBindingExpressions
- .getDependencyExpression(
- bindingRequest(binding.key(), FrameworkType.PROVIDER),
- componentImplementation.name())
- .codeBlock());
- }
-
- @Override
- public Optional<ClassName> alternativeFrameworkClass() {
- return Optional.of(TypeNames.PRODUCER);
- }
-
- // TODO(ronshapiro): should this have a simple factory if the delegate expression is simple?
-}
diff --git a/java/dagger/internal/codegen/writing/ProducerNodeInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/ProducerNodeInstanceBindingExpression.java
deleted file mode 100644
index 0d3f7e8..0000000
--- a/java/dagger/internal/codegen/writing/ProducerNodeInstanceBindingExpression.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.ComponentDescriptor.ComponentMethodDescriptor;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-
-/** Binding expression for producer node instances. */
-final class ProducerNodeInstanceBindingExpression extends FrameworkInstanceBindingExpression {
- /** The component defining this binding. */
- private final ComponentImplementation componentImplementation;
- private final Key key;
- private final ProducerEntryPointView producerEntryPointView;
-
- ProducerNodeInstanceBindingExpression(
- ContributionBinding binding,
- FrameworkInstanceSupplier frameworkInstanceSupplier,
- DaggerTypes types,
- DaggerElements elements,
- ComponentImplementation componentImplementation) {
- super(binding, frameworkInstanceSupplier, types, elements);
- this.componentImplementation = checkNotNull(componentImplementation);
- this.key = binding.key();
- this.producerEntryPointView = new ProducerEntryPointView(types);
- }
-
- @Override
- protected FrameworkType frameworkType() {
- return FrameworkType.PRODUCER_NODE;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- Expression result = super.getDependencyExpression(requestingClass);
- componentImplementation.addCancellableProducerKey(key);
- return result;
- }
-
- @Override
- Expression getDependencyExpressionForComponentMethod(
- ComponentMethodDescriptor componentMethod, ComponentImplementation component) {
- return producerEntryPointView
- .getProducerEntryPointField(this, componentMethod, component)
- .orElseGet(
- () -> super.getDependencyExpressionForComponentMethod(componentMethod, component));
- }
-}
diff --git a/java/dagger/internal/codegen/writing/ProviderInstanceBindingExpression.java b/java/dagger/internal/codegen/writing/ProviderInstanceBindingExpression.java
deleted file mode 100644
index 400c6a2..0000000
--- a/java/dagger/internal/codegen/writing/ProviderInstanceBindingExpression.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-
-/** Binding expression for provider instances. */
-final class ProviderInstanceBindingExpression extends FrameworkInstanceBindingExpression {
-
- ProviderInstanceBindingExpression(
- ContributionBinding binding,
- FrameworkInstanceSupplier frameworkInstanceSupplier,
- DaggerTypes types,
- DaggerElements elements) {
- super(
- binding,
- frameworkInstanceSupplier,
- types,
- elements);
- }
-
- @Override
- protected FrameworkType frameworkType() {
- return FrameworkType.PROVIDER;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SetBindingExpression.java b/java/dagger/internal/codegen/writing/SetBindingExpression.java
deleted file mode 100644
index 0b2e11a..0000000
--- a/java/dagger/internal/codegen/writing/SetBindingExpression.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.internal.codegen.binding.BindingRequest.bindingRequest;
-import static dagger.internal.codegen.javapoet.CodeBlocks.toParametersCodeBlock;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static javax.lang.model.util.ElementFilter.methodsIn;
-
-import com.google.common.collect.ImmutableSet;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.SetBuilder;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.DependencyRequest;
-import java.util.Collections;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression for multibound sets. */
-final class SetBindingExpression extends SimpleInvocationBindingExpression {
- private final ProvisionBinding binding;
- private final BindingGraph graph;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final DaggerTypes types;
- private final DaggerElements elements;
-
- SetBindingExpression(
- ProvisionBinding binding,
- BindingGraph graph,
- ComponentBindingExpressions componentBindingExpressions,
- DaggerTypes types,
- DaggerElements elements) {
- super(binding);
- this.binding = binding;
- this.graph = graph;
- this.componentBindingExpressions = componentBindingExpressions;
- this.types = types;
- this.elements = elements;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- // TODO(ronshapiro): We should also make an ImmutableSet version of SetFactory
- boolean isImmutableSetAvailable = isImmutableSetAvailable();
- // TODO(ronshapiro, gak): Use Sets.immutableEnumSet() if it's available?
- if (isImmutableSetAvailable && binding.dependencies().stream().allMatch(this::isSingleValue)) {
- return Expression.create(
- immutableSetType(),
- CodeBlock.builder()
- .add("$T.", ImmutableSet.class)
- .add(maybeTypeParameter(requestingClass))
- .add(
- "of($L)",
- binding
- .dependencies()
- .stream()
- .map(dependency -> getContributionExpression(dependency, requestingClass))
- .collect(toParametersCodeBlock()))
- .build());
- }
- switch (binding.dependencies().size()) {
- case 0:
- return collectionsStaticFactoryInvocation(requestingClass, CodeBlock.of("emptySet()"));
- case 1:
- {
- DependencyRequest dependency = getOnlyElement(binding.dependencies());
- CodeBlock contributionExpression = getContributionExpression(dependency, requestingClass);
- if (isSingleValue(dependency)) {
- return collectionsStaticFactoryInvocation(
- requestingClass, CodeBlock.of("singleton($L)", contributionExpression));
- } else if (isImmutableSetAvailable) {
- return Expression.create(
- immutableSetType(),
- CodeBlock.builder()
- .add("$T.", ImmutableSet.class)
- .add(maybeTypeParameter(requestingClass))
- .add("copyOf($L)", contributionExpression)
- .build());
- }
- }
- // fall through
- default:
- CodeBlock.Builder instantiation = CodeBlock.builder();
- instantiation
- .add("$T.", isImmutableSetAvailable ? ImmutableSet.class : SetBuilder.class)
- .add(maybeTypeParameter(requestingClass));
- if (isImmutableSetBuilderWithExpectedSizeAvailable()) {
- instantiation.add("builderWithExpectedSize($L)", binding.dependencies().size());
- } else if (isImmutableSetAvailable) {
- instantiation.add("builder()");
- } else {
- instantiation.add("newSetBuilder($L)", binding.dependencies().size());
- }
- for (DependencyRequest dependency : binding.dependencies()) {
- String builderMethod = isSingleValue(dependency) ? "add" : "addAll";
- instantiation.add(
- ".$L($L)", builderMethod, getContributionExpression(dependency, requestingClass));
- }
- instantiation.add(".build()");
- return Expression.create(
- isImmutableSetAvailable ? immutableSetType() : binding.key().type(),
- instantiation.build());
- }
- }
-
- private DeclaredType immutableSetType() {
- return types.getDeclaredType(
- elements.getTypeElement(ImmutableSet.class), SetType.from(binding.key()).elementType());
- }
-
- private CodeBlock getContributionExpression(
- DependencyRequest dependency, ClassName requestingClass) {
- return componentBindingExpressions
- .getDependencyExpression(bindingRequest(dependency), requestingClass)
- .codeBlock();
- }
-
- private Expression collectionsStaticFactoryInvocation(
- ClassName requestingClass, CodeBlock methodInvocation) {
- return Expression.create(
- binding.key().type(),
- CodeBlock.builder()
- .add("$T.", Collections.class)
- .add(maybeTypeParameter(requestingClass))
- .add(methodInvocation)
- .build());
- }
-
- private CodeBlock maybeTypeParameter(ClassName requestingClass) {
- TypeMirror elementType = SetType.from(binding.key()).elementType();
- return isTypeAccessibleFrom(elementType, requestingClass.packageName())
- ? CodeBlock.of("<$T>", elementType)
- : CodeBlock.of("");
- }
-
- private boolean isSingleValue(DependencyRequest dependency) {
- return graph.contributionBinding(dependency.key())
- .contributionType()
- .equals(ContributionType.SET);
- }
-
- private boolean isImmutableSetBuilderWithExpectedSizeAvailable() {
- if (isImmutableSetAvailable()) {
- return methodsIn(elements.getTypeElement(ImmutableSet.class).getEnclosedElements())
- .stream()
- .anyMatch(method -> method.getSimpleName().contentEquals("builderWithExpectedSize"));
- }
- return false;
- }
-
- private boolean isImmutableSetAvailable() {
- return elements.getTypeElement(ImmutableSet.class) != null;
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java b/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
deleted file mode 100644
index 754f909..0000000
--- a/java/dagger/internal/codegen/writing/SetFactoryCreationExpression.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static dagger.internal.codegen.binding.SourceFiles.setFactoryClassName;
-
-import com.squareup.javapoet.CodeBlock;
-import dagger.internal.codegen.base.ContributionType;
-import dagger.internal.codegen.base.SetType;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.BindingType;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.model.DependencyRequest;
-import dagger.producers.Produced;
-
-/** A factory creation expression for a multibound set. */
-final class SetFactoryCreationExpression extends MultibindingFactoryCreationExpression {
- private final BindingGraph graph;
- private final ContributionBinding binding;
-
- SetFactoryCreationExpression(
- ContributionBinding binding,
- ComponentImplementation componentImplementation,
- ComponentBindingExpressions componentBindingExpressions,
- BindingGraph graph) {
- super(binding, componentImplementation, componentBindingExpressions);
- this.binding = checkNotNull(binding);
- this.graph = checkNotNull(graph);
- }
-
- @Override
- public CodeBlock creationExpression() {
- CodeBlock.Builder builder = CodeBlock.builder().add("$T.", setFactoryClassName(binding));
- if (!useRawType()) {
- SetType setType = SetType.from(binding.key());
- builder.add(
- "<$T>",
- setType.elementsAreTypeOf(Produced.class)
- ? setType.unwrappedElementType(Produced.class)
- : setType.elementType());
- }
-
- int individualProviders = 0;
- int setProviders = 0;
- CodeBlock.Builder builderMethodCalls = CodeBlock.builder();
- String methodNameSuffix =
- binding.bindingType().equals(BindingType.PROVISION) ? "Provider" : "Producer";
-
- for (DependencyRequest dependency : binding.dependencies()) {
- ContributionType contributionType =
- graph.contributionBinding(dependency.key()).contributionType();
- String methodNamePrefix;
- switch (contributionType) {
- case SET:
- individualProviders++;
- methodNamePrefix = "add";
- break;
- case SET_VALUES:
- setProviders++;
- methodNamePrefix = "addCollection";
- break;
- default:
- throw new AssertionError(dependency + " is not a set multibinding");
- }
-
- builderMethodCalls.add(
- ".$N$N($L)",
- methodNamePrefix,
- methodNameSuffix,
- multibindingDependencyExpression(dependency));
- }
- builder.add("builder($L, $L)", individualProviders, setProviders);
- builder.add(builderMethodCalls.build());
-
- return builder.add(".build()").build();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java b/java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java
deleted file mode 100644
index f2062f4..0000000
--- a/java/dagger/internal/codegen/writing/SimpleInvocationBindingExpression.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import dagger.internal.codegen.binding.ContributionBinding;
-
-/** A simple binding expression for instance requests. Does not scope. */
-abstract class SimpleInvocationBindingExpression extends BindingExpression {
- private final ContributionBinding binding;
-
- SimpleInvocationBindingExpression(ContributionBinding binding) {
- this.binding = checkNotNull(binding);
- }
-
- @Override
- boolean requiresMethodEncapsulation() {
- return !binding.dependencies().isEmpty();
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SimpleMethodBindingExpression.java b/java/dagger/internal/codegen/writing/SimpleMethodBindingExpression.java
deleted file mode 100644
index 82e6628..0000000
--- a/java/dagger/internal/codegen/writing/SimpleMethodBindingExpression.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 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.writing;
-
-import static com.google.auto.common.MoreElements.asExecutable;
-import static com.google.auto.common.MoreElements.asType;
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock;
-import static dagger.internal.codegen.javapoet.TypeNames.rawTypeName;
-import static dagger.internal.codegen.langmodel.Accessibility.isTypeAccessibleFrom;
-import static dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod.requiresInjectionMethod;
-
-import com.google.auto.common.MoreTypes;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeName;
-import dagger.internal.codegen.binding.ComponentRequirement;
-import dagger.internal.codegen.binding.ProvisionBinding;
-import dagger.internal.codegen.compileroption.CompilerOptions;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.kotlin.KotlinMetadataUtil;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import dagger.internal.codegen.writing.InjectionMethods.ProvisionMethod;
-import dagger.model.DependencyRequest;
-import java.util.Optional;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-/**
- * A binding expression that invokes methods or constructors directly (without attempting to scope)
- * {@link dagger.model.RequestKind#INSTANCE} requests.
- */
-final class SimpleMethodBindingExpression extends SimpleInvocationBindingExpression {
- private final CompilerOptions compilerOptions;
- private final ProvisionBinding provisionBinding;
- private final ComponentBindingExpressions componentBindingExpressions;
- private final MembersInjectionMethods membersInjectionMethods;
- private final ComponentRequirementExpressions componentRequirementExpressions;
- private final DaggerElements elements;
- private final SourceVersion sourceVersion;
- private final KotlinMetadataUtil metadataUtil;
-
- SimpleMethodBindingExpression(
- ProvisionBinding binding,
- CompilerOptions compilerOptions,
- ComponentBindingExpressions componentBindingExpressions,
- MembersInjectionMethods membersInjectionMethods,
- ComponentRequirementExpressions componentRequirementExpressions,
- DaggerElements elements,
- SourceVersion sourceVersion,
- KotlinMetadataUtil metadataUtil) {
- super(binding);
- this.compilerOptions = compilerOptions;
- this.provisionBinding = binding;
- this.metadataUtil = metadataUtil;
- checkArgument(
- provisionBinding.implicitDependencies().isEmpty(),
- "framework deps are not currently supported");
- checkArgument(provisionBinding.bindingElement().isPresent());
- this.componentBindingExpressions = componentBindingExpressions;
- this.membersInjectionMethods = membersInjectionMethods;
- this.componentRequirementExpressions = componentRequirementExpressions;
- this.elements = elements;
- this.sourceVersion = sourceVersion;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return requiresInjectionMethod(provisionBinding, compilerOptions, requestingClass)
- ? invokeInjectionMethod(requestingClass)
- : invokeMethod(requestingClass);
- }
-
- private Expression invokeMethod(ClassName requestingClass) {
- // TODO(dpb): align this with the contents of InlineMethods.create
- CodeBlock arguments =
- makeParametersCodeBlock(
- ProvisionMethod.invokeArguments(
- provisionBinding,
- request -> dependencyArgument(request, requestingClass).codeBlock(),
- requestingClass));
- ExecutableElement method = asExecutable(provisionBinding.bindingElement().get());
- CodeBlock invocation;
- switch (method.getKind()) {
- case CONSTRUCTOR:
- invocation = CodeBlock.of("new $T($L)", constructorTypeName(requestingClass), arguments);
- break;
- case METHOD:
- CodeBlock module;
- Optional<CodeBlock> requiredModuleInstance = moduleReference(requestingClass);
- if (requiredModuleInstance.isPresent()) {
- module = requiredModuleInstance.get();
- } else if (metadataUtil.isObjectClass(asType(method.getEnclosingElement()))) {
- // Call through the singleton instance.
- // See: https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods
- module = CodeBlock.of("$T.INSTANCE", provisionBinding.bindingTypeElement().get());
- } else {
- module = CodeBlock.of("$T", provisionBinding.bindingTypeElement().get());
- }
- invocation = CodeBlock.of("$L.$L($L)", module, method.getSimpleName(), arguments);
- break;
- default:
- throw new IllegalStateException();
- }
-
- return Expression.create(simpleMethodReturnType(), invocation);
- }
-
- private TypeName constructorTypeName(ClassName requestingClass) {
- DeclaredType type = MoreTypes.asDeclared(provisionBinding.key().type());
- TypeName typeName = TypeName.get(type);
- if (type.getTypeArguments().stream()
- .allMatch(t -> isTypeAccessibleFrom(t, requestingClass.packageName()))) {
- return typeName;
- }
- return rawTypeName(typeName);
- }
-
- private Expression invokeInjectionMethod(ClassName requestingClass) {
- return injectMembers(
- ProvisionMethod.invoke(
- provisionBinding,
- request -> dependencyArgument(request, requestingClass).codeBlock(),
- requestingClass,
- moduleReference(requestingClass),
- compilerOptions,
- metadataUtil));
- }
-
- private Expression dependencyArgument(DependencyRequest dependency, ClassName requestingClass) {
- return componentBindingExpressions.getDependencyArgumentExpression(dependency, requestingClass);
- }
-
- private Expression injectMembers(CodeBlock instance) {
- if (provisionBinding.injectionSites().isEmpty()) {
- return Expression.create(simpleMethodReturnType(), instance);
- }
- if (sourceVersion.compareTo(SourceVersion.RELEASE_7) <= 0) {
- // Java 7 type inference can't figure out that instance in
- // injectParameterized(Parameterized_Factory.newParameterized()) is Parameterized<T> and not
- // Parameterized<Object>
- if (!MoreTypes.asDeclared(provisionBinding.key().type()).getTypeArguments().isEmpty()) {
- TypeName keyType = TypeName.get(provisionBinding.key().type());
- instance = CodeBlock.of("($T) ($T) $L", keyType, rawTypeName(keyType), instance);
- }
- }
- MethodSpec membersInjectionMethod = membersInjectionMethods.getOrCreate(provisionBinding.key());
- TypeMirror returnType =
- membersInjectionMethod.returnType.equals(TypeName.OBJECT)
- ? elements.getTypeElement(Object.class).asType()
- : provisionBinding.key().type();
- return Expression.create(returnType, CodeBlock.of("$N($L)", membersInjectionMethod, instance));
- }
-
- private Optional<CodeBlock> moduleReference(ClassName requestingClass) {
- return provisionBinding.requiresModuleInstance()
- ? provisionBinding
- .contributingModule()
- .map(Element::asType)
- .map(ComponentRequirement::forModule)
- .map(module -> componentRequirementExpressions.getExpression(module, requestingClass))
- : Optional.empty();
- }
-
- private TypeMirror simpleMethodReturnType() {
- return provisionBinding.contributedPrimitiveType().orElse(provisionBinding.key().type());
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java b/java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java
deleted file mode 100644
index 3099048..0000000
--- a/java/dagger/internal/codegen/writing/SubcomponentCreatorBindingExpression.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 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.writing;
-
-import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.ContributionBinding;
-import dagger.internal.codegen.javapoet.Expression;
-import javax.lang.model.type.TypeMirror;
-
-/** A binding expression for a subcomponent creator that just invokes the constructor. */
-final class SubcomponentCreatorBindingExpression extends SimpleInvocationBindingExpression {
- private final TypeMirror creatorType;
- private final String creatorImplementationName;
-
- SubcomponentCreatorBindingExpression(
- ContributionBinding binding, String creatorImplementationName) {
- super(binding);
- this.creatorType = binding.key().type();
- this.creatorImplementationName = creatorImplementationName;
- }
-
- @Override
- Expression getDependencyExpression(ClassName requestingClass) {
- return Expression.create(creatorType, "new $L()", creatorImplementationName);
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SubcomponentNames.java b/java/dagger/internal/codegen/writing/SubcomponentNames.java
deleted file mode 100644
index fa0037b..0000000
--- a/java/dagger/internal/codegen/writing/SubcomponentNames.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
-import static java.lang.Character.isUpperCase;
-import static java.lang.String.format;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimaps;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.binding.BindingGraph;
-import dagger.internal.codegen.binding.ComponentCreatorDescriptor;
-import dagger.internal.codegen.binding.ComponentDescriptor;
-import dagger.internal.codegen.binding.KeyFactory;
-import dagger.model.Key;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-
-/**
- * Holds the unique simple names for all subcomponents, keyed by their {@link ComponentDescriptor}
- * and {@link Key} of the subcomponent builder.
- */
-public final class SubcomponentNames {
- private static final Splitter QUALIFIED_NAME_SPLITTER = Splitter.on('.');
-
- private final ImmutableMap<ComponentDescriptor, String> namesByDescriptor;
- private final ImmutableMap<Key, ComponentDescriptor> descriptorsByCreatorKey;
-
- public SubcomponentNames(BindingGraph graph, KeyFactory keyFactory) {
- this.namesByDescriptor = namesByDescriptor(graph);
- this.descriptorsByCreatorKey = descriptorsByCreatorKey(keyFactory, namesByDescriptor.keySet());
- }
-
- /** Returns the simple component name for the given {@link ComponentDescriptor}. */
- String get(ComponentDescriptor componentDescriptor) {
- return namesByDescriptor.get(componentDescriptor);
- }
-
- /**
- * Returns the simple name for the subcomponent creator implementation with the given {@link Key}.
- */
- String getCreatorName(Key key) {
- return getCreatorName(descriptorsByCreatorKey.get(key));
- }
-
- /**
- * Returns the simple name for the subcomponent creator implementation for the given {@link
- * ComponentDescriptor}.
- */
- String getCreatorName(ComponentDescriptor componentDescriptor) {
- checkArgument(componentDescriptor.creatorDescriptor().isPresent());
- ComponentCreatorDescriptor creatorDescriptor = componentDescriptor.creatorDescriptor().get();
- return get(componentDescriptor) + creatorDescriptor.kind().typeName();
- }
-
- private static ImmutableMap<ComponentDescriptor, String> namesByDescriptor(BindingGraph graph) {
- ImmutableListMultimap<String, ComponentDescriptor> componentDescriptorsBySimpleName =
- Multimaps.index(graph.componentDescriptors(), SubcomponentNames::simpleName);
- Map<ComponentDescriptor, String> subcomponentImplSimpleNames = new LinkedHashMap<>();
- componentDescriptorsBySimpleName
- .asMap()
- .values()
- .stream()
- .map(SubcomponentNames::disambiguateConflictingSimpleNames)
- .forEach(subcomponentImplSimpleNames::putAll);
- subcomponentImplSimpleNames.remove(graph.componentDescriptor());
- return ImmutableMap.copyOf(subcomponentImplSimpleNames);
- }
-
- private static ImmutableMap<Key, ComponentDescriptor> descriptorsByCreatorKey(
- KeyFactory keyFactory, ImmutableSet<ComponentDescriptor> subcomponents) {
- return subcomponents.stream()
- .filter(subcomponent -> subcomponent.creatorDescriptor().isPresent())
- .collect(
- toImmutableMap(
- subcomponent ->
- keyFactory.forSubcomponentCreator(
- subcomponent.creatorDescriptor().get().typeElement().asType()),
- subcomponent -> subcomponent));
- }
-
- private static ImmutableMap<ComponentDescriptor, String> disambiguateConflictingSimpleNames(
- Collection<ComponentDescriptor> componentsWithConflictingNames) {
- // If there's only 1 component there's nothing to disambiguate so return the simple name.
- if (componentsWithConflictingNames.size() == 1) {
- ComponentDescriptor component = Iterables.getOnlyElement(componentsWithConflictingNames);
- return ImmutableMap.of(component, simpleName(component));
- }
-
- // There are conflicting simple names, so disambiguate them with a unique prefix.
- // We keep them small to fix https://github.com/google/dagger/issues/421.
- UniqueNameSet nameSet = new UniqueNameSet();
- ImmutableMap.Builder<ComponentDescriptor, String> uniqueNames = ImmutableMap.builder();
- for (ComponentDescriptor component : componentsWithConflictingNames) {
- String simpleName = simpleName(component);
- String basePrefix = uniquingPrefix(component);
- uniqueNames.put(component, format("%s_%s", nameSet.getUniqueName(basePrefix), simpleName));
- }
- return uniqueNames.build();
- }
-
- private static String simpleName(ComponentDescriptor component) {
- return component.typeElement().getSimpleName().toString();
- }
-
- /** Returns a prefix that could make the component's simple name more unique. */
- private static String uniquingPrefix(ComponentDescriptor component) {
- TypeElement typeElement = component.typeElement();
- String containerName = typeElement.getEnclosingElement().getSimpleName().toString();
-
- // If parent element looks like a class, use its initials as a prefix.
- if (!containerName.isEmpty() && isUpperCase(containerName.charAt(0))) {
- return CharMatcher.javaLowerCase().removeFrom(containerName);
- }
-
- // Not in a normally named class. Prefix with the initials of the elements leading here.
- Name qualifiedName = typeElement.getQualifiedName();
- Iterator<String> pieces = QUALIFIED_NAME_SPLITTER.split(qualifiedName).iterator();
- StringBuilder b = new StringBuilder();
-
- while (pieces.hasNext()) {
- String next = pieces.next();
- if (pieces.hasNext()) {
- b.append(next.charAt(0));
- }
- }
-
- // Note that a top level class in the root package will be prefixed "$_".
- return b.length() > 0 ? b.toString() : "$";
- }
-}
diff --git a/java/dagger/internal/codegen/writing/SwitchingProviders.java b/java/dagger/internal/codegen/writing/SwitchingProviders.java
deleted file mode 100644
index d38b9d9..0000000
--- a/java/dagger/internal/codegen/writing/SwitchingProviders.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2018 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.writing;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.getLast;
-import static com.google.common.collect.Iterables.getOnlyElement;
-import static com.squareup.javapoet.MethodSpec.methodBuilder;
-import static com.squareup.javapoet.TypeSpec.classBuilder;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.Suppression.UNCHECKED;
-import static dagger.internal.codegen.javapoet.AnnotationSpecs.suppressWarnings;
-import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.CodeBlock;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import com.squareup.javapoet.TypeVariableName;
-import dagger.internal.codegen.base.UniqueNameSet;
-import dagger.internal.codegen.javapoet.CodeBlocks;
-import dagger.internal.codegen.javapoet.Expression;
-import dagger.internal.codegen.langmodel.DaggerTypes;
-import dagger.model.Key;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Keeps track of all provider expression requests for a component.
- *
- * <p>The provider expression request will be satisfied by a single generated {@code Provider} inner
- * class that can provide instances for all types by switching on an id.
- */
-// TODO(ronshapiro): either merge this with InnerSwitchingProviders, or repurpose this for
-// SwitchingProducers
-abstract class SwitchingProviders {
- /**
- * Defines the {@linkplain Expression expressions} for a switch case in a {@code SwitchProvider}
- * for a particular binding.
- */
- // TODO(bcorso): Consider handling SwitchingProviders with dependency arguments in this class,
- // then we wouldn't need the getProviderExpression method.
- // TODO(bcorso): Consider making this an abstract class with equals/hashCode defined by the key
- // and then using this class directly in Map types instead of Key.
- interface SwitchCase {
- /** Returns the {@link Key} for this switch case. */
- Key key();
-
- /** Returns the {@link Expression} that returns the provided instance for this case. */
- Expression getReturnExpression(ClassName switchingProviderClass);
-
- /**
- * Returns the {@link Expression} that returns the {@code SwitchProvider} instance for this
- * case.
- */
- Expression getProviderExpression(ClassName switchingProviderClass, int switchId);
- }
-
- /**
- * Each switch size is fixed at 100 cases each and put in its own method. This is to limit the
- * size of the methods so that we don't reach the "huge" method size limit for Android that will
- * prevent it from being AOT compiled in some versions of Android (b/77652521). This generally
- * starts to happen around 1500 cases, but we are choosing 100 to be safe.
- */
- // TODO(bcorso): Include a proguard_spec in the Dagger library to prevent inlining these methods?
- // TODO(ronshapiro): Consider making this configurable via a flag.
- private static final int MAX_CASES_PER_SWITCH = 100;
-
- private static final long MAX_CASES_PER_CLASS = MAX_CASES_PER_SWITCH * MAX_CASES_PER_SWITCH;
- private static final TypeVariableName T = TypeVariableName.get("T");
-
- /**
- * Maps a {@link Key} to an instance of a {@link SwitchingProviderBuilder}. Each group of {@code
- * MAX_CASES_PER_CLASS} keys will share the same instance.
- */
- private final Map<Key, SwitchingProviderBuilder> switchingProviderBuilders =
- new LinkedHashMap<>();
-
- private final ComponentImplementation componentImplementation;
- private final ClassName owningComponent;
- private final DaggerTypes types;
- private final UniqueNameSet switchingProviderNames = new UniqueNameSet();
-
- SwitchingProviders(ComponentImplementation componentImplementation, DaggerTypes types) {
- this.componentImplementation = checkNotNull(componentImplementation);
- this.types = checkNotNull(types);
- this.owningComponent = checkNotNull(componentImplementation).name();
- }
-
- /** Returns the {@link TypeSpec} for a {@code SwitchingProvider} based on the given builder. */
- protected abstract TypeSpec createSwitchingProviderType(TypeSpec.Builder builder);
-
- /**
- * Returns the {@link Expression} that returns the {@code SwitchProvider} instance for the case.
- */
- protected final Expression getProviderExpression(SwitchCase switchCase) {
- return switchingProviderBuilders
- .computeIfAbsent(switchCase.key(), key -> getSwitchingProviderBuilder())
- .getProviderExpression(switchCase);
- }
-
- private SwitchingProviderBuilder getSwitchingProviderBuilder() {
- if (switchingProviderBuilders.size() % MAX_CASES_PER_CLASS == 0) {
- String name = switchingProviderNames.getUniqueName("SwitchingProvider");
- SwitchingProviderBuilder switchingProviderBuilder =
- new SwitchingProviderBuilder(owningComponent.nestedClass(name));
- componentImplementation.addTypeSupplier(switchingProviderBuilder::build);
- return switchingProviderBuilder;
- }
- return getLast(switchingProviderBuilders.values());
- }
-
- // TODO(bcorso): Consider just merging this class with SwitchingProviders.
- private final class SwitchingProviderBuilder {
- // Keep the switch cases ordered by switch id. The switch Ids are assigned in pre-order
- // traversal, but the switch cases are assigned in post-order traversal of the binding graph.
- private final Map<Integer, CodeBlock> switchCases = new TreeMap<>();
- private final Map<Key, Integer> switchIds = new HashMap<>();
- private final ClassName switchingProviderType;
-
- SwitchingProviderBuilder(ClassName switchingProviderType) {
- this.switchingProviderType = checkNotNull(switchingProviderType);
- }
-
- Expression getProviderExpression(SwitchCase switchCase) {
- Key key = switchCase.key();
- if (!switchIds.containsKey(key)) {
- int switchId = switchIds.size();
- switchIds.put(key, switchId);
- switchCases.put(switchId, createSwitchCaseCodeBlock(switchCase));
- }
- return switchCase.getProviderExpression(switchingProviderType, switchIds.get(key));
- }
-
- private CodeBlock createSwitchCaseCodeBlock(SwitchCase switchCase) {
- CodeBlock instanceCodeBlock =
- switchCase.getReturnExpression(switchingProviderType).box(types).codeBlock();
-
- return CodeBlock.builder()
- // TODO(bcorso): Is there something else more useful than the key?
- .add("case $L: // $L \n", switchIds.get(switchCase.key()), switchCase.key())
- .addStatement("return ($T) $L", T, instanceCodeBlock)
- .build();
- }
-
- private TypeSpec build() {
- return createSwitchingProviderType(
- classBuilder(switchingProviderType)
- .addTypeVariable(T)
- .addSuperinterface(providerOf(T))
- .addMethods(getMethods()));
- }
-
- private ImmutableList<MethodSpec> getMethods() {
- ImmutableList<CodeBlock> switchCodeBlockPartitions = switchCodeBlockPartitions();
- if (switchCodeBlockPartitions.size() == 1) {
- // There are less than MAX_CASES_PER_SWITCH cases, so no need for extra get methods.
- return ImmutableList.of(
- methodBuilder("get")
- .addModifiers(PUBLIC)
- .addAnnotation(suppressWarnings(UNCHECKED))
- .addAnnotation(Override.class)
- .returns(T)
- .addCode(getOnlyElement(switchCodeBlockPartitions))
- .build());
- }
-
- // This is the main public "get" method that will route to private getter methods.
- MethodSpec.Builder routerMethod =
- methodBuilder("get")
- .addModifiers(PUBLIC)
- .addAnnotation(Override.class)
- .returns(T)
- .beginControlFlow("switch (id / $L)", MAX_CASES_PER_SWITCH);
-
- ImmutableList.Builder<MethodSpec> getMethods = ImmutableList.builder();
- for (int i = 0; i < switchCodeBlockPartitions.size(); i++) {
- MethodSpec method =
- methodBuilder("get" + i)
- .addModifiers(PRIVATE)
- .addAnnotation(suppressWarnings(UNCHECKED))
- .returns(T)
- .addCode(switchCodeBlockPartitions.get(i))
- .build();
- getMethods.add(method);
- routerMethod.addStatement("case $L: return $N()", i, method);
- }
-
- routerMethod.addStatement("default: throw new $T(id)", AssertionError.class).endControlFlow();
-
- return getMethods.add(routerMethod.build()).build();
- }
-
- private ImmutableList<CodeBlock> switchCodeBlockPartitions() {
- return Lists.partition(ImmutableList.copyOf(switchCases.values()), MAX_CASES_PER_SWITCH)
- .stream()
- .map(
- partitionCases ->
- CodeBlock.builder()
- .beginControlFlow("switch (id)")
- .add(CodeBlocks.concat(partitionCases))
- .addStatement("default: throw new $T(id)", AssertionError.class)
- .endControlFlow()
- .build())
- .collect(toImmutableList());
- }
- }
-}
diff --git a/java/dagger/internal/codegen/writing/TopLevel.java b/java/dagger/internal/codegen/writing/TopLevel.java
deleted file mode 100644
index ce71907..0000000
--- a/java/dagger/internal/codegen/writing/TopLevel.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.internal.codegen.writing;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/**
- * A {@link Qualifier} for bindings that are associated with the top level component implementation.
- */
-@Retention(RUNTIME)
-@Qualifier
-public @interface TopLevel {}
diff --git a/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java b/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java
deleted file mode 100644
index f07b882..0000000
--- a/java/dagger/internal/codegen/writing/UnwrappedMapKeyGenerator.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 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.writing;
-
-import dagger.MapKey;
-import dagger.internal.codegen.langmodel.DaggerElements;
-import java.util.Set;
-import javax.annotation.processing.Filer;
-import javax.inject.Inject;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.TypeElement;
-
-/**
- * Generates classes that create annotation instances for an unwrapped {@link MapKey} annotation
- * type whose nested value is an annotation. The generated class will have a private empty
- * constructor and a static method that creates each annotation type that is nested in the top-level
- * annotation type.
- *
- * <p>So for an example {@link MapKey} annotation:
- *
- * <pre>
- * {@literal @MapKey}(unwrapValue = true)
- * {@literal @interface} Foo {
- * Bar bar();
- * }
- *
- * {@literal @interface} Bar {
- * {@literal Class<?> baz();}
- * }
- * </pre>
- *
- * the generated class will look like:
- *
- * <pre>
- * public final class FooCreator {
- * private FooCreator() {}
- *
- * public static Bar createBar({@literal Class<?> baz}) { … }
- * }
- * </pre>
- */
-public final class UnwrappedMapKeyGenerator extends AnnotationCreatorGenerator {
-
- @Inject
- UnwrappedMapKeyGenerator(Filer filer, DaggerElements elements, SourceVersion sourceVersion) {
- super(filer, elements, sourceVersion);
- }
-
- @Override
- protected Set<TypeElement> annotationsToCreate(TypeElement annotationElement) {
- Set<TypeElement> nestedAnnotationElements = super.annotationsToCreate(annotationElement);
- nestedAnnotationElements.remove(annotationElement);
- return nestedAnnotationElements;
- }
-}
diff --git a/java/dagger/internal/guava/BUILD b/java/dagger/internal/guava/BUILD
deleted file mode 100644
index 0bd4dcc..0000000
--- a/java/dagger/internal/guava/BUILD
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) 2017 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:
-# Aliases from guava libraries to //third_party/java/guava.
-
-package(default_visibility = ["//:src"])
-
-alias(
- name = "annotations",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "base",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "cache",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "collect",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "graph",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "io",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "concurrent",
- actual = "@google_bazel_common//third_party/java/guava",
-)
-
-alias(
- name = "base-android",
- actual = "@maven//:com_google_guava_guava",
-)
-
-alias(
- name = "collect-android",
- actual = "@maven//:com_google_guava_guava",
-)
-
-alias(
- name = "concurrent-android",
- actual = "@maven//:com_google_guava_guava",
-)
diff --git a/java/dagger/lint/AndroidManifest.xml b/java/dagger/lint/AndroidManifest.xml
deleted file mode 100644
index f75cee1..0000000
--- a/java/dagger/lint/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.lint">
- <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/java/dagger/lint/BUILD b/java/dagger/lint/BUILD
deleted file mode 100644
index 3e0ffec..0000000
--- a/java/dagger/lint/BUILD
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Dagger Lint Rules
-
-load("//:build_defs.bzl", "POM_VERSION")
-load("//tools:maven.bzl", "gen_maven_artifact")
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-
-package(default_visibility = ["//:src"])
-
-kt_jvm_library(
- name = "lint-artifact-lib",
- srcs = glob(["*.kt"]),
- tags = ["maven_coordinates=com.google.dagger:dagger-lint:" + POM_VERSION],
- deps = [
- "@google_bazel_common//third_party/java/auto:service",
- "@maven//:com_android_tools_external_com_intellij_intellij_core",
- "@maven//:com_android_tools_external_com_intellij_kotlin_compiler",
- "@maven//:com_android_tools_external_org_jetbrains_uast",
- "@maven//:com_android_tools_lint_lint",
- "@maven//:com_android_tools_lint_lint_api",
- ],
-)
-
-# Current `kt_jvm_library` does not output source jars and gen_maven_artifact expects one.
-# See: https://github.com/bazelbuild/rules_kotlin/issues/324
-genrule(
- name = "dagger-lint-sources",
- srcs = glob(["*.kt"]),
- outs = ["liblint-artifact-lib-src.jar"],
- cmd = """
- TEMP="$$(mktemp -d)"
- for file in $(SRCS); do
- filename="$$TEMP/$${file#java/}"
- mkdir -p `dirname $$filename` && cp $$file $$filename
- done
- jar cf $@ -C $$TEMP .
- """,
-)
-
-gen_maven_artifact(
- name = "lint-artifact",
- artifact_coordinates = "com.google.dagger:dagger-lint:" + POM_VERSION,
- artifact_name = "Dagger Lint Rules",
- artifact_target = ":lint-artifact-lib",
- artifact_target_maven_deps = [
- "com.android.tools.external.com-intellij:intellij-core",
- "com.android.tools.external.com-intellij:kotlin-compiler",
- "com.android.tools.external.org-jetbrains:uast",
- "com.android.tools.lint:lint",
- "com.android.tools.lint:lint-api",
- ],
- pom_name = "lint-pom",
-)
-
-# An empty android artifact to distribute and share the Dagger lint rules for
-# the Android sub-projects.
-android_library(
- name = "lint-android-artifact-lib",
- tags = ["maven_coordinates=com.google.dagger:dagger-lint-aar:" + POM_VERSION],
-)
-
-gen_maven_artifact(
- name = "lint-android-artifact",
- artifact_coordinates = "com.google.dagger:dagger-lint-aar:" + POM_VERSION,
- artifact_name = "Dagger Lint Rules AAR Distribution",
- artifact_target = ":lint-android-artifact-lib",
- lint_deps = [":lint-artifact-lib"],
- manifest = "AndroidManifest.xml",
- packaging = "aar",
- pom_name = "lint-android-pom",
-)
diff --git a/java/dagger/lint/DaggerIssueRegistry.kt b/java/dagger/lint/DaggerIssueRegistry.kt
deleted file mode 100644
index 113e85c..0000000
--- a/java/dagger/lint/DaggerIssueRegistry.kt
+++ /dev/null
@@ -1,40 +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.lint
-
-import com.android.tools.lint.client.api.IssueRegistry
-import com.android.tools.lint.detector.api.CURRENT_API
-import com.android.tools.lint.detector.api.Issue
-import com.google.auto.service.AutoService
-
-/**
- * Dagger Lint Issues Registry.
- *
- * A META-INF/services entry is added for this class that Lint will discover and call into for
- * detecting issues.
- */
-@AutoService(IssueRegistry::class)
-@Suppress("unused", "UnstableApiUsage")
-class DaggerIssueRegistry : IssueRegistry() {
- // The minApi is set to the Api this registry was compiled with, if a user has an older Api, Lint
- // will show a warning asking users to upgrade.
- override val minApi: Int = CURRENT_API
- // The api is meant to be the current api for which this registry was compiled, but we set a
- // higher number without depending on a newer Lint to avoid Lint warning users of custom checks
- // that might not work. This value eventually has to be updated as newer Api become available.
- override val api: Int = 8
- override val issues: List<Issue> = DaggerKotlinIssueDetector.issues
-}
diff --git a/java/dagger/lint/DaggerKotlinIssueDetector.kt b/java/dagger/lint/DaggerKotlinIssueDetector.kt
deleted file mode 100644
index f3fdbd3..0000000
--- a/java/dagger/lint/DaggerKotlinIssueDetector.kt
+++ /dev/null
@@ -1,262 +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.lint
-
-import com.android.tools.lint.client.api.JavaEvaluator
-import com.android.tools.lint.client.api.UElementHandler
-import com.android.tools.lint.detector.api.Category
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Implementation
-import com.android.tools.lint.detector.api.Issue
-import com.android.tools.lint.detector.api.JavaContext
-import com.android.tools.lint.detector.api.LintFix
-import com.android.tools.lint.detector.api.Scope
-import com.android.tools.lint.detector.api.Severity
-import com.android.tools.lint.detector.api.SourceCodeScanner
-import com.android.tools.lint.detector.api.TextFormat
-import com.android.tools.lint.detector.api.isKotlin
-import dagger.lint.DaggerKotlinIssueDetector.Companion.ISSUE_FIELD_SITE_TARGET_ON_QUALIFIER_ANNOTATION
-import dagger.lint.DaggerKotlinIssueDetector.Companion.ISSUE_JVM_STATIC_PROVIDES_IN_OBJECT
-import dagger.lint.DaggerKotlinIssueDetector.Companion.ISSUE_MODULE_COMPANION_OBJECTS
-import dagger.lint.DaggerKotlinIssueDetector.Companion.ISSUE_MODULE_COMPANION_OBJECTS_NOT_IN_MODULE_PARENT
-import java.util.EnumSet
-import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.psi.KtAnnotationEntry
-import org.jetbrains.kotlin.psi.KtObjectDeclaration
-import org.jetbrains.uast.UClass
-import org.jetbrains.uast.UElement
-import org.jetbrains.uast.UField
-import org.jetbrains.uast.UMethod
-import org.jetbrains.uast.getUastParentOfType
-import org.jetbrains.uast.kotlin.KotlinUClass
-import org.jetbrains.uast.toUElement
-
-/**
- * This is a simple lint check to catch common Dagger+Kotlin usage issues.
- *
- * - [ISSUE_FIELD_SITE_TARGET_ON_QUALIFIER_ANNOTATION] covers using `field:` site targets for member
- * injections, which are redundant as of Dagger 2.25.
- * - [ISSUE_JVM_STATIC_PROVIDES_IN_OBJECT] covers using `@JvmStatic` for object
- * `@Provides`-annotated functions, which are redundant as of Dagger 2.25. @JvmStatic on companion
- * object functions are redundant as of Dagger 2.26.
- * - [ISSUE_MODULE_COMPANION_OBJECTS] covers annotating companion objects with `@Module`, as they
- * are now part of the enclosing module class's API in Dagger 2.26. This will also error if the
- * enclosing class is _not_ in a `@Module`-annotated class, as this object just should be moved to a
- * top-level object to avoid confusion.
- * - [ISSUE_MODULE_COMPANION_OBJECTS_NOT_IN_MODULE_PARENT] covers annotating companion objects with
- * `@Module` when the parent class is _not_ also annotated with `@Module`. While technically legal,
- * these should be moved up to top-level objects to avoid confusion.
- */
-@Suppress("UnstableApiUsage") // Lots of Lint APIs are marked with @Beta.
-class DaggerKotlinIssueDetector : Detector(), SourceCodeScanner {
-
- companion object {
- // We use the overloaded constructor that takes a varargs of `Scope` as the last param.
- // This is to enable on-the-fly IDE checks. We are telling lint to run on both
- // JAVA and TEST_SOURCES in the `scope` parameter but by providing the `analysisScopes`
- // params, we're indicating that this check can run on either JAVA or TEST_SOURCES and
- // doesn't require both of them together.
- // From discussion on lint-dev https://groups.google.com/d/msg/lint-dev/ULQMzW1ZlP0/1dG4Vj3-AQAJ
- // This was supposed to be fixed in AS 3.4 but still required as recently as 3.6.
- private val SCOPES = Implementation(
- DaggerKotlinIssueDetector::class.java,
- EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES),
- EnumSet.of(Scope.JAVA_FILE),
- EnumSet.of(Scope.TEST_SOURCES)
- )
-
- private val ISSUE_JVM_STATIC_PROVIDES_IN_OBJECT: Issue = Issue.create(
- id = "JvmStaticProvidesInObjectDetector",
- briefDescription = "@JvmStatic used for @Provides function in an object class",
- explanation =
- """
- It's redundant to annotate @Provides functions in object classes with @JvmStatic.
- """,
- category = Category.CORRECTNESS,
- priority = 5,
- severity = Severity.WARNING,
- implementation = SCOPES
- )
-
- private val ISSUE_FIELD_SITE_TARGET_ON_QUALIFIER_ANNOTATION: Issue = Issue.create(
- id = "FieldSiteTargetOnQualifierAnnotation",
- briefDescription = "Redundant 'field:' used for Dagger qualifier annotation.",
- explanation =
- """
- It's redundant to use 'field:' site-targets for qualifier annotations.
- """,
- category = Category.CORRECTNESS,
- priority = 5,
- severity = Severity.WARNING,
- implementation = SCOPES
- )
-
- private val ISSUE_MODULE_COMPANION_OBJECTS: Issue = Issue.create(
- id = "ModuleCompanionObjects",
- briefDescription = "Module companion objects should not be annotated with @Module.",
- explanation =
- """
- Companion objects in @Module-annotated classes are considered part of the API.
- """,
- category = Category.CORRECTNESS,
- priority = 5,
- severity = Severity.WARNING,
- implementation = SCOPES
- )
-
- private val ISSUE_MODULE_COMPANION_OBJECTS_NOT_IN_MODULE_PARENT: Issue = Issue.create(
- id = "ModuleCompanionObjectsNotInModuleParent",
- briefDescription = "Companion objects should not be annotated with @Module.",
- explanation =
- """
- Companion objects in @Module-annotated classes are considered part of the API. This
- companion object is not a companion to an @Module-annotated class though, and should be
- moved to a top-level object declaration instead otherwise Dagger will ignore companion
- object.
- """,
- category = Category.CORRECTNESS,
- priority = 5,
- severity = Severity.WARNING,
- implementation = SCOPES
- )
-
- private const val PROVIDES_ANNOTATION = "dagger.Provides"
- private const val JVM_STATIC_ANNOTATION = "kotlin.jvm.JvmStatic"
- private const val INJECT_ANNOTATION = "javax.inject.Inject"
- private const val QUALIFIER_ANNOTATION = "javax.inject.Qualifier"
- private const val MODULE_ANNOTATION = "dagger.Module"
-
- val issues: List<Issue> = listOf(
- ISSUE_JVM_STATIC_PROVIDES_IN_OBJECT,
- ISSUE_FIELD_SITE_TARGET_ON_QUALIFIER_ANNOTATION,
- ISSUE_MODULE_COMPANION_OBJECTS,
- ISSUE_MODULE_COMPANION_OBJECTS_NOT_IN_MODULE_PARENT
- )
- }
-
- override fun getApplicableUastTypes(): List<Class<out UElement>>? {
- return listOf(UMethod::class.java, UField::class.java, UClass::class.java)
- }
-
- override fun createUastHandler(context: JavaContext): UElementHandler? {
- if (!isKotlin(context.psiFile)) {
- // This is only relevant for Kotlin files.
- return null
- }
- return object : UElementHandler() {
- override fun visitField(node: UField) {
- if (!context.evaluator.isLateInit(node)) {
- return
- }
- // Can't use hasAnnotation because it doesn't capture all annotations!
- val injectAnnotation =
- node.annotations.find { it.qualifiedName == INJECT_ANNOTATION } ?: return
- // Look for qualifier annotations
- node.annotations.forEach { annotation ->
- if (annotation === injectAnnotation) {
- // Skip the inject annotation
- return@forEach
- }
- // Check if it's a FIELD site target
- val sourcePsi = annotation.sourcePsi
- if (sourcePsi is KtAnnotationEntry &&
- sourcePsi.useSiteTarget?.getAnnotationUseSiteTarget() == AnnotationUseSiteTarget.FIELD
- ) {
- // Check if this annotation is a qualifier annotation
- if (annotation.resolve()?.hasAnnotation(QUALIFIER_ANNOTATION) == true) {
- context.report(
- ISSUE_FIELD_SITE_TARGET_ON_QUALIFIER_ANNOTATION,
- context.getLocation(annotation),
- ISSUE_FIELD_SITE_TARGET_ON_QUALIFIER_ANNOTATION
- .getBriefDescription(TextFormat.TEXT),
- LintFix.create()
- .name("Remove 'field:'")
- .replace()
- .text("field:")
- .with("")
- .autoFix()
- .build()
- )
- }
- }
- }
- }
-
- override fun visitMethod(node: UMethod) {
- if (!node.isConstructor &&
- node.hasAnnotation(PROVIDES_ANNOTATION) &&
- node.hasAnnotation(JVM_STATIC_ANNOTATION)
- ) {
- val containingClass = node.containingClass?.toUElement(UClass::class.java) ?: return
- if (containingClass.isObject()) {
- val annotation = node.findAnnotation(JVM_STATIC_ANNOTATION)!!
- context.report(
- ISSUE_JVM_STATIC_PROVIDES_IN_OBJECT,
- context.getLocation(annotation),
- ISSUE_JVM_STATIC_PROVIDES_IN_OBJECT.getBriefDescription(TextFormat.TEXT),
- LintFix.create()
- .name("Remove @JvmStatic")
- .replace()
- .pattern("(@(kotlin\\.jvm\\.)?JvmStatic)")
- .with("")
- .autoFix()
- .build()
- )
- }
- }
- }
-
- override fun visitClass(node: UClass) {
- if (node.hasAnnotation(MODULE_ANNOTATION) && node.isCompanionObject(context.evaluator)) {
- val parent = node.getUastParentOfType(UClass::class.java, false)!!
- if (parent.hasAnnotation(MODULE_ANNOTATION)) {
- context.report(
- ISSUE_MODULE_COMPANION_OBJECTS,
- context.getLocation(node as UElement),
- ISSUE_MODULE_COMPANION_OBJECTS.getBriefDescription(TextFormat.TEXT),
- LintFix.create()
- .name("Remove @Module")
- .replace()
- .pattern("(@(dagger\\.)?Module)")
- .with("")
- .autoFix()
- .build()
-
- )
- } else {
- context.report(
- ISSUE_MODULE_COMPANION_OBJECTS_NOT_IN_MODULE_PARENT,
- context.getLocation(node as UElement),
- ISSUE_MODULE_COMPANION_OBJECTS_NOT_IN_MODULE_PARENT
- .getBriefDescription(TextFormat.TEXT)
- )
- }
- }
- }
- }
- }
-
- /** @return whether or not the [this] is a Kotlin `companion object` type. */
- private fun UClass.isCompanionObject(evaluator: JavaEvaluator): Boolean {
- return isObject() && evaluator.hasModifier(this, KtTokens.COMPANION_KEYWORD)
- }
-
- /** @return whether or not the [this] is a Kotlin `object` type. */
- private fun UClass.isObject(): Boolean {
- return this is KotlinUClass && ktClass is KtObjectDeclaration
- }
-}
diff --git a/java/dagger/model/BUILD b/java/dagger/model/BUILD
index 0be8fc5..5fe0db3 100644
--- a/java/dagger/model/BUILD
+++ b/java/dagger/model/BUILD
@@ -15,23 +15,14 @@
# Description:
# Dagger's core APIs exposed for plugins
-load("@rules_java//java:defs.bzl", "java_library")
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
)
-package(
- default_visibility = [
- # The dagger/spi should be the only direct dependent on this target.
- # If you need to depend on :model, depend on dagger/spi instead so
- # that pom files correctly pick up the spi maven dependency.
- # TODO(bcorso): Consider if :model should have its own maven coordinates.
- "//java/dagger/spi:__pkg__",
- ],
-)
-
INTERNAL_PROXIES = ["BindingGraphProxies.java"]
filegroup(
@@ -48,16 +39,14 @@
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//java/dagger:core",
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
+ "//java/dagger/internal/codegen:jdk-and-guava-extras",
"//java/dagger/producers",
+ "@google_bazel_common//third_party/java/auto:common",
"@google_bazel_common//third_party/java/auto:value",
"@google_bazel_common//third_party/java/error_prone:annotations",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
"@google_bazel_common//third_party/java/jsr330_inject",
- "@maven//:com_google_auto_auto_common",
],
)
@@ -65,11 +54,8 @@
name = "internal-proxies",
srcs = INTERNAL_PROXIES,
tags = ["maven:merged"],
- visibility = ["//:src"],
deps = [
":model",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:graph",
- "@google_bazel_common//third_party/java/auto:value",
+ "@google_bazel_common//third_party/java/guava",
],
)
diff --git a/java/dagger/model/BindingGraph.java b/java/dagger/model/BindingGraph.java
index 1ccba43..748bf38 100644
--- a/java/dagger/model/BindingGraph.java
+++ b/java/dagger/model/BindingGraph.java
@@ -20,10 +20,12 @@
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 static dagger.internal.codegen.DaggerStreams.instancesOf;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSetMultimap;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.graph.EndpointPair;
@@ -46,8 +48,8 @@
* <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})
+ * dagger.producers.ProductionSubcomponent} (only when {@code
+ * -Adagger.experimentalAheadOfTimeSubcomponents=enabled} is passed to the compiler)
* <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()} ()}
@@ -86,12 +88,20 @@
*
* <p><b>Note that this API is experimental and will change.</b>
*/
+@AutoValue
public abstract class BindingGraph {
+
+ static BindingGraph create(Network<Node, Edge> network, boolean isFullBindingGraph) {
+ return new AutoValue_BindingGraph(ImmutableNetwork.copyOf(network), isFullBindingGraph);
+ }
+
+ BindingGraph() {}
+
/** Returns the graph in its {@link Network} representation. */
public abstract ImmutableNetwork<Node, Edge> network();
@Override
- public String toString() {
+ public final String toString() {
return network().toString();
}
@@ -105,7 +115,7 @@
* full binding graphs for components and subcomponents as well as modules.
*/
@Deprecated
- public boolean isModuleBindingGraph() {
+ public final boolean isModuleBindingGraph() {
return !rootComponentNode().isRealComponent();
}
@@ -121,54 +131,54 @@
/**
* 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.
+ * ahead-of-time-subcomponents mode.
*
* @deprecated use {@link ComponentNode#isSubcomponent() rootComponentNode().isSubcomponent()}
* instead
*/
@Deprecated
- public boolean isPartialBindingGraph() {
+ public final boolean isPartialBindingGraph() {
return rootComponentNode().isSubcomponent();
}
/** Returns the bindings. */
- public ImmutableSet<Binding> bindings() {
+ public final ImmutableSet<Binding> bindings() {
return nodes(Binding.class);
}
/** Returns the bindings for a key. */
- public ImmutableSet<Binding> bindings(Key key) {
+ public final 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() {
+ public final ImmutableSet<MissingBinding> missingBindings() {
return nodes(MissingBinding.class);
}
/** Returns the component nodes. */
- public ImmutableSet<ComponentNode> componentNodes() {
+ public final ImmutableSet<ComponentNode> componentNodes() {
return nodes(ComponentNode.class);
}
/** Returns the component node for a component. */
- public Optional<ComponentNode> componentNode(ComponentPath component) {
+ public final 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(TypeElement component) {
+ public final ImmutableSet<ComponentNode> componentNodes(TypeElement component) {
return componentNodes().stream()
.filter(node -> node.componentPath().currentComponent().equals(component))
.collect(toImmutableSet());
}
/** Returns the component node for the root component. */
- public ComponentNode rootComponentNode() {
+ public final ComponentNode rootComponentNode() {
return componentNodes().stream()
.filter(node -> node.componentPath().atRoot())
.findFirst()
@@ -176,7 +186,7 @@
}
/** Returns the dependency edges. */
- public ImmutableSet<DependencyEdge> dependencyEdges() {
+ public final ImmutableSet<DependencyEdge> dependencyEdges() {
return dependencyEdgeStream().collect(toImmutableSet());
}
@@ -187,14 +197,14 @@
* 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(
+ public final 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) {
+ public final ImmutableSet<DependencyEdge> dependencyEdges(DependencyRequest dependencyRequest) {
return dependencyEdgeStream()
.filter(edge -> edge.dependencyRequest().equals(dependencyRequest))
.collect(toImmutableSet());
@@ -204,7 +214,7 @@
* 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) {
+ public final ImmutableSet<DependencyEdge> entryPointEdges(ComponentPath component) {
return dependencyEdgeStream(componentNode(component).get()).collect(toImmutableSet());
}
@@ -216,12 +226,12 @@
* 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() {
+ public final ImmutableSet<DependencyEdge> entryPointEdges() {
return entryPointEdgeStream().collect(toImmutableSet());
}
/** Returns the binding or missing binding nodes that directly satisfy entry points. */
- public ImmutableSet<MaybeBinding> entryPointBindings() {
+ public final ImmutableSet<MaybeBinding> entryPointBindings() {
return entryPointEdgeStream()
.map(edge -> (MaybeBinding) network().incidentNodes(edge).target())
.collect(toImmutableSet());
@@ -231,7 +241,7 @@
* Returns the edges for entry points that transitively depend on a binding or missing binding for
* a key.
*/
- public ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(
+ public final ImmutableSet<DependencyEdge> entryPointEdgesDependingOnBinding(
MaybeBinding binding) {
ImmutableNetwork<Node, DependencyEdge> dependencyGraph = dependencyGraph();
Network<Node, DependencyEdge> subgraphDependingOnBinding =
@@ -241,19 +251,19 @@
}
/** Returns the bindings that directly request a given binding as a dependency. */
- public ImmutableSet<Binding> requestingBindings(MaybeBinding binding) {
+ public final 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
+ * Returns the bindings that a given binding directly request as a dependency. Does not include
* any {@link MissingBinding}s.
*
* @see #requestedMaybeMissingBindings(Binding)
*/
- public ImmutableSet<Binding> requestedBindings(Binding binding) {
+ public final ImmutableSet<Binding> requestedBindings(Binding binding) {
return network().successors(binding).stream()
.flatMap(instancesOf(Binding.class))
.collect(toImmutableSet());
@@ -265,7 +275,7 @@
*
* @see #requestedBindings(Binding)
*/
- public ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
+ public final ImmutableSet<MaybeBinding> requestedMaybeMissingBindings(Binding binding) {
return network().successors(binding).stream()
.flatMap(instancesOf(MaybeBinding.class))
.collect(toImmutableSet());
@@ -297,7 +307,8 @@
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() {
+ @Memoized
+ ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
return network().nodes().stream()
.collect(
toImmutableSetMultimap(
@@ -391,26 +402,37 @@
}
/** A node in the binding graph that represents a missing binding for a key in a component. */
+ @AutoValue
public abstract static class MissingBinding implements MaybeBinding {
+ static MissingBinding create(ComponentPath component, Key key) {
+ return new AutoValue_BindingGraph_MissingBinding(component, key);
+ }
+
/** 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() {
+ public final Optional<Binding> binding() {
return Optional.empty();
}
@Override
- public String toString() {
+ public final String toString() {
return String.format("missing binding for %s in %s", key(), componentPath());
}
+
+ @Memoized
+ @Override
+ public abstract int hashCode();
+
+ @Override
+ public abstract boolean equals(Object o);
}
/**
diff --git a/java/dagger/model/BindingGraphProxies.java b/java/dagger/model/BindingGraphProxies.java
index 85d4df8..c450475 100644
--- a/java/dagger/model/BindingGraphProxies.java
+++ b/java/dagger/model/BindingGraphProxies.java
@@ -16,10 +16,6 @@
package dagger.model;
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.collect.ImmutableSetMultimap;
-import com.google.common.graph.ImmutableNetwork;
import com.google.common.graph.Network;
import dagger.model.BindingGraph.Edge;
import dagger.model.BindingGraph.MissingBinding;
@@ -31,35 +27,14 @@
* API.</em>
*/
public final class BindingGraphProxies {
-
- @AutoValue
- abstract static class BindingGraphImpl extends BindingGraph {
- @Override
- @Memoized
- public ImmutableSetMultimap<Class<? extends Node>, ? extends Node> nodesByClass() {
- return super.nodesByClass();
- }
- }
-
- @AutoValue
- abstract static class MissingBindingImpl extends MissingBinding {
- @Memoized
- @Override
- public abstract int hashCode();
-
- @Override
- public abstract boolean equals(Object o);
- }
-
/** Creates a new {@link BindingGraph}. */
public static BindingGraph bindingGraph(Network<Node, Edge> network, boolean isFullBindingGraph) {
- return new AutoValue_BindingGraphProxies_BindingGraphImpl(
- ImmutableNetwork.copyOf(network), isFullBindingGraph);
+ return BindingGraph.create(network, isFullBindingGraph);
}
/** Creates a new {@link MissingBinding}. */
public static MissingBinding missingBindingNode(ComponentPath component, Key key) {
- return new AutoValue_BindingGraphProxies_MissingBindingImpl(component, key);
+ return MissingBinding.create(component, key);
}
private BindingGraphProxies() {}
diff --git a/java/dagger/model/BindingKind.java b/java/dagger/model/BindingKind.java
index 9bef8fc..20d7b42 100644
--- a/java/dagger/model/BindingKind.java
+++ b/java/dagger/model/BindingKind.java
@@ -25,15 +25,6 @@
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.
*/
diff --git a/java/dagger/model/testing/BUILD b/java/dagger/model/testing/BUILD
index 9c9f44a..a9d5f19 100644
--- a/java/dagger/model/testing/BUILD
+++ b/java/dagger/model/testing/BUILD
@@ -15,27 +15,25 @@
# Description:
# Test utilities for the Dagger model
-load("@rules_java//java:defs.bzl", "java_library")
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
)
-package(default_visibility = ["//:src"])
-
java_library(
name = "testing",
testonly = 1,
srcs = glob(["*.java"]),
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
- "//java/dagger/internal/codegen/extension",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/spi",
+ "//java/dagger/internal/codegen:jdk-and-guava-extras",
+ "//java/dagger/model",
"@google_bazel_common//third_party/java/auto:value",
"@google_bazel_common//third_party/java/checker_framework_annotations",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/truth",
],
)
diff --git a/java/dagger/model/testing/BindingGraphSubject.java b/java/dagger/model/testing/BindingGraphSubject.java
index 2f032cd..dc17c1d 100644
--- a/java/dagger/model/testing/BindingGraphSubject.java
+++ b/java/dagger/model/testing/BindingGraphSubject.java
@@ -18,7 +18,7 @@
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertAbout;
-import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
+import static dagger.internal.codegen.DaggerStreams.toImmutableSet;
import com.google.common.collect.ImmutableSet;
import com.google.common.truth.FailureMetadata;
@@ -29,7 +29,7 @@
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
/** A Truth subject for making assertions on a {@link BindingGraph}. */
-public final class BindingGraphSubject extends Subject {
+public final class BindingGraphSubject extends Subject<BindingGraphSubject, BindingGraph> {
/** Starts a fluent assertion about a {@link BindingGraph}. */
public static BindingGraphSubject assertThat(BindingGraph bindingGraph) {
@@ -107,7 +107,7 @@
}
/** A Truth subject for a {@link Binding}. */
- public final class BindingSubject extends Subject {
+ public final class BindingSubject extends Subject<BindingSubject, Binding> {
private final Binding actual;
diff --git a/java/dagger/producers/BUILD b/java/dagger/producers/BUILD
index 41762e6..ad065a1 100644
--- a/java/dagger/producers/BUILD
+++ b/java/dagger/producers/BUILD
@@ -15,17 +15,15 @@
# Description:
# An asynchronous dependency injection system that extends JSR-330.
-load("@rules_java//java:defs.bzl", "java_library")
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
- "POM_VERSION",
"SOURCE_7_TARGET_7",
)
-load("//tools:maven.bzl", "gen_maven_artifact")
-
-package(default_visibility = ["//:src"])
+load("//tools:maven.bzl", "pom_file", "POM_VERSION")
# Work around b/70476182 which prevents Kythe from connecting :producers to the .java files it
# contains.
@@ -42,38 +40,35 @@
javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
tags = ["maven_coordinates=com.google.dagger:dagger-producers:" + POM_VERSION],
exports = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:concurrent",
+ # TODO(dpb): Don't export any of Guava.
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr330_inject",
],
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
"@google_bazel_common//third_party/java/checker_framework_annotations",
"@google_bazel_common//third_party/java/error_prone:annotations",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr330_inject",
],
)
-gen_maven_artifact(
- name = "artifact",
- artifact_coordinates = "com.google.dagger:dagger-producers:" + POM_VERSION,
+pom_file(
+ name = "pom",
+ artifact_id = "dagger-producers",
artifact_name = "Dagger Producers",
- artifact_target = ":producers",
- artifact_target_maven_deps = [
- "com.google.dagger:dagger",
- "com.google.guava:failureaccess",
- "com.google.guava:guava", # TODO(bcorso): Remove guava dependency and ban it?
- "javax.inject:javax.inject",
- "org.checkerframework:checker-compat-qual",
- ],
- javadoc_exclude_packages = [
+ targets = [":producers"],
+)
+
+load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
+
+javadoc_library(
+ name = "producers-javadoc",
+ srcs = SRCS,
+ exclude_packages = [
"dagger.producers.internal",
"dagger.producers.monitoring.internal",
],
- javadoc_root_packages = ["dagger.producers"],
- javadoc_srcs = SRCS,
- # TODO(bcorso): Look more into why auto/common shading isn't needed here.
+ root_packages = ["dagger.producers"],
+ deps = [":producers"],
)
diff --git a/java/dagger/producers/internal/MissingBindingProducer.java b/java/dagger/producers/internal/MissingBindingProducer.java
new file mode 100644
index 0000000..5721569
--- /dev/null
+++ b/java/dagger/producers/internal/MissingBindingProducer.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.producers.internal;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import dagger.producers.Producer;
+
+/**
+ * A {@link Producer} that always throws on calls to {@link Producer#get()}. This is necessary in
+ * ahead-of-time subcomponents mode, where modifiable binding methods need to return a {@code
+ * Producer<T>} to a framework instance initialization that is pruned and no longer in the binding
+ * graph, but was present in a superclass implementation. This class fulfills that requirement but
+ * is still practically unusable.
+ */
+public final class MissingBindingProducer<T> extends AbstractProducer<T> {
+ private static final MissingBindingProducer<Object> INSTANCE = new MissingBindingProducer<>();
+
+ private MissingBindingProducer() {}
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // safe covariant cast
+ public static <T> Producer<T> create() {
+ return (Producer) INSTANCE;
+ }
+
+ @Override
+ protected ListenableFuture<T> compute() {
+ throw new AssertionError(
+ "This binding is not part of the final binding graph. The key was requested by a binding "
+ + "that was believed to possibly be part of the graph, but is no longer requested. "
+ + "If this exception is thrown, it is the result of a Dagger bug.");
+ }
+}
diff --git a/java/dagger/producers/monitoring/TimingProducerMonitor.java b/java/dagger/producers/monitoring/TimingProducerMonitor.java
index ebb90cf..c63e108 100644
--- a/java/dagger/producers/monitoring/TimingProducerMonitor.java
+++ b/java/dagger/producers/monitoring/TimingProducerMonitor.java
@@ -25,7 +25,6 @@
* A monitor that measures the timing of the execution of a producer method, and logs those timings
* with the given recorder.
*/
-@SuppressWarnings("GoodTime") // should use java.time.Duration
final class TimingProducerMonitor extends ProducerMonitor {
private final ProducerTimingRecorder recorder;
private final Stopwatch stopwatch;
diff --git a/java/dagger/producers/monitoring/TimingRecorders.java b/java/dagger/producers/monitoring/TimingRecorders.java
index be89319..5fbe3e3 100644
--- a/java/dagger/producers/monitoring/TimingRecorders.java
+++ b/java/dagger/producers/monitoring/TimingRecorders.java
@@ -30,7 +30,6 @@
*/
// TODO(beder): Reduce the visibility of this class to package-private.
@Beta
-@SuppressWarnings("GoodTime") // Should be using java.time.Instant/Duration as opposed to nanos
public final class TimingRecorders {
private static final Logger logger = Logger.getLogger(TimingRecorders.class.getName());
diff --git a/java/dagger/spi/BUILD b/java/dagger/spi/BUILD
index cbec465..9c04582 100644
--- a/java/dagger/spi/BUILD
+++ b/java/dagger/spi/BUILD
@@ -15,67 +15,42 @@
# Description:
# The Service Provider Interface for Dagger's binding graph model
-load("@rules_java//java:defs.bzl", "java_library")
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
"DOCLINT_REFERENCES",
- "POM_VERSION",
)
-load("//tools:maven.bzl", "gen_maven_artifact")
-
-package(default_visibility = ["//:src"])
filegroup(
name = "spi-srcs",
- srcs = glob(["*.java"]) + [
- "//java/dagger/model:model-srcs",
- ],
+ srcs = glob(["*.java"]),
)
+load("//tools:maven.bzl", "POM_VERSION", "pom_file")
+
java_library(
name = "spi",
- srcs = glob(["*.java"]),
+ srcs = [":spi-srcs"],
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
tags = ["maven_coordinates=com.google.dagger:dagger-spi:" + POM_VERSION],
- exports = [
- "//java/dagger/model",
- ],
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"//java/dagger/model",
"@google_bazel_common//third_party/java/auto:value",
"@google_bazel_common//third_party/java/error_prone:annotations",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr330_inject",
],
)
-gen_maven_artifact(
- name = "artifact",
- artifact_coordinates = "com.google.dagger:dagger-spi:" + POM_VERSION,
+pom_file(
+ name = "pom",
+ artifact_id = "dagger-spi",
artifact_name = "Dagger SPI",
- artifact_target = ":spi",
- artifact_target_libs = [
- "//java/dagger/internal/codegen/extension",
+ targets = [
"//java/dagger/model",
+ ":spi",
],
- artifact_target_maven_deps = [
- "com.google.auto:auto-common",
- "com.google.code.findbugs:jsr305",
- "com.google.dagger:dagger-producers",
- "com.google.dagger:dagger",
- "com.google.guava:failureaccess",
- "com.google.guava:guava",
- "com.squareup:javapoet",
- "javax.inject:javax.inject",
- ],
- javadoc_root_packages = [
- "dagger.model",
- "dagger.spi",
- ],
- javadoc_srcs = [":spi-srcs"],
- shaded_deps = ["@maven//:com_google_auto_auto_common"],
- shaded_rules = ["rule com.google.auto.common.** dagger.spi.shaded.auto.common.@1"],
)
diff --git a/java/dagger/testing/compile/BUILD b/java/dagger/testing/compile/BUILD
deleted file mode 100644
index 20e6a3d..0000000
--- a/java/dagger/testing/compile/BUILD
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Helpers class for java compiler tests.
-
-load("@rules_java//java:defs.bzl", "java_library")
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "compile",
- testonly = 1,
- srcs = ["CompilerTests.java"],
- deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:io",
- "@google_bazel_common//third_party/java/compile_testing",
- ],
-)
diff --git a/java/dagger/testing/compile/CompilerTests.java b/java/dagger/testing/compile/CompilerTests.java
deleted file mode 100644
index 6750d0c..0000000
--- a/java/dagger/testing/compile/CompilerTests.java
+++ /dev/null
@@ -1,79 +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.testing.compile;
-
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static com.google.common.collect.MoreCollectors.onlyElement;
-import static com.google.common.collect.Streams.stream;
-import static com.google.testing.compile.Compiler.javac;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Files;
-import com.google.testing.compile.Compiler;
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-/**
- * A helper class for working with java compiler tests.
- */
-public final class CompilerTests {
- private CompilerTests() {}
-
- /** Returns the {@plainlink File jar file} containing the compiler deps. */
- public static File compilerDepsJar() {
- try {
- return stream(Files.fileTraverser().breadthFirst(getRunfilesDir()))
- .filter(file -> file.getName().endsWith("_compiler_deps_deploy.jar"))
- .collect(onlyElement());
- } catch (NoSuchElementException e) {
- throw new IllegalStateException(
- "No compiler deps jar found. Are you using the Dagger compiler_test macro?", e);
- }
- }
-
- /** Returns a {@link Compiler} with the compiler deps jar added to the class path. */
- public static Compiler compiler() {
- return javac().withClasspath(ImmutableList.of(compilerDepsJar()));
- }
-
- private static File getRunfilesDir() {
- return getRunfilesPath().toFile();
- }
-
- private static Path getRunfilesPath() {
- Path propPath = getRunfilesPath(System.getProperties());
- if (propPath != null) {
- return propPath;
- }
-
- Path envPath = getRunfilesPath(System.getenv());
- if (envPath != null) {
- return envPath;
- }
-
- Path cwd = Paths.get("").toAbsolutePath();
- return cwd.getParent();
- }
-
- private static Path getRunfilesPath(Map<?, ?> map) {
- String runfilesPath = (String) map.get("TEST_SRCDIR");
- return isNullOrEmpty(runfilesPath) ? null : Paths.get(runfilesPath);
- }
-}
diff --git a/java/dagger/testing/compile/macros.bzl b/java/dagger/testing/compile/macros.bzl
deleted file mode 100644
index 9543e0e..0000000
--- a/java/dagger/testing/compile/macros.bzl
+++ /dev/null
@@ -1,89 +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.
-
-"""Macros for building compiler tests."""
-
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-
-def compiler_test(name, size = "large", compiler_deps = None, **kwargs):
- """Generates a java_test that tests java compilation with the given compiler deps.
-
- This macro separates the compiler dependencies from the test dependencies to avoid
- 1-version violations. For example, this often happens when the java_test uses java
- dependencies but the compiler test expects the android version of the dependencies.
-
- Args:
- name: The name of the java_test.
- size: The size of the test (default "large" since this test does disk I/O).
- compiler_deps: The deps needed during compilation.
- **kwargs: The parameters to pass to the generated java_test.
-
- Returns:
- None
- """
-
- # This JAR is loaded at runtime and contains the dependencies used by the compiler during tests.
- # We separate these dependencies from the java_test dependencies to avoid 1 version violations.
- native.java_binary(
- name = name + "_compiler_deps",
- testonly = 1,
- tags = ["notap"],
- visibility = ["//visibility:private"],
- main_class = "Object.class",
- runtime_deps = compiler_deps,
- )
-
- # Add the compiler deps jar, generated above, to the test's data.
- kwargs["data"] = kwargs.get("data", []) + [name + "_compiler_deps_deploy.jar"]
-
- # Need to check for srcs since for Kotlin tests we use a runtime dep on the kt_jvm_library
- # target. We don't need to worry about adding a compile testing dep since kt_compiler_test
- # adds that in the kt_jvm_library. Adding this dep automatically is merely a convenience
- # for cases with srcs anyway.
- if kwargs.get("srcs", None):
- # Add a dep to allow usage of CompilerTests.
- kwargs["deps"] = kwargs.get("deps", []) + ["//java/dagger/testing/compile"]
-
- native.java_test(name = name, size = size, **kwargs)
-
-def kt_compiler_test(name, srcs = [], deps = [], **kwargs):
- """Generates a java_test that tests java compilation with the given compiler deps.
-
- This macro works the same as the above compiler_test, but for Kotlin sources.
-
- Args:
- name: The name of the java_test.
- srcs: Source files for the test (typically should include Kotlin sources). If no
- sources are needed, just use compiler_test with runtime_deps.
- deps: Deps for compiling the files in srcs.
- **kwargs: The parameters to pass to compiler_test
-
- Returns:
- None
- """
- kt_jvm_library(
- name = name + "_ktlib",
- testonly = 1,
- srcs = srcs,
- deps = deps + ["//java/dagger/testing/compile"],
- visibility = ["//visibility:private"],
- )
-
- compiler_test(
- name = name,
- runtime_deps = [
- ":" + name + "_ktlib",
- ],
- **kwargs
- )
diff --git a/javatests/artifacts/BUILD b/javatests/artifacts/BUILD
deleted file mode 100644
index 9b282de..0000000
--- a/javatests/artifacts/BUILD
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# This package contains gradle tests of the LOCAL-SNAPSHOT artifacts.
-
-package(default_visibility = ["//:src"])
diff --git a/javatests/artifacts/dagger-android/simple/app/build.gradle b/javatests/artifacts/dagger-android/simple/app/build.gradle
deleted file mode 100644
index 20a3734..0000000
--- a/javatests/artifacts/dagger-android/simple/app/build.gradle
+++ /dev/null
@@ -1,75 +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.
- */
-
-apply plugin: 'com.android.application'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.android.simple"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
- sourceSets {
- String sharedTestDir = 'src/sharedTest/java'
- test {
- java.srcDirs += sharedTestDir
- }
- androidTest {
- java.srcDirs += sharedTestDir
- }
- }
-}
-
-dependencies {
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- implementation 'com.google.dagger:dagger-android-support:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
-
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'androidx.test.espresso:espresso-core:3.3.0'
- testImplementation 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
- testAnnotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
-
- androidTestImplementation 'com.google.truth:truth:1.0.1'
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
- androidTestImplementation 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
- androidTestAnnotationProcessor 'com.google.dagger:dagger-android-processor:LOCAL-SNAPSHOT'
-
- // To help us catch usages of Guava APIs for Java 8 in the '-jre' variant.
- annotationProcessor'com.google.guava:guava:28.1-android'
- testAnnotationProcessor'com.google.guava:guava:28.1-android'
- androidTestAnnotationProcessor'com.google.guava:guava:28.1-android'
-}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/AndroidManifest.xml b/javatests/artifacts/dagger-android/simple/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 0f765b5..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.android.simple">
-
- <application
- android:name=".SimpleApplication"
- android:label="@string/appName"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".SimpleActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/Model.java b/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/Model.java
deleted file mode 100644
index d74a501..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/Model.java
+++ /dev/null
@@ -1,29 +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.android.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface Model {}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/ModelModule.java b/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/ModelModule.java
deleted file mode 100644
index 5e04071..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/ModelModule.java
+++ /dev/null
@@ -1,31 +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.android.simple;
-
-import static android.os.Build.MODEL;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class ModelModule {
- @Provides
- @Model
- static String provideModel() {
- return MODEL;
- }
-}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/SimpleActivity.java b/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/SimpleActivity.java
deleted file mode 100644
index 39a88e3..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/SimpleActivity.java
+++ /dev/null
@@ -1,73 +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.android.simple;
-
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.TextView;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Subcomponent;
-import dagger.android.AndroidInjector;
-import dagger.android.support.DaggerAppCompatActivity;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-import javax.inject.Inject;
-
-/**
- * The main activity of the application.
- *
- * <p>It can be injected with any binding from both {@link SimpleActivityComponent} and {@link
- * SimpleApplication.SimpleComponent}.
- */
-public class SimpleActivity extends DaggerAppCompatActivity {
- @Subcomponent
- interface SimpleActivityComponent extends AndroidInjector<SimpleActivity> {
-
- @Subcomponent.Factory
- interface Factory extends AndroidInjector.Factory<SimpleActivity> {}
- }
-
- @Module(
- subcomponents = SimpleActivityComponent.class,
- includes = UserNameModule.class
- )
- abstract static class InjectorModule {
-
- @Binds
- @IntoMap
- @ClassKey(SimpleActivity.class)
- abstract AndroidInjector.Factory<?> bind(SimpleActivityComponent.Factory factory);
- }
-
- private static final String TAG = SimpleActivity.class.getSimpleName();
-
- @Inject @UserName String userName;
- @Inject @Model String model;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.i(TAG, "Injected with userName and model: " + userName + ", " + model);
-
- setContentView(R.layout.activity_main);
-
- TextView greeting = (TextView) findViewById(R.id.greeting);
- String text = getResources().getString(R.string.welcome, userName, model);
- greeting.setText(text);
- }
-}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/SimpleApplication.java b/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/SimpleApplication.java
deleted file mode 100644
index dcc7bcb..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/SimpleApplication.java
+++ /dev/null
@@ -1,59 +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.android.simple;
-
-import android.util.Log;
-import dagger.Component;
-import dagger.android.AndroidInjectionModule;
-import dagger.android.AndroidInjector;
-import dagger.android.DaggerApplication;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A simple, skeletal application that demonstrates a dependency-injected application using the
- * utilities in {@code dagger.android}.
- */
-public class SimpleApplication extends DaggerApplication {
- private static final String TAG = SimpleApplication.class.getSimpleName();
-
- @Singleton
- @Component(
- modules = {
- AndroidInjectionModule.class,
- SimpleActivity.InjectorModule.class,
- ModelModule.class
- }
- )
- interface SimpleComponent extends AndroidInjector<SimpleApplication> {
- @Component.Factory
- interface Factory extends AndroidInjector.Factory<SimpleApplication> {}
- }
-
- @Inject @Model String model;
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.i(TAG, "Injected with model: " + model);
- }
-
- @Override
- protected AndroidInjector<SimpleApplication> applicationInjector() {
- return DaggerSimpleApplication_SimpleComponent.factory().create(this);
- }
-}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/UserName.java b/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/UserName.java
deleted file mode 100644
index 2f861b1..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/UserName.java
+++ /dev/null
@@ -1,29 +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.android.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface UserName {}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/UserNameModule.java b/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/UserNameModule.java
deleted file mode 100644
index d6bc0ac..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/java/dagger/android/simple/UserNameModule.java
+++ /dev/null
@@ -1,31 +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.android.simple;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-final class UserNameModule {
- @UserName
- @Provides
- static String provideUserName() {
- return "ProdUser";
- }
-
- private UserNameModule() {}
-}
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/res/layout/activity_main.xml b/javatests/artifacts/dagger-android/simple/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 3cecc4c..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-</RelativeLayout>
diff --git a/javatests/artifacts/dagger-android/simple/app/src/main/res/values/strings.xml b/javatests/artifacts/dagger-android/simple/app/src/main/res/values/strings.xml
deleted file mode 100644
index 579f478..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<resources>
- <!--The app name [CHAR_LIMIT=25]-->
- <string name="appName">Simple Dagger Android</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s! You are on build %2$s.</string>
-</resources>
diff --git a/javatests/artifacts/dagger-android/simple/app/src/sharedTest/java/dagger/android/simple/SimpleActivityTest.java b/javatests/artifacts/dagger-android/simple/app/src/sharedTest/java/dagger/android/simple/SimpleActivityTest.java
deleted file mode 100644
index 024da5c..0000000
--- a/javatests/artifacts/dagger-android/simple/app/src/sharedTest/java/dagger/android/simple/SimpleActivityTest.java
+++ /dev/null
@@ -1,57 +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.android.simple;
-
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.Build;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-/** A simple test using dagger-android that can be run with instrumentation or Robolectric tests. */
-@RunWith(AndroidJUnit4.class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = Build.VERSION_CODES.P)
-public final class SimpleActivityTest {
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(
- activity -> {
- onView(withId(R.id.greeting))
- .check(matches(withText("Hello, ProdUser! You are on build robolectric.")));
- });
- }
- }
-
- @Test
- public void verifyApplicationInstance() {
- assertThat((Context) ApplicationProvider.getApplicationContext())
- .isInstanceOf(SimpleApplication.class);
- }
-}
diff --git a/javatests/artifacts/dagger-android/simple/build.gradle b/javatests/artifacts/dagger-android/simple/build.gradle
deleted file mode 100644
index 8c179e5..0000000
--- a/javatests/artifacts/dagger-android/simple/build.gradle
+++ /dev/null
@@ -1,38 +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.
- */
-
-buildscript {
- ext {
- agp_version = System.getenv('AGP_VERSION') ?: "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
-
diff --git a/javatests/artifacts/dagger-android/simple/gradle.properties b/javatests/artifacts/dagger-android/simple/gradle.properties
deleted file mode 100644
index 2d8d1e4..0000000
--- a/javatests/artifacts/dagger-android/simple/gradle.properties
+++ /dev/null
@@ -1 +0,0 @@
-android.useAndroidX=true
\ No newline at end of file
diff --git a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/javatests/artifacts/dagger-android/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/dagger-android/simple/gradlew b/javatests/artifacts/dagger-android/simple/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/javatests/artifacts/dagger-android/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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-android/simple/settings.gradle b/javatests/artifacts/dagger-android/simple/settings.gradle
deleted file mode 100644
index c5a07bc..0000000
--- a/javatests/artifacts/dagger-android/simple/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-include ':app'
-rootProject.name='Simple Dagger Android'
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/simple/build.gradle b/javatests/artifacts/dagger/simple/build.gradle
deleted file mode 100644
index 97c966e..0000000
--- a/javatests/artifacts/dagger/simple/build.gradle
+++ /dev/null
@@ -1,37 +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.
- */
-
-plugins {
- id 'java'
- id 'application'
-}
-
-repositories {
- mavenCentral()
- mavenLocal()
-}
-
-java {
- // Make sure the generated source is compatible with Java 7.
- sourceCompatibility = JavaVersion.VERSION_1_7
-}
-
-dependencies {
- implementation 'com.google.dagger:dagger:LOCAL-SNAPSHOT'
- annotationProcessor 'com.google.dagger:dagger-compiler:LOCAL-SNAPSHOT'
-}
-
-mainClassName = 'dagger.simple.SimpleApplication'
\ No newline at end of file
diff --git a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/javatests/artifacts/dagger/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/dagger/simple/gradlew b/javatests/artifacts/dagger/simple/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/javatests/artifacts/dagger/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/simple/src/main/java/dagger/simple/AssistedInjects.java b/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/AssistedInjects.java
deleted file mode 100644
index eb4946f..0000000
--- a/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/AssistedInjects.java
+++ /dev/null
@@ -1,66 +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.simple;
-
-import dagger.Component;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import javax.inject.Inject;
-
-// 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 {
- @Component
- interface MyComponent {
- FooFactory fooFactory();
-
- ParameterizedFooFactory<Bar, String> parameterizedFooFactory();
- }
-
- static final class Bar {
- @Inject
- Bar() {}
- }
-
- static class Foo {
- @AssistedInject
- Foo(Bar bar, @Assisted String str) {}
- }
-
- @AssistedFactory
- interface FooFactory {
- Foo create(String str);
- }
-
- static class ParameterizedFoo<T1, T2> {
- @AssistedInject
- ParameterizedFoo(T1 t1, @Assisted T2 t2) {}
- }
-
- @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/simple/src/main/java/dagger/simple/SimpleApplication.java b/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/SimpleApplication.java
deleted file mode 100644
index f136101..0000000
--- a/javatests/artifacts/dagger/simple/src/main/java/dagger/simple/SimpleApplication.java
+++ /dev/null
@@ -1,48 +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.simple;
-
-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();
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle b/javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle
deleted file mode 100644
index 43ccd1d..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/build.gradle
+++ /dev/null
@@ -1,69 +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.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.gradleConfigCache"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "dagger.hilt.android.gradleConfigCache.TestRunner"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
-}
-
-hilt {
- enableTransformForLocalTests = true
-}
-
-dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'androidx.activity:activity-ktx:1.1.0'
- implementation 'androidx.multidex:multidex:2.0.0'
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'junit:junit:4.13'
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptTest 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'com.google.dagger:hilt-android-testing:LOCAL-SNAPSHOT'
- kaptAndroidTest 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt
deleted file mode 100644
index 9099db4..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/EmulatorTest.kt
+++ /dev/null
@@ -1,43 +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.gradleConfigCache
-
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Assert.assertNotNull
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class EmulatorTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun testFooInjected() {
- ActivityScenario.launch(MainActivity::class.java).use {
- it.onActivity { activity ->
- assertNotNull(activity.foo)
- }
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt
deleted file mode 100644
index 9fce7cd..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/androidTest/java/dagger/hilt/android/gradleConfigCache/TestRunner.kt
+++ /dev/null
@@ -1,28 +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.gradleConfigCache
-
-import android.app.Application
-import android.content.Context
-import androidx.test.runner.AndroidJUnitRunner
-import dagger.hilt.android.testing.HiltTestApplication
-
-class TestRunner : AndroidJUnitRunner() {
- override fun newApplication(cl: ClassLoader, appName: String, context: Context): Application {
- return super.newApplication(cl, HiltTestApplication::class.java.name, context)
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml
deleted file mode 100644
index ce1fb71..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.gradleConfigCache">
-
- <application
- android:name=".App"
- android:allowBackup="true"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/App.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/App.kt
deleted file mode 100644
index 1cbd4b0..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/App.kt
+++ /dev/null
@@ -1,23 +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.gradleConfigCache
-
-import androidx.multidex.MultiDexApplication
-import dagger.hilt.android.HiltAndroidApp
-
-@HiltAndroidApp
-class App : MultiDexApplication()
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt
deleted file mode 100644
index 969e183..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/Foo.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package dagger.hilt.android.gradleConfigCache
-
-import javax.inject.Inject
-
-class Foo @Inject constructor()
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/MainActivity.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/MainActivity.kt
deleted file mode 100644
index 0011bde..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/java/dagger/hilt/android/gradleConfigCache/MainActivity.kt
+++ /dev/null
@@ -1,36 +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.gradleConfigCache
-
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class MainActivity : AppCompatActivity() {
-
- @Inject
- lateinit var foo: Foo
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- Log.d("Hilt", "Foo is $foo")
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/layout/activity_main.xml b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index cb5a8df..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-</RelativeLayout>
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/values/strings.xml b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/values/strings.xml
deleted file mode 100644
index 05afdbf..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,20 +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.
- -->
-
-<resources>
- <!--The app name [CHAR_LIMIT=40]-->
- <string name="app_name">Gradle Configuration Cache App</string>
-</resources>
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt b/javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt
deleted file mode 100644
index 527d887..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/app/src/test/java/dagger/hilt/android/gradleConfigCache/LocalTest.kt
+++ /dev/null
@@ -1,46 +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.gradleConfigCache
-
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import dagger.hilt.android.testing.HiltTestApplication
-import org.junit.Assert.assertNotNull
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.annotation.Config
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-@Config(application = HiltTestApplication::class)
-class LocalTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun testFooInjected() {
- ActivityScenario.launch(MainActivity::class.java).use {
- it.onActivity { activity ->
- assertNotNull(activity.foo)
- }
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/build.gradle b/javatests/artifacts/hilt-android/gradleConfigCache/build.gradle
deleted file mode 100644
index 3b0cdde..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/build.gradle
+++ /dev/null
@@ -1,41 +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.
- */
-
-buildscript {
- ext {
- kotlin_version = '1.4.20'
- agp_version = "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties b/javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties
deleted file mode 100644
index 1813493..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradle.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
-
-# Error out if an issue is found that disallows the configuration cache.
-# These options along with this app being built in presubmit helps us cache
-# changes that would cause config cache to be disabled via the HiltGradlePlugin.
-org.gradle.unsafe.configuration-cache=ERROR
-org.gradle.unsafe.configuration-cache.max-problems=0
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 62d4c05..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew b/javatests/artifacts/hilt-android/gradleConfigCache/gradlew
deleted file mode 100755
index fbd7c51..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/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
-#
-# https://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 or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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"
-
-exec "$JAVACMD" "$@"
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat b/javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat
deleted file mode 100644
index a9f778a..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/gradlew.bat
+++ /dev/null
@@ -1,104 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
diff --git a/javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle b/javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle
deleted file mode 100644
index d0d5fee..0000000
--- a/javatests/artifacts/hilt-android/gradleConfigCache/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-rootProject.name='Gradle Configuration Cache App'
-include ':app'
diff --git a/javatests/artifacts/hilt-android/simple/app/build.gradle b/javatests/artifacts/hilt-android/simple/app/build.gradle
deleted file mode 100644
index 98b79e1..0000000
--- a/javatests/artifacts/hilt-android/simple/app/build.gradle
+++ /dev/null
@@ -1,105 +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.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.simple"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "dagger.hilt.android.simple.SimpleEmulatorTestRunner"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
- lintOptions {
- checkReleaseBuilds = false
- }
- sourceSets {
- String sharedTestDir = 'src/sharedTest/java'
- test {
- java.srcDirs += sharedTestDir
- }
- androidTest {
- java.srcDirs += sharedTestDir
- }
- }
-}
-
-hilt {
- enableExperimentalClasspathAggregation = true
- enableTransformForLocalTests = true
-}
-
-configurations.all {
- resolutionStrategy.eachDependency { DependencyResolveDetails details ->
- if ("$dagger_version" == 'LOCAL-SNAPSHOT'
- && details.requested.group == 'com.google.dagger') {
- details.useVersion 'LOCAL-SNAPSHOT'
- details.because 'LOCAL-SNAPSHOT should act as latest version.'
- }
- }
-}
-
-dependencies {
- implementation project(':feature')
- implementation project(':lib')
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation "com.google.dagger:hilt-android:$dagger_version"
- annotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
-
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'androidx.test.espresso:espresso-core:3.3.0'
- testImplementation "com.google.dagger:hilt-android-testing:$dagger_version"
- testAnnotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
-
- androidTestImplementation 'com.google.truth:truth:1.0.1'
- androidTestImplementation 'junit:junit:4.13'
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
- androidTestImplementation "com.google.dagger:hilt-android-testing:$dagger_version"
- androidTestAnnotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
-
- // To help us catch usages of Guava APIs for Java 8 in the '-jre' variant.
- annotationProcessor'com.google.guava:guava:28.1-android'
- testAnnotationProcessor'com.google.guava:guava:28.1-android'
- androidTestAnnotationProcessor'com.google.guava:guava:28.1-android'
-
- // To help us catch version skew related issues in hilt extensions.
- // TODO(bcorso): Add examples testing the actual API.
- implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
- implementation 'androidx.hilt:hilt-work:1.0.0-alpha01'
- annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
- testAnnotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
- androidTestAnnotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/androidTest/java/dagger/hilt/android/simple/SimpleEmulatorTestRunner.java b/javatests/artifacts/hilt-android/simple/app/src/androidTest/java/dagger/hilt/android/simple/SimpleEmulatorTestRunner.java
deleted file mode 100644
index 6ee721c..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/androidTest/java/dagger/hilt/android/simple/SimpleEmulatorTestRunner.java
+++ /dev/null
@@ -1,32 +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.simple;
-
-import android.app.Application;
-import android.content.Context;
-import androidx.test.runner.AndroidJUnitRunner;
-import dagger.hilt.android.testing.HiltTestApplication;
-
-/** A custom runner to setup the emulator application class for tests. */
-public final class SimpleEmulatorTestRunner extends AndroidJUnitRunner {
-
- @Override
- public Application newApplication(ClassLoader cl, String className, Context context)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- return super.newApplication(cl, HiltTestApplication.class.getName(), context);
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 14d33b0..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,33 +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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simple">
-
- <application>
- <activity
- android:name=".Injection1Test$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false" />
- <activity
- android:name=".Injection2Test$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false"/>
- <activity
- android:name=".ActivityScenarioRuleTest$TestActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false"/>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml
deleted file mode 100644
index 0b12b13..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simple">
-
- <application android:name=".SimpleApplication" android:label="@string/appName">
- <activity
- android:name=".SimpleActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name=".SettingsActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="false">
- </activity>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/Model.java b/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/Model.java
deleted file mode 100644
index 9965b2e..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/Model.java
+++ /dev/null
@@ -1,29 +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.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to {@link android.os.Build#MODEL}. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface Model {}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/ModelModule.java b/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/ModelModule.java
deleted file mode 100644
index 9a63f17..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/ModelModule.java
+++ /dev/null
@@ -1,36 +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.simple;
-
-import static android.os.Build.MODEL;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-
-@Module
-@InstallIn(SingletonComponent.class)
-final class ModelModule {
- @Provides
- @Model
- static String provideModel() {
- return MODEL;
- }
-
- private ModelModule() {}
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/SimpleActivity.java b/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/SimpleActivity.java
deleted file mode 100644
index 5d16cd4..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/SimpleActivity.java
+++ /dev/null
@@ -1,53 +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.simple;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.Button;
-import android.widget.TextView;
-import androidx.appcompat.app.AppCompatActivity;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.simple.feature.FeatureActivity;
-import dagger.hilt.android.simple.lib.Thing;
-import javax.inject.Inject;
-
-/** The main activity of the application. */
-@AndroidEntryPoint
-public class SimpleActivity extends AppCompatActivity {
- private static final String TAG = SimpleActivity.class.getSimpleName();
-
- @Inject @UserName String userName;
- @Inject @Model String model;
- @Inject Thing thing;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Log.i(TAG, "Injected with userName and model: " + userName + ", " + model);
-
- setContentView(R.layout.activity_main);
-
- ((TextView) findViewById(R.id.greeting))
- .setText(getResources().getString(R.string.welcome, userName, model));
-
- Button featureButton = (Button) findViewById(R.id.goto_feature);
- featureButton.setOnClickListener(
- view -> startActivity(new Intent(this, FeatureActivity.class)));
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/SimpleApplication.java b/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/SimpleApplication.java
deleted file mode 100644
index 3c7d1f3..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/SimpleApplication.java
+++ /dev/null
@@ -1,39 +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.simple;
-
-import android.app.Application;
-import android.util.Log;
-import dagger.hilt.android.HiltAndroidApp;
-import javax.inject.Inject;
-
-/**
- * A simple, skeletal application that demonstrates a dependency-injected application using the
- * utilities in {@code Hilt} in Android.
- */
-@HiltAndroidApp
-public class SimpleApplication extends Application {
- private static final String TAG = SimpleApplication.class.getSimpleName();
-
- @Inject @Model String model;
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.i(TAG, "Injected with model: " + model);
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/UserName.java b/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/UserName.java
deleted file mode 100644
index 19f0679..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/UserName.java
+++ /dev/null
@@ -1,29 +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.simple;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(RUNTIME)
-@Documented
-@interface UserName {}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/UserNameModule.java b/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/UserNameModule.java
deleted file mode 100644
index 26d52df..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/java/dagger/hilt/android/simple/UserNameModule.java
+++ /dev/null
@@ -1,34 +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.simple;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.components.ActivityComponent;
-
-@Module
-@InstallIn(ActivityComponent.class)
-final class UserNameModule {
- @UserName
- @Provides
- static String provideUserName() {
- return "ProdUser";
- }
-
- private UserNameModule() {}
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/res/layout/activity_main.xml b/javatests/artifacts/hilt-android/simple/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index b786106..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-
- <Button
- android:id="@+id/goto_feature"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/greeting"
- android:text="@string/navigateToFeature"
- />
-</RelativeLayout>
diff --git a/javatests/artifacts/hilt-android/simple/app/src/main/res/values/strings.xml b/javatests/artifacts/hilt-android/simple/app/src/main/res/values/strings.xml
deleted file mode 100644
index c8f9b8a..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<resources>
- <!--The app name [CHAR_LIMIT=20]-->
- <string name="appName">Simple Hilt Android</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s! You are on build %2$s.</string>
-
- <!--The feature button message [CHAR_LIMIT=100]-->
- <string name="navigateToFeature">Navigate to a feature!</string>
-</resources>
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/ActivityScenarioRuleTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/ActivityScenarioRuleTest.java
deleted file mode 100644
index b49e666..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/ActivityScenarioRuleTest.java
+++ /dev/null
@@ -1,80 +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.simple;
-
-import static androidx.lifecycle.Lifecycle.State.RESUMED;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.rules.ActivityScenarioRule;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests that {@link ActivityScenarioRule} works with Hilt tests. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class ActivityScenarioRuleTest {
- private static final String STR_VALUE = "STR_VALUE";
-
- /** An activity to test injection. */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject String str;
- }
-
- @Rule(order = 0) public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
-
- @Rule(order = 1)
- public ActivityScenarioRule<TestActivity> scenarioRule =
- new ActivityScenarioRule<>(TestActivity.class);
-
- @BindValue String str = STR_VALUE;
-
- @Test
- public void testState() {
- assertThat(scenarioRule.getScenario().getState()).isEqualTo(RESUMED);
- }
-
- @Test
- public void testInjection() {
- scenarioRule
- .getScenario()
- .onActivity(activity -> assertThat(activity.str).isEqualTo(STR_VALUE));
- }
-
-
- @Test
- public void verifyMainActivity() {
- try (ActivityScenario<TestActivity> scenario =
- ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(
- activity -> {
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_ActivityScenarioRuleTest_TestActivity");
- }
- );
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/BindValueTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/BindValueTest.java
deleted file mode 100644
index e77f605..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/BindValueTest.java
+++ /dev/null
@@ -1,155 +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.simple;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.google.common.collect.ImmutableSet;
-import dagger.MapKey;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.BindElementsIntoSet;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.BindValueIntoMap;
-import dagger.hilt.android.testing.BindValueIntoSet;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import java.util.Map;
-import java.util.Set;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class BindValueTest {
- private static final String BIND_VALUE_STRING = "BIND_VALUE_STRING";
- private static final String TEST_QUALIFIER = "TEST_QUALIFIER";
-
- private static final String SET_STRING_1 = "SetString1";
- private static final String SET_STRING_2 = "SetString2";
- private static final String SET_STRING_3 = "SetString3";
-
- private static final String KEY_1 = "Key1";
- private static final String KEY_2 = "Key2";
- private static final String VALUE_1 = "Value1";
- private static final String VALUE_2 = "Value2";
- private static final String VALUE_3 = "Value3";
-
- private static final Integer SET_INT_1 = 1;
- private static final Integer SET_INT_2 = 2;
- private static final Integer SET_INT_3 = 3;
-
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- interface BindValueEntryPoint {
- @Named(TEST_QUALIFIER)
- String bindValueString();
-
- Set<String> getStringSet();
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue
- @Named(TEST_QUALIFIER)
- String bindValueString = BIND_VALUE_STRING;
-
- @BindElementsIntoSet Set<String> bindElementsSet1 = ImmutableSet.of(SET_STRING_1);
- @BindElementsIntoSet Set<String> bindElementsSet2 = ImmutableSet.of(SET_STRING_2);
-
- @BindValueIntoMap
- @MyMapKey(KEY_1)
- String boundValue1 = VALUE_1;
-
- @BindValueIntoMap
- @MyMapKey(KEY_2)
- String boundValue2 = VALUE_2;
-
- @BindValueIntoSet Integer bindValueSetInt1 = SET_INT_1;
- @BindValueIntoSet Integer bindValueSetInt2 = SET_INT_2;
-
- @Inject Set<String> stringSet;
- @Inject Provider<Set<String>> providedStringSet;
- @Inject Provider<Map<String, String>> mapProvider;
- @Inject Set<Integer> intSet;
- @Inject Provider<Set<Integer>> providedIntSet;
-
- @Test
- public void testBindValueFieldIsProvided() throws Exception {
- assertThat(bindValueString).isEqualTo(BIND_VALUE_STRING);
- assertThat(getBinding()).isEqualTo(BIND_VALUE_STRING);
- }
-
- @Test
- public void testBindValueIsMutable() throws Exception {
- bindValueString = "newValue";
- assertThat(getBinding()).isEqualTo("newValue");
- }
-
- @Test
- public void testElementsIntoSet() throws Exception {
- rule.inject();
- // basic check that initial/default values are properly injected
- assertThat(providedStringSet.get()).containsExactly(SET_STRING_1, SET_STRING_2);
- // Test empty sets (something that cannot be done with @BindValueIntoSet)
- bindElementsSet1 = ImmutableSet.of();
- bindElementsSet2 = ImmutableSet.of();
- assertThat(providedStringSet.get()).isEmpty();
- // Test multiple elements in set.
- bindElementsSet1 = ImmutableSet.of(SET_STRING_1, SET_STRING_2, SET_STRING_3);
- assertThat(providedStringSet.get()).containsExactly(SET_STRING_1, SET_STRING_2, SET_STRING_3);
- }
-
- @Test
- public void testBindValueIntoMap() throws Exception {
- rule.inject();
- Map<String, String> oldMap = mapProvider.get();
- assertThat(oldMap).containsExactly(KEY_1, VALUE_1, KEY_2, VALUE_2);
- boundValue1 = VALUE_3;
- Map<String, String> newMap = mapProvider.get();
- assertThat(oldMap).containsExactly(KEY_1, VALUE_1, KEY_2, VALUE_2);
- assertThat(newMap).containsExactly(KEY_1, VALUE_3, KEY_2, VALUE_2);
- }
-
- @Test
- public void testBindValueIntoSet() throws Exception {
- rule.inject();
- // basic check that initial/default values are properly injected
- assertThat(providedIntSet.get()).containsExactly(SET_INT_1, SET_INT_2);
- bindValueSetInt1 = SET_INT_3;
- // change the value for bindValueSetString from 1 to 3
- assertThat(providedIntSet.get()).containsExactly(SET_INT_2, SET_INT_3);
- }
-
- @MapKey
- @interface MyMapKey {
- String value();
- }
-
- private static String getBinding() {
- return EntryPoints.get(getApplicationContext(), BindValueEntryPoint.class).bindValueString();
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/DelayComponentReadyTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/DelayComponentReadyTest.java
deleted file mode 100644
index 81afb6e..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/DelayComponentReadyTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.android.simple;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertThrows;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.OnComponentReadyRunner;
-import dagger.hilt.components.SingletonComponent;
-import java.util.concurrent.atomic.AtomicReference;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class DelayComponentReadyTest {
-
- private static final String EXPECTED_VALUE = "expected";
-
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- public interface FooEntryPoint {
- String foo();
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this).delayComponentReady();
-
- @BindValue String foo;
-
- @Test
- public void testLateBindValue() throws Exception {
- AtomicReference<String> fooRef = new AtomicReference<>();
- OnComponentReadyRunner.addListener(
- ApplicationProvider.getApplicationContext(),
- FooEntryPoint.class,
- entryPoint -> fooRef.set(entryPoint.foo()));
-
- // Test that setting the listener before the component is ready doesn't run the listener.
- assertThat(fooRef.get()).isNull();
-
- foo = EXPECTED_VALUE;
- rule.componentReady().inject();
- assertThat(EntryPoints.get(getApplicationContext(), FooEntryPoint.class).foo())
- .isEqualTo(EXPECTED_VALUE);
- }
-
- @Test
- public void testUnitializedBindValue_fails() throws Exception {
- OnComponentReadyRunner.addListener(
- ApplicationProvider.getApplicationContext(), FooEntryPoint.class, FooEntryPoint::foo);
-
- // foo not set
- NullPointerException expected = assertThrows(NullPointerException.class, rule::componentReady);
- // This is not the best error message, but it is equivalent to the message from a regular
- // (non-delayed) @BindValue returning null;
- assertThat(expected)
- .hasMessageThat()
- .isEqualTo("Cannot return null from a non-@Nullable @Provides method");
- }
-
- @Test
- public void testDoubleComponentReady_fails() throws Exception {
- foo = EXPECTED_VALUE;
- rule.componentReady();
- IllegalStateException expected =
- assertThrows(IllegalStateException.class, rule::componentReady);
- assertThat(expected).hasMessageThat().isEqualTo("Called componentReady() multiple times");
- }
-
- @Test
- public void testMissingComponentReady_fails() throws Exception {
- // componentReady not called
- foo = EXPECTED_VALUE;
- IllegalStateException expected = assertThrows(IllegalStateException.class, rule::inject);
- assertThat(expected)
- .hasMessageThat()
- .isEqualTo("Called inject() before calling componentReady()");
- }
-
- @Test
- public void testDelayComponentReadyAfterStart_fails() throws Exception {
- IllegalStateException expected =
- assertThrows(IllegalStateException.class, rule::delayComponentReady);
- assertThat(expected)
- .hasMessageThat()
- .isEqualTo("Called delayComponentReady after test execution started");
- // Prevents failure due to never calling componentReady()
- foo = EXPECTED_VALUE;
- rule.componentReady();
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/Injection1Test.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/Injection1Test.java
deleted file mode 100644
index 6e5ad6a..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/Injection1Test.java
+++ /dev/null
@@ -1,100 +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.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic injection APIs, and that bindings don't conflict with {@link Injection2Test}. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class Injection1Test {
- private static final String APPLICATION_QUALIFIER = "APPLICATION_QUALIFIER";
- private static final String ACTIVITY_QUALIFIER = "ACTIVITY_QUALIFIER";
- private static final String APPLICATION_VALUE = "Injection1Test_ApplicationValue";
- private static final String ACTIVITY_VALUE = "Injection1Test_ActivityValue";
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface TestApplicationModule {
- @Provides
- @Named(APPLICATION_QUALIFIER)
- static String provideString() {
- return APPLICATION_VALUE;
- }
- }
-
- @Module
- @InstallIn(ActivityComponent.class)
- interface TestActivityModule {
- @Provides
- @Named(ACTIVITY_QUALIFIER)
- static String provideString() {
- return ACTIVITY_VALUE;
- }
- }
-
- /** Test activity used to test activity injection */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject @Named(ACTIVITY_QUALIFIER) String activityValue;
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject @Named(APPLICATION_QUALIFIER) String applicationValue;
-
- @Test
- public void testApplicationInjection() throws Exception {
- assertThat(applicationValue).isNull();
- rule.inject();
- assertThat(applicationValue).isEqualTo(APPLICATION_VALUE);
- }
-
- @Test
- public void testActivityInjection() throws Exception {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.activityValue).isEqualTo(ACTIVITY_VALUE));
- }
- }
-
- @Test
- public void testSuperClassTransformation() {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(
- activity ->
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_Injection1Test_TestActivity"));
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/Injection2Test.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/Injection2Test.java
deleted file mode 100644
index 1ba3c2f..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/Injection2Test.java
+++ /dev/null
@@ -1,90 +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.simple;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.AndroidEntryPoint;
-import dagger.hilt.android.components.ActivityComponent;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-import javax.inject.Named;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic injection APIs, and that bindings don't conflict with {@link Injection1Test}. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class Injection2Test {
- private static final String APPLICATION_QUALIFIER = "APPLICATION_QUALIFIER";
- private static final String ACTIVITY_QUALIFIER = "ACTIVITY_QUALIFIER";
- private static final String APPLICATION_VALUE = "Injection2Test_ApplicationValue";
- private static final String ACTIVITY_VALUE = "Injection2Test_ActivityValue";
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface TestApplicationModule {
- @Provides
- @Named(APPLICATION_QUALIFIER)
- static String provideString() {
- return APPLICATION_VALUE;
- }
- }
-
- @Module
- @InstallIn(ActivityComponent.class)
- interface TestActivityModule {
- @Provides
- @Named(ACTIVITY_QUALIFIER)
- static String provideString() {
- return ACTIVITY_VALUE;
- }
- }
-
- /** Test activity used to test activity injection */
- @AndroidEntryPoint
- public static final class TestActivity extends AppCompatActivity {
- @Inject @Named(ACTIVITY_QUALIFIER) String activityValue;
- }
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Inject @Named(APPLICATION_QUALIFIER) String applicationValue;
-
- @Test
- public void testApplicationInjection() throws Exception {
- assertThat(applicationValue).isNull();
- rule.inject();
- assertThat(applicationValue).isEqualTo(APPLICATION_VALUE);
- }
-
- @Test
- public void testActivityInjection() throws Exception {
- try (ActivityScenario<TestActivity> scenario = ActivityScenario.launch(TestActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.activityValue).isEqualTo(ACTIVITY_VALUE));
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/ModuleTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/ModuleTest.java
deleted file mode 100644
index e1f4421..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/ModuleTest.java
+++ /dev/null
@@ -1,157 +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.simple;
-
-import static org.junit.Assert.assertEquals;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.components.SingletonComponent;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-import javax.inject.Inject;
-import javax.inject.Qualifier;
-import javax.inject.Singleton;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Tests basic functionality of using modules in test. */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class ModuleTest {
- @Rule public final HiltAndroidRule rules = new HiltAndroidRule(this);
-
- /** Qualifier for distinguishing test Strings, */
- @Qualifier
- @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
- public @interface TestQualifier {
- int value();
- }
-
- @Inject
- @TestQualifier(1)
- String testString1;
-
- @Inject
- @TestQualifier(2)
- String testString2;
-
- @Inject
- @TestQualifier(3)
- String testString3;
-
- @Inject
- @TestQualifier(4)
- String testString4;
-
- @Inject FooImpl fooImpl;
- @Inject Foo foo;
-
- /**
- * Module which is used to test if non-static test modules get registered in the component
- * correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public final class NonStaticModuleNonStaticProvides {
- @Provides
- @TestQualifier(1)
- String provideString() {
- return "1";
- }
- }
-
- /**
- * Module which is used to test if static test modules get registered in the component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public static final class StaticModuleStaticProvides {
- @Provides
- @TestQualifier(2)
- static String provideString() {
- return "2";
- }
-
- private StaticModuleStaticProvides() {}
- }
-
- /**
- * Module which is used to test if static test modules with a non-static methods get registered in
- * the component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public static final class StaticModuleNonStaticProvidesDefaultConstructor {
- @Provides
- @TestQualifier(3)
- String provideString() {
- return "3";
- }
- }
-
- /**
- * Module which is used to test if abstract test modules get registered in the component
- * correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public abstract static class AbstractModuleStaticProvides {
- @Provides
- @TestQualifier(4)
- static String provideString() {
- return "4";
- }
-
- private AbstractModuleStaticProvides() {}
- }
-
- /**
- * Module which is used to test if abstract test modules with a binds method get registered in the
- * component correctly.
- */
- @Module
- @InstallIn(SingletonComponent.class)
- public abstract static class AbstractModuleBindsMethod {
- @Binds
- abstract Foo foo(FooImpl fooImpl);
- }
-
- interface Foo {}
-
- @Singleton
- static final class FooImpl implements Foo {
- @Inject
- FooImpl() {}
- }
-
- @Test
- public void testInjection() throws Exception {
- rules.inject();
- assertEquals("1", testString1);
- assertEquals("2", testString2);
- assertEquals("3", testString3);
- assertEquals("4", testString4);
- assertEquals(fooImpl, foo);
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/SimpleActivityTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/SimpleActivityTest.java
deleted file mode 100644
index f2e2e77..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/SimpleActivityTest.java
+++ /dev/null
@@ -1,105 +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.simple;
-
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import dagger.hilt.android.simple.lib.ThingImpl;
-import dagger.hilt.android.testing.BindValue;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import dagger.hilt.android.testing.UninstallModules;
-import javax.inject.Inject;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** A simple test using Hilt that can be run with instrumentation or Robolectric tests. */
-@UninstallModules({
- UserNameModule.class,
- ModelModule.class
-})
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public final class SimpleActivityTest {
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @BindValue @UserName String fakeUserName = "FakeUser";
- @BindValue @Model String fakeModel = "FakeModel";
-
- @Inject @UserName String injectedUserName;
- @Inject @Model String injectedModel;
-
- @Test
- public void testInjectedUserName() throws Exception {
- assertThat(injectedUserName).isNull();
- rule.inject();
- assertThat(injectedUserName).isEqualTo("FakeUser");
- }
-
- @Test
- public void testInjectedModel() throws Exception {
- assertThat(injectedModel).isNull();
- rule.inject();
- assertThat(injectedModel).isEqualTo("FakeModel");
- }
-
- @Test
- public void testActivityInject() throws Exception {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- onView(withId(R.id.greeting))
- .check(matches(withText("Hello, FakeUser! You are on build FakeModel.")));
- } catch (RuntimeException e) {
- // Just skip this test if the root view never becomes active.
- // This issue occurs sporadically in emulator tests and causes the test to be flaky.
- // It is likely caused by a race between our activity and a dialog or lock screen but
- // it's difficult to debug this since it only fails in CI builds.
- // TODO(b/176111885): Remove this once this bug is fixed.
- if (!e.getMessage().startsWith("Waited for the root of the view hierarchy")) {
- throw e;
- }
- }
- }
-
- @Test
- public void verifyMainActivity() {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(
- activity -> {
- assertThat(activity.getClass().getSuperclass().getSimpleName())
- .isEqualTo("Hilt_SimpleActivity");
- }
- );
- }
- }
-
- @Test
- public void verifyThing() {
- try (ActivityScenario<SimpleActivity> scenario =
- ActivityScenario.launch(SimpleActivity.class)) {
- scenario.onActivity(activity -> assertThat(activity.thing).isInstanceOf(ThingImpl.class));
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/TransitiveDependenciesTest.java b/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/TransitiveDependenciesTest.java
deleted file mode 100644
index a4f900d..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/sharedTest/java/dagger/hilt/android/simple/TransitiveDependenciesTest.java
+++ /dev/null
@@ -1,43 +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.simple;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-import dagger.hilt.android.simple.feature.FeatureEntryPoints;
-import dagger.hilt.android.testing.HiltAndroidRule;
-import dagger.hilt.android.testing.HiltAndroidTest;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests that entry points in deep dependencies with `implementation` boundaries are available at
- * runtime.
- */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4.class)
-public class TransitiveDependenciesTest {
-
- @Rule public HiltAndroidRule rule = new HiltAndroidRule(this);
-
- @Test
- public void testEntryPoint() {
- FeatureEntryPoints.invokeEntryPoints(
- InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext());
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/app/src/test/resources/dagger/hilt/android/simple/robolectric.properties b/javatests/artifacts/hilt-android/simple/app/src/test/resources/dagger/hilt/android/simple/robolectric.properties
deleted file mode 100644
index 0234ffe..0000000
--- a/javatests/artifacts/hilt-android/simple/app/src/test/resources/dagger/hilt/android/simple/robolectric.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-sdk=28
-application=dagger.hilt.android.testing.HiltTestApplication
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simple/build.gradle b/javatests/artifacts/hilt-android/simple/build.gradle
deleted file mode 100644
index 770fabd..0000000
--- a/javatests/artifacts/hilt-android/simple/build.gradle
+++ /dev/null
@@ -1,42 +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.
- */
-
-buildscript {
- ext {
- dagger_version = 'LOCAL-SNAPSHOT'
- kotlin_version = '1.3.61'
- agp_version = System.getenv('AGP_VERSION') ?: "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath "com.google.dagger:hilt-android-gradle-plugin:$dagger_version"
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle b/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle
deleted file mode 100644
index e5ed046..0000000
--- a/javatests/artifacts/hilt-android/simple/deep-android-lib/build.gradle
+++ /dev/null
@@ -1,26 +0,0 @@
-plugins {
- id 'com.android.library'
- id 'dagger.hilt.android.plugin'
-}
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
-
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
-}
-
-dependencies {
- implementation "com.google.dagger:hilt-android:$dagger_version"
- annotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
-}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simple/deep-android-lib/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/deep-android-lib/src/main/AndroidManifest.xml
deleted file mode 100644
index 49a304e..0000000
--- a/javatests/artifacts/hilt-android/simple/deep-android-lib/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simple.deep">
-
-</manifest>
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simple/deep-android-lib/src/main/java/dagger/hilt/android/simple/deep/DeepAndroidLib.java b/javatests/artifacts/hilt-android/simple/deep-android-lib/src/main/java/dagger/hilt/android/simple/deep/DeepAndroidLib.java
deleted file mode 100644
index 57fd803..0000000
--- a/javatests/artifacts/hilt-android/simple/deep-android-lib/src/main/java/dagger/hilt/android/simple/deep/DeepAndroidLib.java
+++ /dev/null
@@ -1,41 +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.simple.deep;
-
-import android.content.Context;
-import dagger.hilt.EntryPoint;
-import dagger.hilt.InstallIn;
-import dagger.hilt.android.EntryPointAccessors;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-
-public class DeepAndroidLib {
-
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- interface LibEntryPoint {
- DeepAndroidLib getDeepAndroidInstance();
- }
-
- @Inject
- public DeepAndroidLib() {}
-
- public static DeepAndroidLib getInstance(Context context) {
- return EntryPointAccessors.fromApplication(context, LibEntryPoint.class)
- .getDeepAndroidInstance();
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle b/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle
deleted file mode 100644
index 22f815c..0000000
--- a/javatests/artifacts/hilt-android/simple/deep-lib/build.gradle
+++ /dev/null
@@ -1,13 +0,0 @@
-plugins {
- id 'java-library'
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_7
- targetCompatibility = JavaVersion.VERSION_1_7
-}
-
-dependencies {
- implementation "com.google.dagger:hilt-core:$dagger_version"
- annotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
-}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simple/deep-lib/src/main/java/dagger/hilt/android/deep/DeepLib.java b/javatests/artifacts/hilt-android/simple/deep-lib/src/main/java/dagger/hilt/android/deep/DeepLib.java
deleted file mode 100644
index 419e539..0000000
--- a/javatests/artifacts/hilt-android/simple/deep-lib/src/main/java/dagger/hilt/android/deep/DeepLib.java
+++ /dev/null
@@ -1,39 +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.deep;
-
-import dagger.hilt.EntryPoint;
-import dagger.hilt.EntryPoints;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-
-public class DeepLib {
-
- @EntryPoint
- @InstallIn(SingletonComponent.class)
- interface LibEntryPoint {
- DeepLib getDeepInstance();
- }
-
- @Inject
- public DeepLib() {}
-
- public static DeepLib getInstance(Object componentManager) {
- return EntryPoints.get(componentManager, LibEntryPoint.class).getDeepInstance();
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/feature/build.gradle b/javatests/artifacts/hilt-android/simple/feature/build.gradle
deleted file mode 100644
index 0e772a8..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/build.gradle
+++ /dev/null
@@ -1,57 +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.
- */
-
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply plugin: 'dagger.hilt.android.plugin'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
-}
-
-kapt {
- correctErrorTypes true
-}
-
-hilt {
- enableTransformForLocalTests = true
-}
-
-dependencies {
- // This is api instead of implementation since Kotlin modules here consumed
- // by the app need to expose @kotlin.Metadata
- api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-
- implementation project(":deep-android-lib")
- implementation project(":deep-lib")
-
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation "com.google.dagger:hilt-android:$dagger_version"
- kapt "com.google.dagger:hilt-compiler:$dagger_version"
-}
diff --git a/javatests/artifacts/hilt-android/simple/feature/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simple/feature/src/main/AndroidManifest.xml
deleted file mode 100644
index fe583e5..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simple.feature">
- <application>
- <activity
- android:name=".FeatureActivity"
- android:theme="@style/Theme.AppCompat.Light"
- android:exported="true"/>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureActivity.kt b/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureActivity.kt
deleted file mode 100644
index c1931ac..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureActivity.kt
+++ /dev/null
@@ -1,46 +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.simple.feature
-
-import android.os.Bundle
-import android.widget.Button
-import android.widget.TextView
-import androidx.appcompat.app.AppCompatActivity
-import dagger.hilt.android.AndroidEntryPoint
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class FeatureActivity : AppCompatActivity() {
- @Inject lateinit var counter: FeatureCounter
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setContentView(R.layout.activity_feature)
-
- findViewById<Button>(R.id.feature_button).setOnClickListener {
- counter.count++
- updateCountText()
- }
-
- updateCountText()
- }
-
- private fun updateCountText() {
- findViewById<TextView>(R.id.feature_count).text = "The count: ${counter.count}"
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureCounter.kt b/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureCounter.kt
deleted file mode 100644
index d55bb5a..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureCounter.kt
+++ /dev/null
@@ -1,19 +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.simple.feature
-
-class FeatureCounter(var count: Int)
diff --git a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureEntryPoints.java b/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureEntryPoints.java
deleted file mode 100644
index c1ca22f..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureEntryPoints.java
+++ /dev/null
@@ -1,31 +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.simple.feature;
-
-import android.content.Context;
-import dagger.hilt.android.deep.DeepLib;
-import dagger.hilt.android.simple.deep.DeepAndroidLib;
-
-public final class FeatureEntryPoints {
-
- public static void invokeEntryPoints(Context context) {
- DeepAndroidLib.getInstance(context);
- DeepLib.getInstance(context);
- }
-
- private FeatureEntryPoints() {}
-}
diff --git a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureModule.kt b/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureModule.kt
deleted file mode 100644
index d513f37..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/src/main/java/dagger/hilt/android/simple/feature/FeatureModule.kt
+++ /dev/null
@@ -1,31 +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.simple.feature
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityRetainedComponent
-import dagger.hilt.android.scopes.ActivityRetainedScoped
-
-@Module
-@InstallIn(ActivityRetainedComponent::class)
-object FeatureModule {
- @Provides
- @ActivityRetainedScoped
- fun provideData() = FeatureCounter(0)
-}
diff --git a/javatests/artifacts/hilt-android/simple/feature/src/main/res/layout/activity_feature.xml b/javatests/artifacts/hilt-android/simple/feature/src/main/res/layout/activity_feature.xml
deleted file mode 100644
index 99adcfd..0000000
--- a/javatests/artifacts/hilt-android/simple/feature/src/main/res/layout/activity_feature.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/feature_count"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-
- <Button
- android:id="@+id/feature_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/feature_count"
- android:text="Count++"
- />
-</RelativeLayout>
diff --git a/javatests/artifacts/hilt-android/simple/gradle.properties b/javatests/artifacts/hilt-android/simple/gradle.properties
deleted file mode 100644
index 646c51b..0000000
--- a/javatests/artifacts/hilt-android/simple/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/javatests/artifacts/hilt-android/simple/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/simple/gradlew b/javatests/artifacts/hilt-android/simple/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/javatests/artifacts/hilt-android/simple/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/hilt-android/simple/lib/build.gradle b/javatests/artifacts/hilt-android/simple/lib/build.gradle
deleted file mode 100644
index d67be3b..0000000
--- a/javatests/artifacts/hilt-android/simple/lib/build.gradle
+++ /dev/null
@@ -1,29 +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.
- */
-
-plugins {
- id 'java-library'
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
-}
-
-dependencies {
- implementation "com.google.dagger:hilt-core:$dagger_version"
- annotationProcessor "com.google.dagger:hilt-compiler:$dagger_version"
-}
diff --git a/javatests/artifacts/hilt-android/simple/lib/src/main/java/dagger/hilt/android/simple/lib/Thing.java b/javatests/artifacts/hilt-android/simple/lib/src/main/java/dagger/hilt/android/simple/lib/Thing.java
deleted file mode 100644
index baded09..0000000
--- a/javatests/artifacts/hilt-android/simple/lib/src/main/java/dagger/hilt/android/simple/lib/Thing.java
+++ /dev/null
@@ -1,20 +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.simple.lib;
-
-/** A thing. */
-public interface Thing {}
diff --git a/javatests/artifacts/hilt-android/simple/lib/src/main/java/dagger/hilt/android/simple/lib/ThingImpl.java b/javatests/artifacts/hilt-android/simple/lib/src/main/java/dagger/hilt/android/simple/lib/ThingImpl.java
deleted file mode 100644
index f6a628e..0000000
--- a/javatests/artifacts/hilt-android/simple/lib/src/main/java/dagger/hilt/android/simple/lib/ThingImpl.java
+++ /dev/null
@@ -1,35 +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.simple.lib;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-import javax.inject.Inject;
-
-/** An implementation of a thing. */
-public final class ThingImpl implements Thing {
- @Inject
- ThingImpl() {}
-
- @Module
- @InstallIn(SingletonComponent.class)
- interface FooStringModule {
- @Binds Thing bind(ThingImpl impl);
- }
-}
diff --git a/javatests/artifacts/hilt-android/simple/settings.gradle b/javatests/artifacts/hilt-android/simple/settings.gradle
deleted file mode 100644
index bad895d..0000000
--- a/javatests/artifacts/hilt-android/simple/settings.gradle
+++ /dev/null
@@ -1,6 +0,0 @@
-rootProject.name='Simple Hilt Android'
-include ':app'
-include ':feature'
-include ':lib'
-include ':deep-android-lib'
-include ':deep-lib'
\ 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
deleted file mode 100644
index 383c4be..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/android-library/build.gradle
+++ /dev/null
@@ -1,31 +0,0 @@
-plugins {
- id 'com.android.library'
- id 'kotlin-android'
- id 'kotlin-kapt'
-}
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
-}
-
-dependencies {
- implementation project(':deep-android-lib')
- implementation project(':deep-kotlin-lib')
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/android-library/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simpleKotlin/android-library/src/main/AndroidManifest.xml
deleted file mode 100644
index c60ba73..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/android-library/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simpleKotlin.lib">
-
-</manifest>
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/android-library/src/main/java/dagger/hilt/android/simpleKotlin/lib/AndroidLibraryEntryPoints.kt b/javatests/artifacts/hilt-android/simpleKotlin/android-library/src/main/java/dagger/hilt/android/simpleKotlin/lib/AndroidLibraryEntryPoints.kt
deleted file mode 100644
index cb10c8b..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/android-library/src/main/java/dagger/hilt/android/simpleKotlin/lib/AndroidLibraryEntryPoints.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package dagger.hilt.android.simpleKotlin.lib
-
-import android.content.Context
-import dagger.hilt.android.simpleKotlin.deep.DeepAndroidLib
-import dagger.hilt.android.simpleKotlin.deep.DeepLib
-
-object AndroidLibraryEntryPoints {
- fun invokeEntryPoints(context: Context) {
- DeepAndroidLib.getInstance(context)
- DeepLib.getInstance(context)
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
deleted file mode 100644
index ecfaf6e..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/build.gradle
+++ /dev/null
@@ -1,96 +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.
- */
-
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'dagger.hilt.android.plugin'
-apply plugin: 'kotlin-kapt'
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- applicationId "dagger.hilt.android.simpleKotlin"
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "dagger.hilt.android.example.gradle.simpleKotlin.TestRunner"
- }
- buildTypes {
- release {
- minifyEnabled true
- shrinkResources true
- }
- }
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
- testOptions {
- unitTests.includeAndroidResources = true
- }
- lintOptions {
- checkReleaseBuilds = false
- }
- sourceSets {
- String sharedTestDir = 'src/sharedTest/java'
- test {
- java.srcDirs += sharedTestDir
- }
- androidTest {
- java.srcDirs += sharedTestDir
- }
- }
-}
-
-hilt {
- enableExperimentalClasspathAggregation = true
- enableTransformForLocalTests = true
-}
-
-dependencies {
- implementation project(':android-library')
- implementation project(':kotlin-library')
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'androidx.activity:activity-ktx:1.1.0'
-
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'androidx.test:runner:1.3.0'
- testImplementation 'com.google.truth:truth:1.0.1'
- testImplementation 'junit:junit:4.13'
- testImplementation 'org.robolectric:robolectric:4.5-alpha-3'
- testImplementation 'androidx.core:core:1.3.2'
- // 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'
-
- androidTestImplementation 'androidx.fragment:fragment-ktx:1.2.5'
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.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'
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/SimpleEmulatorTestRunner.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/SimpleEmulatorTestRunner.kt
deleted file mode 100644
index d790265..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/SimpleEmulatorTestRunner.kt
+++ /dev/null
@@ -1,28 +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.simpleKotlin
-
-import android.app.Application
-import android.content.Context
-import androidx.test.runner.AndroidJUnitRunner
-import dagger.hilt.android.testing.HiltTestApplication
-
-/** A custom runner to setup the emulator application class for tests. */
-class SimpleEmulatorTestRunner : AndroidJUnitRunner() {
- override fun newApplication(cl: ClassLoader, className: String, context: Context): Application {
- return super.newApplication(cl, HiltTestApplication::class.java.name, context)
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/TestRunner.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/TestRunner.kt
deleted file mode 100644
index 29ffc9e..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/TestRunner.kt
+++ /dev/null
@@ -1,28 +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.example.gradle.simpleKotlin
-
-import android.app.Application
-import android.content.Context
-import androidx.test.runner.AndroidJUnitRunner
-import dagger.hilt.android.testing.HiltTestApplication
-
-class TestRunner : AndroidJUnitRunner() {
- override fun newApplication(cl: ClassLoader, appName: String, context: Context): Application {
- return super.newApplication(cl, HiltTestApplication::class.java.name, context)
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/ActivityInjectionTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/ActivityInjectionTest.kt
deleted file mode 100644
index 6786e9d..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/ActivityInjectionTest.kt
+++ /dev/null
@@ -1,59 +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.simpleKotlin.viewmodel
-
-import androidx.activity.viewModels
-import androidx.fragment.app.FragmentActivity
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class ActivityInjectionTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun verifyInjection() {
- ActivityScenario.launch(TestActivity::class.java).use {
- it.onActivity { activity ->
- assertThat(activity.myAndroidViewModel).isNotNull()
- assertThat(activity.myViewModel).isNotNull()
- assertThat(activity.myInjectedViewModel).isNotNull()
- assertThat(activity.myNestedInjectedViewModel).isNotNull()
- assertThat(activity.myInjectedViewModelWithSavedState).isNotNull()
- }
- }
- }
-
- @AndroidEntryPoint
- class TestActivity : FragmentActivity() {
- val myAndroidViewModel by viewModels<MyAndroidViewModel>()
- val myViewModel by viewModels<MyViewModel>()
- val myInjectedViewModel by viewModels<MyInjectedViewModel>()
- val myNestedInjectedViewModel by viewModels<TopClass.MyNestedInjectedViewModel>()
- val myInjectedViewModelWithSavedState by viewModels<MyInjectedViewModelWithSavedState>()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/BaseActivityInjectionTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/BaseActivityInjectionTest.kt
deleted file mode 100644
index 7ac4ebf..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/BaseActivityInjectionTest.kt
+++ /dev/null
@@ -1,57 +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.simpleKotlin.viewmodel
-
-import androidx.activity.viewModels
-import androidx.fragment.app.FragmentActivity
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class BaseActivityInjectionTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun verifyInjection() {
- ActivityScenario.launch(TestActivity::class.java).use {
- it.onActivity { activity ->
- assertThat(activity.myAndroidViewModel).isNotNull()
- assertThat(activity.myViewModel).isNotNull()
- assertThat(activity.myInjectedViewModel).isNotNull()
- }
- }
- }
-
- @AndroidEntryPoint
- class TestActivity : BaseActivity()
-
- abstract class BaseActivity : FragmentActivity() {
- val myAndroidViewModel by viewModels<MyAndroidViewModel>()
- val myViewModel by viewModels<MyViewModel>()
- val myInjectedViewModel by viewModels<MyInjectedViewModel>()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/BaseFragmentInjectionTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/BaseFragmentInjectionTest.kt
deleted file mode 100644
index 679a0d9..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/BaseFragmentInjectionTest.kt
+++ /dev/null
@@ -1,68 +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.simpleKotlin.viewmodel
-
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.viewModels
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class BaseFragmentInjectionTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun verifyInjection() {
- ActivityScenario.launch(TestActivity::class.java).use {
- it.onActivity { activity ->
- val fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
- TestFragment::class.java.classLoader!!,
- TestFragment::class.java.name
- ) as TestFragment
- activity.supportFragmentManager.beginTransaction()
- .add(0, fragment, FragmentInjectionTest.FRAGMENT_TAG)
- .commitNow()
- assertThat(fragment.myAndroidViewModel).isNotNull()
- assertThat(fragment.myViewModel).isNotNull()
- assertThat(fragment.myInjectedViewModel).isNotNull()
- }
- }
- }
-
- @AndroidEntryPoint
- class TestActivity : FragmentActivity()
-
- @AndroidEntryPoint
- class TestFragment : BaseFragment()
-
- abstract class BaseFragment : Fragment() {
- val myAndroidViewModel by viewModels<MyAndroidViewModel>()
- val myViewModel by viewModels<MyViewModel>()
- val myInjectedViewModel by viewModels<MyInjectedViewModel>()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/Bindings.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/Bindings.kt
deleted file mode 100644
index 480aea1..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/Bindings.kt
+++ /dev/null
@@ -1,36 +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.simpleKotlin.viewmodel
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import javax.inject.Inject
-import javax.inject.Named
-
-class Foo @Inject constructor()
-
-class Bar
-
-@Module
-@InstallIn(SingletonComponent::class)
-object StringModule {
- @Provides
- @Named("SayMyName")
- fun provide() = "Heisenberg"
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/FragmentInjectionTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/FragmentInjectionTest.kt
deleted file mode 100644
index 8d98e92..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/FragmentInjectionTest.kt
+++ /dev/null
@@ -1,129 +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.simpleKotlin.viewmodel
-
-import android.os.Bundle
-import androidx.activity.viewModels
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.activityViewModels
-import androidx.fragment.app.viewModels
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@LargeTest
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class FragmentInjectionTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun verifyInjection() {
- ActivityScenario.launch(TestActivity::class.java).use {
- it.onActivity { activity ->
- activity.addTestFragment()
- activity.supportFragmentManager.findTestFragment().let { fragment ->
- assertThat(fragment.myAndroidViewModel).isNotNull()
- assertThat(fragment.myViewModel).isNotNull()
- assertThat(fragment.myInjectedViewModel).isNotNull()
- assertThat(fragment.myInjectedViewModelWithSavedState).isNotNull()
- }
- }
- }
- }
-
- @Test
- fun verifyActivityViewModelInjection() {
- ActivityScenario.launch(TestActivity::class.java).use {
- it.onActivity { activity ->
- activity.addTestFragment()
- activity.supportFragmentManager.findTestFragment().let { fragment ->
- assertThat(fragment.myInjectedViewModel).isNotNull()
- assertThat(fragment.myActivityLevelInjectedViewModel).isNotNull()
- assertThat(fragment.myInjectedViewModel)
- .isNotEqualTo(fragment.myActivityLevelInjectedViewModel)
- assertThat(fragment.myActivityLevelInjectedViewModel)
- .isEqualTo(activity.myInjectedViewModel)
- }
- activity.removeTestFragment()
- activity.addTestFragment()
- activity.supportFragmentManager.findTestFragment().let { fragment ->
- assertThat(fragment.myInjectedViewModel).isNotNull()
- assertThat(fragment.myActivityLevelInjectedViewModel).isNotNull()
- assertThat(fragment.myInjectedViewModel)
- .isNotEqualTo(fragment.myActivityLevelInjectedViewModel)
- assertThat(fragment.myActivityLevelInjectedViewModel)
- .isEqualTo(activity.myInjectedViewModel)
- }
- }
- }
- }
-
- @AndroidEntryPoint
- class TestActivity : FragmentActivity() {
-
- val myInjectedViewModel by viewModels<MyInjectedViewModel>()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- addTestFragment()
- }
-
- fun addTestFragment() {
- val fragment = supportFragmentManager.fragmentFactory.instantiate(
- TestFragment::class.java.classLoader!!,
- TestFragment::class.java.name
- )
- supportFragmentManager.beginTransaction()
- .add(0, fragment, FRAGMENT_TAG)
- .commitNow()
- }
-
- fun removeTestFragment() {
- supportFragmentManager.beginTransaction()
- .remove(supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)!!)
- .commitNow()
- }
- }
-
- @AndroidEntryPoint
- class TestFragment : Fragment() {
- val myAndroidViewModel by viewModels<MyAndroidViewModel>()
- val myViewModel by viewModels<MyViewModel>()
- val myInjectedViewModel by viewModels<MyInjectedViewModel>()
- val myInjectedViewModelWithSavedState by viewModels<MyInjectedViewModelWithSavedState>()
- val myActivityLevelInjectedViewModel by activityViewModels<MyInjectedViewModel>()
- }
-
- private fun FragmentManager.findTestFragment() =
- findFragmentByTag(FRAGMENT_TAG) as TestFragment
-
- companion object {
- const val FRAGMENT_TAG = "tag"
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/MyViewModels.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/MyViewModels.kt
deleted file mode 100644
index c24c6b7..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/MyViewModels.kt
+++ /dev/null
@@ -1,49 +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.simpleKotlin.viewmodel
-
-import android.app.Application
-import androidx.lifecycle.AndroidViewModel
-import androidx.lifecycle.SavedStateHandle
-import androidx.lifecycle.ViewModel
-import dagger.hilt.android.lifecycle.HiltViewModel
-import javax.inject.Inject
-import javax.inject.Named
-
-class MyAndroidViewModel(app: Application) : AndroidViewModel(app)
-
-class MyViewModel() : ViewModel()
-
-@Suppress("UNUSED_PARAMETER")
-@HiltViewModel
-class MyInjectedViewModel @Inject constructor(
- foo: Foo,
- @Named("SayMyName") theName: String
-) : ViewModel()
-
-object TopClass {
- @Suppress("UNUSED_PARAMETER")
- @HiltViewModel
- class MyNestedInjectedViewModel @Inject constructor(foo: Foo) : ViewModel()
-}
-
-@Suppress("UNUSED_PARAMETER")
-@HiltViewModel
-class MyInjectedViewModelWithSavedState @Inject constructor(
- foo: Foo,
- handle: SavedStateHandle
-) : ViewModel()
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/ViewModelScopedTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/ViewModelScopedTest.kt
deleted file mode 100644
index cdf6a65..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/androidTest/java/dagger/hilt/android/simpleKotlin/viewmodel/ViewModelScopedTest.kt
+++ /dev/null
@@ -1,106 +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.simpleKotlin.viewmodel
-
-import android.os.Bundle
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
-import androidx.fragment.app.FragmentManager
-import androidx.fragment.app.viewModels
-import androidx.lifecycle.ViewModel
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.components.ViewModelComponent
-import dagger.hilt.android.lifecycle.HiltViewModel
-import dagger.hilt.android.scopes.ViewModelScoped
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import javax.inject.Inject
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class ViewModelScopedTest {
-
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun testViewModelScopeInFragment() {
- ActivityScenario.launch(TestActivity::class.java).use {
- it.onActivity { activity ->
- activity.supportFragmentManager.findTestFragment().let { fragment ->
- val vm = fragment.vm
- assertThat(vm.one.bar).isEqualTo(vm.two.bar)
- }
- }
- }
- }
-
- @Module
- @InstallIn(ViewModelComponent::class)
- object ScopedModule {
- @Provides
- @ViewModelScoped
- fun provideBar() = Bar()
- }
-
- @AndroidEntryPoint
- class TestActivity : FragmentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- if (savedInstanceState == null) {
- val fragment = supportFragmentManager.fragmentFactory.instantiate(
- TestFragment::class.java.classLoader!!,
- TestFragment::class.java.name
- )
- supportFragmentManager.beginTransaction()
- .add(0, fragment, FRAGMENT_TAG)
- .commitNow()
- }
- }
- }
-
- @AndroidEntryPoint
- class TestFragment : Fragment() {
- val vm by viewModels<TestViewModel>()
- }
-
- @HiltViewModel
- class TestViewModel @Inject constructor(
- val one: DependsOnBarOne,
- val two: DependsOnBarTwo
- ) : ViewModel()
-
- class DependsOnBarOne @Inject constructor(val bar: Bar)
- class DependsOnBarTwo @Inject constructor(val bar: Bar)
-
- private fun FragmentManager.findTestFragment() =
- findFragmentByTag(FRAGMENT_TAG) as TestFragment
-
- companion object {
- const val FRAGMENT_TAG = "tag"
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/debug/AndroidManifest.xml b/javatests/artifacts/hilt-android/simpleKotlin/app/src/debug/AndroidManifest.xml
deleted file mode 100644
index 0a0270e..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simpleKotlin">
-
- <application>
- <activity android:name=".SimpleTest$TestActivity" android:exported="false"/>
- <activity android:name=".viewmodel.ActivityInjectionTest$TestActivity" android:exported="false"/>
- <activity android:name=".viewmodel.BaseActivityInjectionTest$TestActivity" android:exported="false"/>
- <activity android:name=".viewmodel.FragmentInjectionTest$TestActivity" android:exported="false"/>
- <activity android:name=".viewmodel.BaseFragmentInjectionTest$TestActivity" android:exported="false"/>
- <activity android:name=".viewmodel.ViewModelScopedTest$TestActivity" android:exported="false"/>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/AndroidManifest.xml
deleted file mode 100644
index ca700b2..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simpleKotlin">
-
- <application
- android:name=".KotlinApplication"
- android:allowBackup="true"
- android:label="@string/app_name"
- android:supportsRtl="true"
- android:theme="@style/Theme.AppCompat.Light">
- <activity android:name=".MainActivity" android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
-
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/ActivityRetainedModule.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/ActivityRetainedModule.kt
deleted file mode 100644
index b830f31..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/ActivityRetainedModule.kt
+++ /dev/null
@@ -1,31 +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.simpleKotlin
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.android.components.ActivityRetainedComponent
-
-@Module
-@InstallIn(ActivityRetainedComponent::class)
-object ActivityRetainedModule {
- @UserName
- @Provides
- fun provideUserName(): String {
- return "Android User"
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/ApplicationModule.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/ApplicationModule.kt
deleted file mode 100644
index 59b79bb..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/ApplicationModule.kt
+++ /dev/null
@@ -1,33 +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.simpleKotlin
-
-import android.os.Build
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-
-@Module
-@InstallIn(SingletonComponent::class)
-object ApplicationModule {
- @Provides
- @Model
- fun provideModel(): String {
- return Build.MODEL
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/DefinedStrings.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/DefinedStrings.kt
deleted file mode 100644
index b22e588..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/DefinedStrings.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2021 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package dagger.hilt.android.simpleKotlin
-
-object DefinedStrings {
- internal val morningSweet = "Mallorca"
- internal fun getInternalSweet() = "Sugar Donuts"
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/KotlinApplication.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/KotlinApplication.kt
deleted file mode 100644
index c638706..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/KotlinApplication.kt
+++ /dev/null
@@ -1,30 +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.simpleKotlin
-
-import android.app.Application
-import dagger.hilt.android.HiltAndroidApp
-import javax.inject.Inject
-
-@HiltAndroidApp
-class KotlinApplication : Application() {
- // Shows that we can inject ApplicationComponent bindings into an application.
- @Inject
- @Model
- @JvmField
- var model: String? = null
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/MainActivity.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/MainActivity.kt
deleted file mode 100644
index bd7f8a7..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/MainActivity.kt
+++ /dev/null
@@ -1,48 +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.simpleKotlin
-
-import android.os.Bundle
-import android.view.View
-import android.widget.TextView
-import androidx.activity.viewModels
-import androidx.appcompat.app.AppCompatActivity
-import androidx.lifecycle.ViewModel
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.lifecycle.HiltViewModel
-import javax.inject.Inject
-
-@AndroidEntryPoint
-class MainActivity : AppCompatActivity() {
-
- val viewModel by viewModels<MainViewModel>()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- val greeting = findViewById<View>(R.id.greeting) as TextView
- val text = resources.getString(R.string.welcome, viewModel.name, viewModel.model)
- greeting.text = text
- }
-
- // Shows that we can inject bindings into a ViewModel
- @HiltViewModel
- class MainViewModel @Inject constructor(
- @Model val model: String,
- @UserName val name: String
- ) : ViewModel()
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/Model.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/Model.kt
deleted file mode 100644
index 7e7e9ae..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/Model.kt
+++ /dev/null
@@ -1,24 +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.simpleKotlin
-
-import javax.inject.Qualifier
-
-/** Qualifies bindings relating to [android.os.Build.MODEL]. */
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class Model
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/UserName.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/UserName.kt
deleted file mode 100644
index 352e48c..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/java/dagger/hilt/android/simpleKotlin/UserName.kt
+++ /dev/null
@@ -1,24 +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.simpleKotlin
-
-import javax.inject.Qualifier
-
-/** Qualifies bindings relating to the user name. */
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class UserName
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/res/layout/activity_main.xml b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 0d7637d..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/background_light">
-
- <TextView
- android:id="@+id/greeting"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:textColor="@android:color/primary_text_light"
- />
-</RelativeLayout>
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/res/values/strings.xml b/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/res/values/strings.xml
deleted file mode 100644
index c1e4f27..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,23 +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.
- -->
-
-<resources>
- <!--The app name [CHAR_LIMIT=40]-->
- <string name="app_name">Simple Hilt Kotlin Android App</string>
-
- <!--The greeting message [CHAR_LIMIT=100]-->
- <string name="welcome">Hello, %1$s! You are on build %2$s.</string>
-</resources>
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/InternalAccessTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/InternalAccessTest.kt
deleted file mode 100644
index 43a1abc..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/InternalAccessTest.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2021 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package dagger.hilt.android.simpleKotlin
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Verifies internal Kotlin classes are accessible with classpath aggregation.
- */
-@RunWith(AndroidJUnit4::class)
-class InternalAccessTest {
- @Test
- fun verifyInternalMembersAreAccessible() {
- assertThat(DefinedStrings.morningSweet).isNotNull()
- assertThat(DefinedStrings.getInternalSweet()).isNotNull()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/TransitiveDependenciesTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/TransitiveDependenciesTest.kt
deleted file mode 100644
index 10e6515..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/sharedTest/java/dagger/hilt/android/simpleKotlin/TransitiveDependenciesTest.kt
+++ /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 dagger.hilt.android.simpleKotlin
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import dagger.hilt.android.simpleKotlin.lib.AndroidLibraryEntryPoints
-import dagger.hilt.android.simpleKotlin.lib.KotlinLibraryEntryPoints
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Tests that entry points in deep dependencies with `implementation` boundaries are available at
- * runtime.
- */
-@HiltAndroidTest
-@RunWith(AndroidJUnit4::class)
-class TransitiveDependenciesTest {
- @get:Rule
- val rule = HiltAndroidRule(this)
-
- @Test
- fun testEntryPointFromAndroidLib() {
- AndroidLibraryEntryPoints.invokeEntryPoints(
- InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
- )
- }
-
- @Test
- fun testEntryPointFromKotlinLib() {
- KotlinLibraryEntryPoints.invokeEntryPoints(
- InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
- )
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt
deleted file mode 100644
index 1e04606..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/java/dagger/hilt/android/simpleKotlin/SimpleTest.kt
+++ /dev/null
@@ -1,83 +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.simpleKotlin
-
-import android.os.Build
-import androidx.appcompat.app.AppCompatActivity
-import androidx.test.core.app.ActivityScenario
-import com.google.common.truth.Truth.assertThat
-import dagger.hilt.android.AndroidEntryPoint
-import dagger.hilt.android.testing.BindValue
-import dagger.hilt.android.testing.HiltAndroidRule
-import dagger.hilt.android.testing.HiltAndroidTest
-import dagger.hilt.android.testing.HiltTestApplication
-import javax.inject.Inject
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.annotation.Config
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@HiltAndroidTest
-@RunWith(RobolectricTestRunner::class)
-// Robolectric requires Java9 to run API 29 and above, so use API 28 instead
-@Config(sdk = [Build.VERSION_CODES.P], application = HiltTestApplication::class)
-class SimpleTest {
- @get:Rule val rule = HiltAndroidRule(this)
-
- @BindValue val bindStr = "STRING_BINDING"
-
- @Inject @JvmField
- var str: String? = null
-
- @AndroidEntryPoint
- class TestActivity : AppCompatActivity()
-
- @Test
- fun testBindValue() {
- assertThat(str).isNull()
- rule.inject()
- assertThat(str).isEqualTo(bindStr)
- }
-
- @Test
- fun verifyMainActivity() {
- ActivityScenario.launch(MainActivity::class.java).use { scenario ->
- scenario.onActivity { activity ->
- assertThat(activity::class.java.getSuperclass()?.getSimpleName())
- .isEqualTo("Hilt_MainActivity")
- assertThat(activity.viewModel.model).isNotNull()
- assertThat(activity.viewModel.name).isNotNull()
- }
- }
- }
-
- @Test
- fun verifyTestActivity() {
- ActivityScenario.launch(TestActivity::class.java).use { scenario ->
- scenario.onActivity { activity ->
- assertThat(activity::class.java.getSuperclass()?.getSimpleName())
- .isEqualTo("Hilt_SimpleTest_TestActivity")
- }
- }
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/resources/dagger/hilt/android/simpleKotlin/robolectric.properties b/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/resources/dagger/hilt/android/simpleKotlin/robolectric.properties
deleted file mode 100644
index 0234ffe..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/app/src/test/resources/dagger/hilt/android/simpleKotlin/robolectric.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-sdk=28
-application=dagger.hilt.android.testing.HiltTestApplication
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
deleted file mode 100644
index d594476..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/build.gradle
+++ /dev/null
@@ -1,41 +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.
- */
-
-buildscript {
- ext {
- kotlin_version = '1.3.61'
- agp_version = System.getenv('AGP_VERSION') ?: "4.2.0-beta04"
- }
- repositories {
- google()
- jcenter()
- mavenLocal()
- }
- dependencies {
- classpath "com.android.tools.build:gradle:$agp_version"
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
- classpath 'com.google.dagger:hilt-android-gradle-plugin:LOCAL-SNAPSHOT'
- }
-}
-
-allprojects {
- repositories {
- google()
- jcenter()
- mavenCentral()
- mavenLocal()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
deleted file mode 100644
index 3a1923a..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/build.gradle
+++ /dev/null
@@ -1,46 +0,0 @@
-plugins {
- id 'com.android.library'
- id 'kotlin-android'
- id 'kotlin-kapt'
- id 'dagger.hilt.android.plugin'
-}
-
-android {
- compileSdkVersion 30
- buildToolsVersion "30.0.2"
-
- defaultConfig {
- minSdkVersion 15
- targetSdkVersion 30
- versionCode 1
- versionName "1.0"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
- lintOptions {
- checkReleaseBuilds = false
- }
-}
-
-dependencies {
- implementation 'com.google.dagger:hilt-android:LOCAL-SNAPSHOT'
- kapt 'com.google.dagger:hilt-compiler:LOCAL-SNAPSHOT'
-
- testImplementation 'androidx.test.ext:junit:1.1.2'
- testImplementation 'com.google.truth:truth:1.0.1'
-
- androidTestImplementation 'androidx.test.ext:junit:1.1.2'
- androidTestImplementation 'androidx.test:runner:1.3.0'
- androidTestImplementation 'com.google.truth:truth:1.0.1'
-}
-
-hilt {
- enableExperimentalClasspathAggregation = true
-}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/androidTest/java/dagger/hilt/android/simpleKotlin/deep/InternalAccessEmulatorTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/androidTest/java/dagger/hilt/android/simpleKotlin/deep/InternalAccessEmulatorTest.kt
deleted file mode 100644
index 4ea4c09..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/androidTest/java/dagger/hilt/android/simpleKotlin/deep/InternalAccessEmulatorTest.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package dagger.hilt.android.simpleKotlin.deep
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-/**
- * Verifies internal Kotlin classes are accessible with classpath aggregation in Android library.
- */
-@RunWith(AndroidJUnit4::class)
-class InternalAccessEmulatorTest {
- @Test
- fun verifyInternalMembersAreAccessible() {
- assertThat(DeepAndroidLib.internalFunction()).isNotNull()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/main/AndroidManifest.xml b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/main/AndroidManifest.xml
deleted file mode 100644
index ae2a5e3..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="dagger.hilt.android.simpleKotlin.deep">
-
-</manifest>
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/main/java/dagger/hilt/android/simpleKotlin/deep/DeepAndroidLib.kt b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/main/java/dagger/hilt/android/simpleKotlin/deep/DeepAndroidLib.kt
deleted file mode 100644
index a2fcb73..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/main/java/dagger/hilt/android/simpleKotlin/deep/DeepAndroidLib.kt
+++ /dev/null
@@ -1,40 +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.simpleKotlin.deep
-
-import android.content.Context
-import dagger.hilt.EntryPoint
-import dagger.hilt.InstallIn
-import dagger.hilt.android.EntryPointAccessors
-import dagger.hilt.components.SingletonComponent
-import javax.inject.Inject
-
-class DeepAndroidLib @Inject constructor() {
- @EntryPoint
- @InstallIn(SingletonComponent::class)
- internal interface LibEntryPoint {
- fun getDeepAndroidInstance(): DeepAndroidLib
- }
-
- companion object {
- fun getInstance(context: Context) =
- EntryPointAccessors.fromApplication(context, LibEntryPoint::class.java)
- .getDeepAndroidInstance()
-
- internal fun internalFunction() = Any()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/test/java/dagger/hilt/android/simpleKotlin/deep/InternalAccessLocalTest.kt b/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/test/java/dagger/hilt/android/simpleKotlin/deep/InternalAccessLocalTest.kt
deleted file mode 100644
index 508e7d5..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-android-lib/src/test/java/dagger/hilt/android/simpleKotlin/deep/InternalAccessLocalTest.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2021 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package dagger.hilt.android.simpleKotlin.deep
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/**
- * Verifies internal Kotlin classes are accessible with classpath aggregation in Android library.
- */
-class InternalAccessLocalTest {
- @Test
- fun verifyInternalMembersAreAccessible() {
- assertThat(DeepAndroidLib.internalFunction()).isNotNull()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle
deleted file mode 100644
index 306c171..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-plugins {
- id 'java-library'
- id 'kotlin'
- id 'kotlin-kapt'
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
-}
-
-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"
-}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/src/main/java/dagger/hilt/android/simpleKotlin/deep/DeepLib.kt b/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/src/main/java/dagger/hilt/android/simpleKotlin/deep/DeepLib.kt
deleted file mode 100644
index 0d2bc61..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/deep-kotlin-lib/src/main/java/dagger/hilt/android/simpleKotlin/deep/DeepLib.kt
+++ /dev/null
@@ -1,36 +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.simpleKotlin.deep
-
-import dagger.hilt.EntryPoint
-import dagger.hilt.EntryPoints
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import javax.inject.Inject
-
-class DeepLib @Inject constructor() {
- @EntryPoint
- @InstallIn(SingletonComponent::class)
- internal interface LibEntryPoint {
- fun getDeepInstance(): DeepLib
- }
-
- companion object {
- fun getInstance(componentManager: Any) =
- EntryPoints.get(componentManager, LibEntryPoint::class.java)
- .getDeepInstance()
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties b/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties
deleted file mode 100644
index 646c51b..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-android.useAndroidX=true
-android.enableJetifier=true
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.jar b/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index 5c2d1cf..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.jar
+++ /dev/null
Binary files differ
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties b/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/gradlew b/javatests/artifacts/hilt-android/simpleKotlin/gradlew
deleted file mode 100755
index b0d6d0a..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/gradlew
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/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/hilt-android/simpleKotlin/kotlin-library/build.gradle b/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/build.gradle
deleted file mode 100644
index 7c8462f..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/build.gradle
+++ /dev/null
@@ -1,17 +0,0 @@
-plugins {
- id 'java-library'
- id 'kotlin'
- id 'kotlin-kapt'
-}
-
-java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
-}
-
-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"
-}
\ No newline at end of file
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/src/main/java/dagger/hilt/android/simpleKotlin/lib/KotlinLibraryEntryPoints.kt b/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/src/main/java/dagger/hilt/android/simpleKotlin/lib/KotlinLibraryEntryPoints.kt
deleted file mode 100644
index 8989ebb..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/kotlin-library/src/main/java/dagger/hilt/android/simpleKotlin/lib/KotlinLibraryEntryPoints.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package dagger.hilt.android.simpleKotlin.lib
-
-import dagger.hilt.android.simpleKotlin.deep.DeepLib
-
-object KotlinLibraryEntryPoints {
- fun invokeEntryPoints(component: Any) {
- DeepLib.getInstance(component)
- }
-}
diff --git a/javatests/artifacts/hilt-android/simpleKotlin/settings.gradle b/javatests/artifacts/hilt-android/simpleKotlin/settings.gradle
deleted file mode 100644
index cea0913..0000000
--- a/javatests/artifacts/hilt-android/simpleKotlin/settings.gradle
+++ /dev/null
@@ -1,6 +0,0 @@
-rootProject.name='Simple Kotlin Hilt Android'
-include ':app'
-include ':android-library'
-include ':kotlin-library'
-include ':deep-android-lib'
-include ':deep-kotlin-lib'
diff --git a/javatests/dagger/BUILD b/javatests/dagger/BUILD
index c6ab360..3debec5 100644
--- a/javatests/dagger/BUILD
+++ b/javatests/dagger/BUILD
@@ -15,11 +15,11 @@
# Description:
# A JSR-330 compliant dependency injection system for android and java
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "DOCLINT_REFERENCES")
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "core_tests",
srcs = glob(["**/*.java"]),
@@ -27,8 +27,7 @@
javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//java/dagger:core",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr330_inject",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/truth",
diff --git a/javatests/dagger/android/AndroidInjectionTest.java b/javatests/dagger/android/AndroidInjectionTest.java
index 7e60ebd..19b6e84 100644
--- a/javatests/dagger/android/AndroidInjectionTest.java
+++ b/javatests/dagger/android/AndroidInjectionTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-import static org.robolectric.annotation.LooperMode.Mode.LEGACY;
import android.app.Activity;
import android.app.Application;
@@ -28,10 +27,9 @@
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.LooperMode;
import org.robolectric.util.FragmentTestUtil;
-@LooperMode(LEGACY)
+@Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class)
public final class AndroidInjectionTest {
@@ -41,7 +39,7 @@
String tag;
}
- private static AndroidInjector<Object> fakeFragmentInjector(String tag) {
+ private static AndroidInjector<Fragment> fakeFragmentInjector(String tag) {
return instance -> {
if (instance instanceof InjectableFragment) {
((InjectableFragment) instance).tag = tag;
@@ -49,14 +47,15 @@
};
}
- public static class ApplicationInjectsFragment extends Application implements HasAndroidInjector {
+ public static class ApplicationInjectsFragment extends Application
+ implements HasFragmentInjector {
@Override
- public AndroidInjector<Object> androidInjector() {
+ public AndroidInjector<Fragment> fragmentInjector() {
return fakeFragmentInjector("injected by app");
}
}
- @Config(application = ApplicationInjectsFragment.class)
+ @Config(manifest = Config.NONE, application = ApplicationInjectsFragment.class)
@Test
public void fragmentInjectedByApplication() {
Activity activity = Robolectric.setupActivity(Activity.class);
@@ -68,14 +67,14 @@
assertThat(fragment.tag).isEqualTo("injected by app");
}
- public static class ActivityInjectsFragment extends Activity implements HasAndroidInjector {
+ public static class ActivityInjectsFragment extends Activity implements HasFragmentInjector {
@Override
- public AndroidInjector<Object> androidInjector() {
+ public AndroidInjector<Fragment> fragmentInjector() {
return fakeFragmentInjector("injected by activity");
}
}
- @Config(application = ApplicationInjectsFragment.class)
+ @Config(manifest = Config.NONE, application = ApplicationInjectsFragment.class)
@Test
public void fragmentInjectedByActivity() {
ActivityInjectsFragment activity = Robolectric.setupActivity(ActivityInjectsFragment.class);
@@ -88,14 +87,14 @@
}
public static class ParentFragmentInjectsChildFragment extends Fragment
- implements HasAndroidInjector {
+ implements HasFragmentInjector {
@Override
- public AndroidInjector<Object> androidInjector() {
+ public AndroidInjector<Fragment> fragmentInjector() {
return fakeFragmentInjector("injected by parent fragment");
}
}
- @Config(application = ApplicationInjectsFragment.class)
+ @Config(manifest = Config.NONE, application = ApplicationInjectsFragment.class)
@Test
public void fragmentInjectedByParentFragment() {
ActivityInjectsFragment activity = Robolectric.setupActivity(ActivityInjectsFragment.class);
@@ -114,7 +113,7 @@
}
@Test
- public void injectActivity_applicationDoesntImplementHasAndroidInjector() {
+ public void injectActivity_applicationDoesntImplementHasActivityInjector() {
Activity activity = Robolectric.setupActivity(Activity.class);
try {
@@ -140,15 +139,21 @@
}
}
- private static class ApplicationReturnsNull extends Application implements HasAndroidInjector {
+ private static class ApplicationReturnsNull extends Application
+ implements HasActivityInjector, HasFragmentInjector {
@Override
- public AndroidInjector<Object> androidInjector() {
+ public AndroidInjector<Activity> activityInjector() {
+ return null;
+ }
+
+ @Override
+ public AndroidInjector<Fragment> fragmentInjector() {
return null;
}
}
@Test
- @Config(application = ApplicationReturnsNull.class)
+ @Config(manifest = Config.NONE, application = ApplicationReturnsNull.class)
public void activityInjector_returnsNull() {
Activity activity = Robolectric.setupActivity(Activity.class);
@@ -156,12 +161,12 @@
AndroidInjection.inject(activity);
fail();
} catch (Exception e) {
- assertThat(e).hasMessageThat().contains("androidInjector() returned null");
+ assertThat(e).hasMessageThat().contains("activityInjector() returned null");
}
}
@Test
- @Config(application = ApplicationReturnsNull.class)
+ @Config(manifest = Config.NONE, application = ApplicationReturnsNull.class)
public void fragmentInjector_returnsNull() {
Fragment fragment = new Fragment();
FragmentTestUtil.startFragment(fragment);
@@ -170,7 +175,7 @@
AndroidInjection.inject(fragment);
fail();
} catch (Exception e) {
- assertThat(e).hasMessageThat().contains("androidInjector() returned null");
+ assertThat(e).hasMessageThat().contains("fragmentInjector() returned null");
}
}
diff --git a/javatests/dagger/android/AndroidProguardTest.java b/javatests/dagger/android/AndroidProguardTest.java
deleted file mode 100644
index 0f51e49..0000000
--- a/javatests/dagger/android/AndroidProguardTest.java
+++ /dev/null
@@ -1,57 +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.android;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.android.internal.AndroidInjectionKeys;
-import java.net.URL;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class AndroidProguardTest {
-
- @Test
- public void checkLegacyProguardRules() {
- URL resUrl =
- AndroidInjectionKeys.class
- .getClassLoader()
- .getResource("META-INF/proguard/dagger-android.pro");
- assertThat(resUrl).isNotNull();
- }
-
- // The com.android.tools files are only used outside Google, in Gradle projects.
- @Test
- public void checkProguardRules() {
- URL resUrl =
- AndroidInjectionKeys.class
- .getClassLoader()
- .getResource("META-INF/com.android.tools/proguard/dagger-android.pro");
- assertThat(resUrl).isNotNull();
- }
-
- @Test
- public void checkR8Rules() {
- URL resUrl =
- AndroidInjectionKeys.class
- .getClassLoader()
- .getResource("META-INF/com.android.tools/r8/dagger-android.pro");
- assertThat(resUrl).isNotNull();
- }
-}
diff --git a/javatests/dagger/android/BUILD b/javatests/dagger/android/BUILD
index 38efb3a..5bc3f45 100644
--- a/javatests/dagger/android/BUILD
+++ b/javatests/dagger/android/BUILD
@@ -15,11 +15,11 @@
# Description:
# Tests for Dagger's Android integrations
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenRobolectricTests")
-package(default_visibility = ["//:src"])
-
GenRobolectricTests(
name = "android_tests",
srcs = glob(["*.java"]),
@@ -29,7 +29,7 @@
deps = [
"//:dagger_with_compiler",
"//java/dagger/android",
- "//java/dagger/internal/guava:collect",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/truth",
],
diff --git a/javatests/dagger/android/DispatchingAndroidInjectorTest.java b/javatests/dagger/android/DispatchingAndroidInjectorTest.java
index 37d3d61..d0306b8 100644
--- a/javatests/dagger/android/DispatchingAndroidInjectorTest.java
+++ b/javatests/dagger/android/DispatchingAndroidInjectorTest.java
@@ -29,7 +29,9 @@
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+@Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class)
public final class DispatchingAndroidInjectorTest {
@Test
diff --git a/javatests/dagger/android/processor/AndroidProcessorTest.java b/javatests/dagger/android/processor/AndroidProcessorTest.java
new file mode 100644
index 0000000..1a45bdd
--- /dev/null
+++ b/javatests/dagger/android/processor/AndroidProcessorTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.android.processor;
+
+import static com.google.common.truth.Truth8.assertThat;
+import static com.google.testing.compile.CompilationSubject.assertThat;
+import static com.google.testing.compile.Compiler.javac;
+import static javax.tools.StandardLocation.CLASS_OUTPUT;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AndroidProcessorTest {
+ @Test
+ public void generatedProguardFile() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.android.AndroidInjectionKey;",
+ "import dagger.Module;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides",
+ " @IntoMap",
+ " @AndroidInjectionKey(\"test.TestActivity\")",
+ " static int i() { ",
+ " return 1;",
+ " }",
+ "}");
+ Compilation enabled =
+ javac()
+ .withProcessors(new AndroidProcessor())
+ .withOptions("-Adagger.android.experimentalUseStringKeys=true")
+ .compile(module);
+ assertThat(enabled).succeeded();
+ assertThat(enabled)
+ .generatedFile(CLASS_OUTPUT, "META-INF/proguard/dagger.android.AndroidInjectionKeys");
+
+ Compilation disabled =
+ javac()
+ .withProcessors(new AndroidProcessor())
+ .withOptions("-Adagger.android.experimentalUseStringKeys=false")
+ .compile(module);
+ assertThat(disabled).succeeded();
+ assertThat(
+ disabled.generatedFile(
+ CLASS_OUTPUT, "META-INF/proguard/dagger.android.AndroidInjectionKeys"))
+ .isEmpty();
+
+ Compilation noFlag = javac().withProcessors(new AndroidProcessor()).compile(module);
+ assertThat(noFlag).succeeded();
+ assertThat(
+ noFlag.generatedFile(
+ CLASS_OUTPUT, "META-INF/proguard/dagger.android.AndroidInjectionKeys"))
+ .isEmpty();
+ }
+}
diff --git a/javatests/dagger/android/processor/BUILD b/javatests/dagger/android/processor/BUILD
index d7b210c..8a9c16e 100644
--- a/javatests/dagger/android/processor/BUILD
+++ b/javatests/dagger/android/processor/BUILD
@@ -15,27 +15,28 @@
# Description:
# Tests for Dagger's Android integrations
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "android_processor_tests",
srcs = glob(["*.java"]),
functional = False,
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
+ "@google_bazel_common//third_party/java/guava",
+ "@androidsdk//com.android.support:support-fragment-25.0.0",
+ # TODO(ronshapiro): create a common location to define the current Android version
+ "@androidsdk//:platforms/android-26/android.jar",
+ "@google_bazel_common//third_party/java/compile_testing",
"//:dagger_with_compiler",
+ "@google_bazel_common//third_party/java/junit",
+ "@google_bazel_common//third_party/java/truth",
+ "@google_bazel_common//third_party/java/truth:truth8",
"//java/dagger/android",
"//java/dagger/android/processor",
"//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@androidsdk//:platforms/android-30/android.jar",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:androidx_fragment_fragment",
],
)
diff --git a/javatests/dagger/android/support/AndroidSupportInjectionTest.java b/javatests/dagger/android/support/AndroidSupportInjectionTest.java
index 25c5e94..51e9992 100644
--- a/javatests/dagger/android/support/AndroidSupportInjectionTest.java
+++ b/javatests/dagger/android/support/AndroidSupportInjectionTest.java
@@ -20,15 +20,15 @@
import static org.junit.Assert.fail;
import android.app.Application;
-import androidx.fragment.app.Fragment;
+import android.support.v4.app.Fragment;
import dagger.android.AndroidInjector;
-import dagger.android.HasAndroidInjector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.support.v4.SupportFragmentTestUtil;
+@Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class)
public final class AndroidSupportInjectionTest {
@Test
@@ -45,15 +45,15 @@
}
private static class ApplicationReturnsNull extends Application
- implements HasAndroidInjector {
+ implements HasSupportFragmentInjector {
@Override
- public AndroidInjector<Object> androidInjector() {
+ public AndroidInjector<Fragment> supportFragmentInjector() {
return null;
}
}
@Test
- @Config(application = ApplicationReturnsNull.class)
+ @Config(manifest = Config.NONE, application = ApplicationReturnsNull.class)
public void fragmentInjector_returnsNull() {
Fragment fragment = new Fragment();
SupportFragmentTestUtil.startFragment(fragment);
@@ -62,7 +62,7 @@
AndroidSupportInjection.inject(fragment);
fail();
} catch (Exception e) {
- assertThat(e).hasMessageThat().contains("androidInjector() returned null");
+ assertThat(e).hasMessageThat().contains("supportFragmentInjector() returned null");
}
}
diff --git a/javatests/dagger/android/support/BUILD b/javatests/dagger/android/support/BUILD
index 6bbfaa1..6d8f43b 100644
--- a/javatests/dagger/android/support/BUILD
+++ b/javatests/dagger/android/support/BUILD
@@ -15,11 +15,11 @@
# Description:
# Tests for Dagger's Android and Support library integrations
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenRobolectricTests")
-package(default_visibility = ["//:src"])
-
GenRobolectricTests(
name = "android-support-tests",
srcs = glob(["*.java"]),
@@ -29,12 +29,10 @@
"//:dagger_with_compiler",
"//java/dagger/android",
"//java/dagger/android/support",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
+ "@androidsdk//com.android.support:appcompat-v7-25.0.0",
+ "@androidsdk//com.android.support:support-fragment-25.0.0",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/truth",
- "@maven//:androidx_appcompat_appcompat",
- "@maven//:androidx_fragment_fragment",
],
)
diff --git a/javatests/dagger/android/support/functional/AndroidManifest.xml b/javatests/dagger/android/support/functional/AndroidManifest.xml
index 0b5f4cd..2e40a35 100644
--- a/javatests/dagger/android/support/functional/AndroidManifest.xml
+++ b/javatests/dagger/android/support/functional/AndroidManifest.xml
@@ -16,8 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dagger.android.support.functional">
- <!-- Bump targetSdk to 29 when we update to Java 11 -->
- <uses-sdk android:minSdkVersion="1" android:targetSdkVersion="28" />
+ <uses-sdk android:minSdkVersion="1" android:targetSdkVersion="26" />
<application android:theme="@style/Theme.AppCompat"
android:name=".UsesGeneratedModulesApplication">
diff --git a/javatests/dagger/android/support/functional/BUILD b/javatests/dagger/android/support/functional/BUILD
index 1ae1108..130b971 100644
--- a/javatests/dagger/android/support/functional/BUILD
+++ b/javatests/dagger/android/support/functional/BUILD
@@ -15,8 +15,6 @@
# Description:
# Functional test code for Dagger-Android
-load("//:test_defs.bzl", "GenRobolectricTests")
-
package(default_visibility = ["//:src"])
android_library(
@@ -29,10 +27,9 @@
manifest = "AndroidManifest.xml",
resource_files = glob(["res/**"]),
deps = [
- "@maven//:androidx_fragment_fragment",
- "@maven//:androidx_appcompat_appcompat",
- "@maven//:androidx_annotation_annotation",
- "//java/dagger/internal/guava:collect-android",
+ "@androidsdk//com.android.support:support-fragment-25.0.0",
+ "@androidsdk//com.android.support:appcompat-v7-25.0.0",
+ "@google_bazel_common//third_party/java/guava",
"//:dagger_with_compiler",
"//:android",
"//:android-support",
@@ -41,6 +38,8 @@
],
)
+load("//:test_defs.bzl", "GenRobolectricTests")
+
GenRobolectricTests(
name = "functional_tests",
srcs = glob(["*Test.java"]),
@@ -49,9 +48,9 @@
"//:android",
"//:android-support",
"//:dagger_with_compiler",
+ "@androidsdk//com.android.support:support-fragment-25.0.0",
+ "@google_bazel_common//third_party/java/junit",
+ "@google_bazel_common//third_party/java/robolectric",
"@google_bazel_common//third_party/java/truth",
- "@maven//:androidx_fragment_fragment",
- "@maven//:junit_junit",
- "@maven//:org_robolectric_robolectric",
],
)
diff --git a/javatests/dagger/android/support/functional/InjectorsTest.java b/javatests/dagger/android/support/functional/InjectorsTest.java
index 73bb98a..c5cb150 100644
--- a/javatests/dagger/android/support/functional/InjectorsTest.java
+++ b/javatests/dagger/android/support/functional/InjectorsTest.java
@@ -20,12 +20,12 @@
import android.content.Intent;
import android.content.res.Configuration;
-import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
@@ -59,7 +59,7 @@
intentService = Robolectric.buildIntentService(TestIntentService.class).create().get();
broadcastReceiver = new TestBroadcastReceiver();
- broadcastReceiver.onReceive(ApplicationProvider.getApplicationContext(), new Intent());
+ broadcastReceiver.onReceive(RuntimeEnvironment.application, new Intent());
contentProvider = Robolectric.setupContentProvider(TestContentProvider.class);
}
diff --git a/javatests/dagger/android/support/functional/TestContentProvider.java b/javatests/dagger/android/support/functional/TestContentProvider.java
index aff8961..1668ce6 100644
--- a/javatests/dagger/android/support/functional/TestContentProvider.java
+++ b/javatests/dagger/android/support/functional/TestContentProvider.java
@@ -19,7 +19,7 @@
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
-import androidx.annotation.Nullable;
+import android.support.annotation.Nullable;
import dagger.android.DaggerContentProvider;
import java.util.Set;
import javax.inject.Inject;
diff --git a/javatests/dagger/functional/BUILD b/javatests/dagger/functional/BUILD
index 8e6a555..f417bec 100644
--- a/javatests/dagger/functional/BUILD
+++ b/javatests/dagger/functional/BUILD
@@ -15,11 +15,15 @@
# Description:
# Functional tests for Dagger
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "SOURCE_7_TARGET_7")
-load("//:test_defs.bzl", "GenJavaTests")
-
package(default_visibility = ["//:src"])
+load(
+ "//:build_defs.bzl",
+ "DOCLINT_HTML_AND_SYNTAX",
+ "SOURCE_7_TARGET_7",
+)
+load("//:test_defs.bzl", "GenJavaTests")
+
GenJavaTests(
name = "functional_tests",
srcs = glob(
@@ -27,16 +31,14 @@
),
javacopts = DOCLINT_HTML_AND_SYNTAX,
lib_javacopts = SOURCE_7_TARGET_7,
+ # NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
+ # used without Guava and jsr305 deps.
test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
"@google_bazel_common//third_party/java/guava:testlib",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/truth",
"@google_bazel_common//third_party/java/junit",
],
- # NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
- # used without Guava and jsr305 deps.
deps = [
"//:dagger_with_compiler",
"@google_bazel_common//third_party/java/auto:factory",
diff --git a/javatests/dagger/functional/BoundedGenerics.java b/javatests/dagger/functional/BoundedGenerics.java
index d514337..812cd04 100644
--- a/javatests/dagger/functional/BoundedGenerics.java
+++ b/javatests/dagger/functional/BoundedGenerics.java
@@ -19,7 +19,6 @@
import java.util.List;
import javax.inject.Inject;
-
class BoundedGenerics<A extends Number & Comparable<? super A>,
B extends List<? extends CharSequence>,
C extends List<? super String>,
diff --git a/javatests/dagger/functional/ComponentDependenciesTest.java b/javatests/dagger/functional/ComponentDependenciesTest.java
deleted file mode 100644
index 502c51d..0000000
--- a/javatests/dagger/functional/ComponentDependenciesTest.java
+++ /dev/null
@@ -1,92 +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.functional;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests component dependencies.
- */
-@RunWith(JUnit4.class)
-public final class ComponentDependenciesTest {
- public interface One {
- String getString();
- }
-
- public interface Two {
- String getString();
- }
-
- public interface Merged extends One, Two {
- }
-
- @Component(dependencies = Merged.class)
- interface TestComponent {
- String getString();
-
- @Component.Builder
- interface Builder {
- Builder dep(Merged dep);
-
- TestComponent build();
- }
- }
-
- @Test
- public void testSameMethodTwice() throws Exception {
- TestComponent component =
- DaggerComponentDependenciesTest_TestComponent.builder().dep(() -> "test").build();
- assertThat(component.getString()).isEqualTo("test");
- }
-
- public interface OneOverride {
- Object getString();
- }
-
- public interface TwoOverride {
- Object getString();
- }
-
- public interface MergedOverride extends OneOverride, TwoOverride {
- @Override
- String getString();
- }
-
- @Component(dependencies = MergedOverride.class)
- interface TestOverrideComponent {
- String getString();
-
- @Component.Builder
- interface Builder {
- Builder dep(MergedOverride dep);
-
- TestOverrideComponent build();
- }
- }
-
- @Test
- public void testPolymorphicOverridesStillCompiles() throws Exception {
- TestOverrideComponent component =
- DaggerComponentDependenciesTest_TestOverrideComponent.builder().dep(() -> "test").build();
- assertThat(component.getString()).isEqualTo("test");
- }
-}
diff --git a/javatests/dagger/functional/Generic2.java b/javatests/dagger/functional/Generic2.java
index 40ef546..f53c0f8 100644
--- a/javatests/dagger/functional/Generic2.java
+++ b/javatests/dagger/functional/Generic2.java
@@ -18,7 +18,6 @@
import javax.inject.Inject;
-
public class Generic2<T> {
final T t;
diff --git a/javatests/dagger/functional/GenericNoDeps.java b/javatests/dagger/functional/GenericNoDeps.java
index 0e3d41b..c3f38b4 100644
--- a/javatests/dagger/functional/GenericNoDeps.java
+++ b/javatests/dagger/functional/GenericNoDeps.java
@@ -18,7 +18,6 @@
import javax.inject.Inject;
-
class GenericNoDeps<T> {
@Inject GenericNoDeps() {}
diff --git a/javatests/dagger/functional/MultibindingTest.java b/javatests/dagger/functional/MultibindingTest.java
index 3da3901..d99e46d 100644
--- a/javatests/dagger/functional/MultibindingTest.java
+++ b/javatests/dagger/functional/MultibindingTest.java
@@ -80,7 +80,7 @@
@Test
public void wrappedAnnotationKeyMap() {
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings("unchecked")
Class<? extends Number>[] classes = new Class[] {Long.class, Integer.class};
assertThat(multibindingComponent.wrappedAnnotationKeyMap())
.containsExactly(
diff --git a/javatests/dagger/functional/NeedsFactory.java b/javatests/dagger/functional/NeedsFactory.java
index 14ab134..2ea01ec 100644
--- a/javatests/dagger/functional/NeedsFactory.java
+++ b/javatests/dagger/functional/NeedsFactory.java
@@ -19,19 +19,11 @@
import com.google.auto.factory.AutoFactory;
import javax.inject.Inject;
-public class NeedsFactory {
+class NeedsFactory {
@Inject
- NeedsFactory(
- @SuppressWarnings("unused") NeedsFactory_SomethingFactory somethingFactory,
- @SuppressWarnings("unused") SomethingFactoryImpl somethingFactoryImpl) {}
+ NeedsFactory(@SuppressWarnings("unused") NeedsFactory_SomethingFactory somethingFactory) {}
- public interface SomethingFactory {}
-
- @AutoFactory(implementing = SomethingFactory.class, allowSubclasses = true)
+ @AutoFactory
static class Something {}
-
- public static final class SomethingFactoryImpl extends NeedsFactory_SomethingFactory {
- @Inject SomethingFactoryImpl() {}
- }
}
diff --git a/javatests/dagger/functional/NeedsProviderOfFactory.java b/javatests/dagger/functional/NeedsProviderOfFactory.java
index 1ae797e..efbd73d 100644
--- a/javatests/dagger/functional/NeedsProviderOfFactory.java
+++ b/javatests/dagger/functional/NeedsProviderOfFactory.java
@@ -26,8 +26,7 @@
static class InjectsProviderOfFactory {
@Inject
InjectsProviderOfFactory(
- Provider<NeedsProviderOfFactory_SomethingFactory> somethingFactoryProvider,
- Provider<SomethingFactoryImpl> somethingFactoryImplProvider) {}
+ Provider<NeedsProviderOfFactory_SomethingFactory> provider) {}
}
@Component
@@ -35,12 +34,6 @@
InjectsProviderOfFactory injectsProviderOfFactory();
}
- interface SomethingFactory {}
-
- @AutoFactory(implementing = SomethingFactory.class, allowSubclasses = true)
+ @AutoFactory
static class Something {}
-
- static final class SomethingFactoryImpl extends NeedsProviderOfFactory_SomethingFactory {
- @Inject SomethingFactoryImpl() {}
- }
}
diff --git a/javatests/dagger/functional/aot/DependsOnMissingArrayKey.java b/javatests/dagger/functional/aot/DependsOnMissingArrayKey.java
new file mode 100644
index 0000000..20a89d4
--- /dev/null
+++ b/javatests/dagger/functional/aot/DependsOnMissingArrayKey.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+
+/**
+ * Regression test for an ahead-of-time subcomponents bug where generating the name for a missing
+ * binding method for a key of an array type threw an exception.
+ */
+final class DependsOnMissingArrayKey {
+ @Module
+ abstract static class ModuleArrayDependencies {
+ @Provides
+ static int dependsOnMissingArrayType(int[] primitive, Object[] object, String[][] doubleArray) {
+ return 0;
+ }
+ }
+
+ @Subcomponent(modules = ModuleArrayDependencies.class)
+ interface HasMissingArrayBindings {
+ int dependsOnMissingArrayType();
+ }
+}
diff --git a/javatests/dagger/functional/aot/MapFrameworkInstanceWithContributionsInMultipleImplementationsTest.java b/javatests/dagger/functional/aot/MapFrameworkInstanceWithContributionsInMultipleImplementationsTest.java
new file mode 100644
index 0000000..ae6b3a4
--- /dev/null
+++ b/javatests/dagger/functional/aot/MapFrameworkInstanceWithContributionsInMultipleImplementationsTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.functional.aot;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.StringKey;
+import java.util.Map;
+import javax.inject.Provider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests that framework instances of map bindings are properly instantiated in ahead-of-time mode
+ * when contributions are made in 3 or more implementations.
+ */
+@RunWith(JUnit4.class)
+public final class MapFrameworkInstanceWithContributionsInMultipleImplementationsTest {
+ @Subcomponent(modules = LeafModule.class)
+ interface Leaf {
+ Provider<Map<String, String>> providerOfMapOfValues();
+ Provider<Map<String, Provider<String>>> providerOfMapOfProviders();
+ }
+
+ @Module
+ interface LeafModule {
+ @Provides
+ @IntoMap
+ @StringKey("a")
+ static String fromLeaf() {
+ return "a";
+ }
+ }
+
+ @Subcomponent(modules = AncestorModule.class)
+ interface Ancestor {
+ Leaf leaf();
+ }
+
+ @Module
+ interface AncestorModule {
+ @Provides
+ @IntoMap
+ @StringKey("b")
+ static String fromAncestor() {
+ return "b";
+ }
+ }
+
+ @Component(modules = RootModule.class)
+ interface Root {
+ Ancestor ancestor();
+ }
+
+ @Module
+ interface RootModule {
+ @Provides
+ @IntoMap
+ @StringKey("c")
+ static String fromRoot() {
+ return "c";
+ }
+ }
+
+ @Test
+ public void mapFactoryCanBeInstantiatedAcrossComponentImplementations() {
+ Leaf leaf =
+ DaggerMapFrameworkInstanceWithContributionsInMultipleImplementationsTest_Root.create()
+ .ancestor()
+ .leaf();
+ assertThat(leaf.providerOfMapOfValues().get()).hasSize(3);
+ assertThat(leaf.providerOfMapOfProviders().get()).hasSize(3);
+ }
+}
diff --git a/javatests/dagger/functional/aot/MissingBindingReplacedWithGeneratedInstance.java b/javatests/dagger/functional/aot/MissingBindingReplacedWithGeneratedInstance.java
new file mode 100644
index 0000000..1813ad2
--- /dev/null
+++ b/javatests/dagger/functional/aot/MissingBindingReplacedWithGeneratedInstance.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Subcomponent;
+import javax.inject.Inject;
+
+/**
+ * This class demonstrates a regression where a missing binding method was generated in a leaf
+ * component and then satisfied in an ancestor with a generated instance binding. If the ancestor's
+ * generated instance method had the same name as the formerly-missing binding method, Dagger would
+ * generate code without a proper {@code DaggerOuter.this} reference:
+ *
+ * <pre>{@code
+ * public class DaggerAncestor implements Ancestor {
+ * protected abstract Ancestor getAncestor();
+ *
+ * protected abstract class LeafImpl extends DaggerLeaf {
+ * {@literal @Override}
+ * protected final Ancestor getAncestor() {
+ * return getAncestor();
+ * // ^ should be DaggerAncestor.this.getAncestor()
+ * }
+ * }
+ * }
+ * }</pre>
+ */
+final class MissingBindingReplacedWithGeneratedInstance {
+ @Subcomponent
+ interface Leaf {
+ DependsOnGeneratedInstance dependsOnGeneratedInstance();
+ }
+
+ static class DependsOnGeneratedInstance {
+ @Inject DependsOnGeneratedInstance(Ancestor generatedInstance) {}
+ }
+
+ @Subcomponent
+ interface Ancestor {
+ Leaf child();
+ }
+}
diff --git a/javatests/dagger/functional/aot/ModifiedFrameworkInstancesTest.java b/javatests/dagger/functional/aot/ModifiedFrameworkInstancesTest.java
new file mode 100644
index 0000000..7084f83
--- /dev/null
+++ b/javatests/dagger/functional/aot/ModifiedFrameworkInstancesTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+import dagger.multibindings.IntoSet;
+import java.util.Set;
+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)
+public final class ModifiedFrameworkInstancesTest {
+ static class DependsOnModifiableBinding {
+ @Inject
+ DependsOnModifiableBinding(Set<Integer> modifiableDependency) {}
+ }
+
+ @Module
+ interface ChildModule {
+ @Provides
+ @IntoSet
+ static int contribution() {
+ return 1;
+ }
+ }
+
+ @Subcomponent(modules = ChildModule.class)
+ interface Child {
+ Provider<DependsOnModifiableBinding> frameworkInstanceWithModifiedDependency();
+ }
+
+ @Module
+ interface ParentModule {
+ @Provides
+ @IntoSet
+ static int contribution() {
+ return 2;
+ }
+ }
+
+ @Component(modules = ParentModule.class)
+ interface Parent {
+ Child child();
+ }
+
+ @Test
+ public void dependsOnModifiedFrameworkInstance() {
+ DaggerModifiedFrameworkInstancesTest_Parent.create()
+ .child()
+ .frameworkInstanceWithModifiedDependency()
+ // Ensure that modified framework instances that are dependencies to other framework
+ // instances from superclass implementations are initialized correctly. This fixes a
+ // regression where a null instance would be passed to the superclass initialization, and
+ // then a NullPointerException would be thrown when the factory attempted to satisfy the
+ // dependency in get(). If get() succeeds, this test should pass.
+ .get();
+ }
+}
diff --git a/javatests/dagger/functional/aot/PrunedBindingDependedOnInSuperInitializationTest.java b/javatests/dagger/functional/aot/PrunedBindingDependedOnInSuperInitializationTest.java
new file mode 100644
index 0000000..853e22b
--- /dev/null
+++ b/javatests/dagger/functional/aot/PrunedBindingDependedOnInSuperInitializationTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+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)
+public class PrunedBindingDependedOnInSuperInitializationTest {
+ interface PrunedDependency {}
+
+ static class WillHavePrunedDependency {
+ @Inject WillHavePrunedDependency(PrunedDependency pruned) {}
+ }
+
+ @Subcomponent
+ interface Child {
+ Provider<WillHavePrunedDependency> frameworkInstance();
+ }
+
+ @Module
+ static class ParentModule {
+ @Provides
+ static WillHavePrunedDependency pruneDependency() {
+ return new WillHavePrunedDependency(new PrunedDependency() {});
+ }
+ }
+
+ @Component(modules = ParentModule.class)
+ interface Parent {
+ Child child();
+ }
+
+ @Test
+ public void prunedFrameworkInstanceBindingUsedInInitializationDoesntThrow() {
+ Parent parent = DaggerPrunedBindingDependedOnInSuperInitializationTest_Parent.create();
+ // This test ensures that pruned bindings that are used during unpruned initialization
+ // statements do not throw exceptions. If the subcomponent initialization succeeds, the test
+ // should pass
+ parent.child();
+ }
+}
diff --git a/javatests/dagger/functional/aot/PrunedFrameworkInstanceWithModuleInstanceTest.java b/javatests/dagger/functional/aot/PrunedFrameworkInstanceWithModuleInstanceTest.java
new file mode 100644
index 0000000..f995789
--- /dev/null
+++ b/javatests/dagger/functional/aot/PrunedFrameworkInstanceWithModuleInstanceTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.functional.aot;
+
+import dagger.Component;
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+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)
+public class PrunedFrameworkInstanceWithModuleInstanceTest {
+ static class Pruned {}
+
+ static class InjectsPruned {
+ @Inject
+ InjectsPruned(Provider<Pruned> pruned) {}
+ }
+
+ @Module
+ static class InstanceStateModule {
+ @Provides
+ /* intentionally not static */ Pruned pruned() {
+ return new Pruned();
+ }
+ }
+
+ @Subcomponent(modules = InstanceStateModule.class)
+ interface LeafWithoutCreator {
+ InjectsPruned injectsPruned();
+ }
+
+ @Subcomponent(modules = InstanceStateModule.class)
+ interface LeafWithCreator {
+ InjectsPruned injectsPruned();
+
+ @Subcomponent.Builder
+ interface Builder {
+ Builder module(InstanceStateModule module);
+ LeafWithCreator build();
+ }
+ }
+
+ @Module
+ interface RootModule {
+ @Provides
+ static InjectsPruned pruneBindingWithInstanceState() {
+ return new InjectsPruned(null);
+ }
+ }
+
+ @Component(modules = RootModule.class)
+ interface Root {
+ LeafWithoutCreator leafWithoutCreator(InstanceStateModule pruned);
+ LeafWithCreator.Builder leafWithCreator();
+ }
+
+ @Test
+ public void prunedBindingWithModuleInstance_doesntThrowDuringInitialization() {
+ Root root = DaggerPrunedFrameworkInstanceWithModuleInstanceTest_Root.create();
+
+ Object unused = root.leafWithoutCreator(new InstanceStateModule()).injectsPruned();
+ unused = root.leafWithCreator().module(new InstanceStateModule()).build().injectsPruned();
+ }
+}
diff --git a/javatests/dagger/functional/aot/ScopedBindsWithMissingDependency.java b/javatests/dagger/functional/aot/ScopedBindsWithMissingDependency.java
new file mode 100644
index 0000000..2723ac0
--- /dev/null
+++ b/javatests/dagger/functional/aot/ScopedBindsWithMissingDependency.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Reusable;
+import dagger.Subcomponent;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.inject.Scope;
+
+/**
+ * A regression test for ahead-of-time subcomponents mode where a scoped {@link Binds} method whose
+ * dependency was missing in a partial subcomponent implementation threw an exception in the
+ * processor.
+ */
+final class ScopedBindsWithMissingDependency {
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Scope
+ @interface CustomScope {}
+
+ @Module
+ interface ScopedBindsWithMissingDependencyModule {
+ @Binds
+ @CustomScope
+ Object bindsCustomScopeToMissingDep(String missingDependency);
+
+ @Binds
+ @Reusable
+ CharSequence bindsReusableScopeToMissingDep(String missingDependency);
+ }
+
+ @CustomScope
+ @Subcomponent(modules = ScopedBindsWithMissingDependencyModule.class)
+ interface HasScopedBindsWithMissingDependency {
+ Object customScopedBindsWithMissingDependency();
+ CharSequence reusableScopedBindsWithMissingDependency();
+ }
+}
diff --git a/javatests/dagger/functional/aot/SubcomponentWithInaccessibleMissingBindingMethod.java b/javatests/dagger/functional/aot/SubcomponentWithInaccessibleMissingBindingMethod.java
new file mode 100644
index 0000000..689689c
--- /dev/null
+++ b/javatests/dagger/functional/aot/SubcomponentWithInaccessibleMissingBindingMethod.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Subcomponent;
+import dagger.functional.aot.sub.PublicTypeWithPackagePrivateMissingDep;
+import javax.inject.Provider;
+
+@Subcomponent
+interface SubcomponentWithInaccessibleMissingBindingMethod {
+ PublicTypeWithPackagePrivateMissingDep instance();
+ Provider<PublicTypeWithPackagePrivateMissingDep> frameworkInstance();
+}
diff --git a/javatests/dagger/functional/aot/SubcomponentWithModifiedInaccessibleDependency.java b/javatests/dagger/functional/aot/SubcomponentWithModifiedInaccessibleDependency.java
new file mode 100644
index 0000000..06cebb9
--- /dev/null
+++ b/javatests/dagger/functional/aot/SubcomponentWithModifiedInaccessibleDependency.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.aot;
+
+import dagger.Subcomponent;
+import dagger.functional.aot.sub.BindsPackagePrivateModule;
+import dagger.functional.aot.sub.SubcomponentWithInaccessibleOptionalBindingMethod;
+
+/**
+ * See {@link dagger.functional.aot.sub.SubcomponentWithInaccessibleOptionalBindingMethod}. This
+ * subcomponent will induce a modified binding method for its single child for the key {@code
+ * Optional<dagger.functional.aot.sub.PackagePrivate>}. When it tries to reimplement it, it must use
+ * the publicly accessible type.
+ */
+@Subcomponent(modules = BindsPackagePrivateModule.class)
+interface SubcomponentWithModifiedInaccessibleDependency {
+ SubcomponentWithInaccessibleOptionalBindingMethod child();
+}
diff --git a/javatests/dagger/functional/aot/sub/BindsPackagePrivateModule.java b/javatests/dagger/functional/aot/sub/BindsPackagePrivateModule.java
new file mode 100644
index 0000000..2eee3c9
--- /dev/null
+++ b/javatests/dagger/functional/aot/sub/BindsPackagePrivateModule.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.aot.sub;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public final class BindsPackagePrivateModule {
+ @Provides
+ static PackagePrivate packagePrivate() {
+ return new PackagePrivate();
+ }
+}
diff --git a/javatests/dagger/functional/aot/sub/PackagePrivate.java b/javatests/dagger/functional/aot/sub/PackagePrivate.java
new file mode 100644
index 0000000..c629f6e
--- /dev/null
+++ b/javatests/dagger/functional/aot/sub/PackagePrivate.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 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.aot.sub;
+
+final class PackagePrivate {}
diff --git a/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateMissingDep.java b/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateMissingDep.java
new file mode 100644
index 0000000..b5ced6f
--- /dev/null
+++ b/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateMissingDep.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 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.aot.sub;
+
+import javax.inject.Inject;
+
+public class PublicTypeWithPackagePrivateMissingDep {
+ @Inject
+ PublicTypeWithPackagePrivateMissingDep(PackagePrivate packagePrivate) {}
+}
diff --git a/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateOptionalDep.java b/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateOptionalDep.java
new file mode 100644
index 0000000..1d69723
--- /dev/null
+++ b/javatests/dagger/functional/aot/sub/PublicTypeWithPackagePrivateOptionalDep.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 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.aot.sub;
+
+import java.util.Optional;
+import javax.inject.Inject;
+
+public class PublicTypeWithPackagePrivateOptionalDep {
+ @Inject
+ PublicTypeWithPackagePrivateOptionalDep(Optional<PackagePrivate> packagePrivateOptional) {}
+}
diff --git a/javatests/dagger/functional/aot/sub/SubcomponentWithInaccessibleOptionalBindingMethod.java b/javatests/dagger/functional/aot/sub/SubcomponentWithInaccessibleOptionalBindingMethod.java
new file mode 100644
index 0000000..d908b1c
--- /dev/null
+++ b/javatests/dagger/functional/aot/sub/SubcomponentWithInaccessibleOptionalBindingMethod.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.aot.sub;
+
+import dagger.BindsOptionalOf;
+import dagger.Module;
+import dagger.Subcomponent;
+import dagger.functional.aot.sub.SubcomponentWithInaccessibleOptionalBindingMethod.ExposesModifiablePackagePrivateBindingModule;
+import javax.inject.Provider;
+
+/**
+ * This component will generate a modifiable binding method for the key {@code
+ * Optional<PackagePrivate>} as a dependency of {@link PublicTypeWithPackagePrivateOptionalDep}.
+ * Even though this subcomponent implementation can refer to the parameterized type, a subclass
+ * implementation in another package will not be able to, and thus the return type must be reduced
+ * to the publicly accessible type. This is exhibited in {@link
+ * dagger.functional.aot.SubcomponentWithModifiedInaccessibleDependency}.
+ */
+@Subcomponent(modules = ExposesModifiablePackagePrivateBindingModule.class)
+public interface SubcomponentWithInaccessibleOptionalBindingMethod {
+ PublicTypeWithPackagePrivateOptionalDep instance();
+ Provider<PublicTypeWithPackagePrivateOptionalDep> frameworkInstance();
+
+ @Module
+ interface ExposesModifiablePackagePrivateBindingModule {
+ @BindsOptionalOf
+ PackagePrivate optional();
+ }
+}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryBindsTest.java b/javatests/dagger/functional/assisted/AssistedFactoryBindsTest.java
deleted file mode 100644
index 78495b7..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryBindsTest.java
+++ /dev/null
@@ -1,89 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Binds;
-import dagger.Component;
-import dagger.Module;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import javax.inject.Inject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class AssistedFactoryBindsTest {
- @Component(modules = FooFactoryModule.class)
- interface ParentComponent {
- // Test using @Binds where Foo => FooImpl and FooFactory => FooFactoryImpl
- FooFactory fooFactory();
- }
-
- @Module
- interface FooFactoryModule {
- @Binds
- FooFactory bind(FooFactoryImpl impl);
- }
-
- interface Foo {}
-
- static final class FooImpl implements Foo {
- private final Dep dep;
- private final AssistedDep assistedDep;
-
- @AssistedInject
- FooImpl(Dep dep, @Assisted AssistedDep assistedDep) {
- this.dep = dep;
- this.assistedDep = assistedDep;
- }
- }
-
- interface FooFactory {
- Foo create(AssistedDep assistedDep);
- }
-
- @AssistedFactory
- interface FooFactoryImpl extends FooFactory {
- @Override
- FooImpl create(AssistedDep assistedDep);
- }
-
- static final class AssistedDep {}
-
- static final class Dep {
- @Inject
- Dep() {}
- }
-
- @Test
- public void testFooFactory() {
- FooFactory fooFactory = DaggerAssistedFactoryBindsTest_ParentComponent.create().fooFactory();
- assertThat(fooFactory).isInstanceOf(FooFactoryImpl.class);
-
- AssistedDep assistedDep = new AssistedDep();
- Foo foo = fooFactory.create(assistedDep);
- assertThat(foo).isInstanceOf(FooImpl.class);
-
- FooImpl fooImpl = (FooImpl) foo;
- assertThat(fooImpl.dep).isNotNull();
- assertThat(fooImpl.assistedDep).isEqualTo(assistedDep);
- }
-}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryInaccessibleTest.java b/javatests/dagger/functional/assisted/AssistedFactoryInaccessibleTest.java
deleted file mode 100644
index d586c61..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryInaccessibleTest.java
+++ /dev/null
@@ -1,69 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.assisted.AssistedFactory;
-import dagger.functional.assisted.subpackage.AccessibleFoo;
-import dagger.functional.assisted.subpackage.AssistedDep;
-import dagger.functional.assisted.subpackage.InaccessibleFooFactory;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class AssistedFactoryInaccessibleTest {
- @Component
- interface ParentComponent {
- // Factory for an accessible type from another package
- AccessibleFooFactory accessibleFooFactory();
-
- // Factory for an inaccessible type from another package
- InaccessibleFooFactory inaccessibleFooFactory();
- }
-
- @AssistedFactory
- public interface AccessibleFooFactory {
- // Use different parameter names than Foo to make sure we're not assuming they're the same.
- AccessibleFoo create(AssistedDep factoryAssistedDep);
- }
-
- @Test
- public void testAccessibleFooFactory() {
- AssistedDep assistedDep = new AssistedDep();
- AccessibleFoo accessibleFoo =
- DaggerAssistedFactoryInaccessibleTest_ParentComponent.create()
- .accessibleFooFactory()
- .create(assistedDep);
- assertThat(accessibleFoo).isNotNull();
- assertThat(accessibleFoo.dep).isNotNull();
- assertThat(accessibleFoo.assistedDep).isEqualTo(assistedDep);
- }
-
- @Test
- public void testInaccessibleFooFactory() {
- AssistedDep assistedDep = new AssistedDep();
- // We can't access InaccessibleFoo directly, so just use Object instead.
- Object inaccessibleFoo =
- DaggerAssistedFactoryInaccessibleTest_ParentComponent.create()
- .inaccessibleFooFactory()
- .create(assistedDep);
- assertThat(inaccessibleFoo).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryParameterizedTest.java b/javatests/dagger/functional/assisted/AssistedFactoryParameterizedTest.java
deleted file mode 100644
index d079430..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryParameterizedTest.java
+++ /dev/null
@@ -1,265 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class AssistedFactoryParameterizedTest {
- @Singleton
- @Component
- interface ParentComponent {
- // Tests a parameterized Factory with unique @Assisted types
- ParameterizedFooFactory<Dep2, AssistedDep2> uniqueParameterizedFooFactory();
-
- // Tests a parameterized Factory with duplicate @Assisted types in its resolved request type.
- // Note: this is fine since the @Assisted types are still unique on the @AssistedInject and
- // @AssistedFactory types, so that the generated code can correctly matches types.
- ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory();
-
- // Tests a parameterized Factory with same type as binding
- ParameterizedFooFactory<Dep1, Dep1> bindingParameterizedFooFactory();
-
- // Tests a parameterized Factory with fixed type parameters
- FixedParameterizedFooFactory fixedParameterizedFooFactory();
-
- // Tests a parameterized Factory that extends an interface with a parameterized return type
- ExtendedFooFactory<Dep2, AssistedDep2> extendedParameterizedFooFactory();
-
- // Tests a request of factories from another binding.
- SomeEntryPoint someEntryPoint();
- }
-
- static final class Dep1 {
- @Inject
- Dep1(Dep2 dep2, Dep3 dep3) {}
- }
-
- static final class Dep2 {
- @Inject
- Dep2(Dep3 dep3) {}
- }
-
- static final class Dep3 {
- @Inject
- Dep3(Dep4 dep4) {}
- }
-
- static final class Dep4 {
- @Inject
- Dep4() {}
- }
-
- // A base interface to test that factories can reference subclasses of the assisted parameter.
- interface AssistedDep {}
-
- static final class AssistedDep1 implements AssistedDep {}
-
- static final class AssistedDep2 implements AssistedDep {}
-
- abstract static class BaseFoo {
- @Inject Dep4 dep4;
- }
-
- static final class ParameterizedFoo<DepT, AssistedDepT> extends BaseFoo {
- private final Dep1 dep1;
- private final Provider<DepT> depTProvider;
- private final AssistedDep1 assistedDep1;
- private final AssistedDepT assistedDepT;
- private final int assistedInt;
- private final ParameterizedFooFactory<DepT, AssistedDepT> factory;
-
- @Inject Dep3 dep3;
-
- @AssistedInject
- ParameterizedFoo(
- Dep1 dep1,
- @Assisted AssistedDep1 assistedDep1,
- Provider<DepT> depTProvider,
- @Assisted AssistedDepT assistedDepT,
- @Assisted int assistedInt,
- ParameterizedFooFactory<DepT, AssistedDepT> factory) {
- this.dep1 = dep1;
- this.depTProvider = depTProvider;
- this.assistedDep1 = assistedDep1;
- this.assistedDepT = assistedDepT;
- this.assistedInt = assistedInt;
- this.factory = factory;
- }
- }
-
- @AssistedFactory
- interface ParameterizedFooFactory<DepT, AssistedDepT> {
- ParameterizedFoo<DepT, AssistedDepT> create(
- AssistedDep1 assistedDep1, AssistedDepT assistedDepT, int assistedInt);
- }
-
- @Test
- public void testUniqueParameterizedFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- AssistedDep2 assistedDep2 = new AssistedDep2();
- int assistedInt = 7;
- ParameterizedFoo<Dep2, AssistedDep2> parameterizedFoo =
- DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
- .uniqueParameterizedFooFactory()
- .create(assistedDep1, assistedDep2, assistedInt);
- assertThat(parameterizedFoo.dep1).isNotNull();
- assertThat(parameterizedFoo.depTProvider).isNotNull();
- assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
- assertThat(parameterizedFoo.dep3).isNotNull();
- assertThat(parameterizedFoo.dep4).isNotNull();
- assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2);
- assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
- assertThat(parameterizedFoo.factory).isNotNull();
- }
-
- @Test
- public void testDupeParameterizedFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- int assistedInt = 7;
- ParameterizedFoo<Dep1, AssistedDep1> parameterizedFoo =
- DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
- .dupeParameterizedFooFactory()
- .create(assistedDep1, assistedDep1, assistedInt);
- assertThat(parameterizedFoo.dep1).isNotNull();
- assertThat(parameterizedFoo.depTProvider).isNotNull();
- assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
- assertThat(parameterizedFoo.dep3).isNotNull();
- assertThat(parameterizedFoo.dep4).isNotNull();
- assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
- assertThat(parameterizedFoo.factory).isNotNull();
- }
-
- @Test
- public void testBindingParameterizedFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- Dep1 dep1 = new Dep1(new Dep2(new Dep3(new Dep4())), new Dep3(new Dep4()));
- int assistedInt = 7;
- ParameterizedFoo<Dep1, Dep1> parameterizedFoo =
- DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
- .bindingParameterizedFooFactory()
- .create(assistedDep1, dep1, assistedInt);
- assertThat(parameterizedFoo.dep1).isNotNull();
- assertThat(parameterizedFoo.depTProvider).isNotNull();
- assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
- assertThat(parameterizedFoo.dep3).isNotNull();
- assertThat(parameterizedFoo.dep4).isNotNull();
- assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedDepT).isEqualTo(dep1);
- assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
- assertThat(parameterizedFoo.factory).isNotNull();
- }
-
- @AssistedFactory
- interface FixedParameterizedFooFactory {
- ParameterizedFoo<Dep2, AssistedDep2> create(
- AssistedDep1 assistedDep1, AssistedDep2 assistedDep2, int assistedInt);
- }
-
- @Test
- public void testFixedParameterizedFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- AssistedDep2 assistedDep2 = new AssistedDep2();
- int assistedInt = 7;
- ParameterizedFoo<Dep2, AssistedDep2> parameterizedFoo =
- DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
- .fixedParameterizedFooFactory()
- .create(assistedDep1, assistedDep2, assistedInt);
- assertThat(parameterizedFoo.dep1).isNotNull();
- assertThat(parameterizedFoo.depTProvider).isNotNull();
- assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
- assertThat(parameterizedFoo.dep3).isNotNull();
- assertThat(parameterizedFoo.dep4).isNotNull();
- assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2);
- assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
- assertThat(parameterizedFoo.factory).isNotNull();
- }
-
- interface ParameterizedFactory<ReturnT, DepT, AssistedDepT> {
- // Use different parameter names than Foo to make sure we're not assuming they're the same.
- ReturnT create(
- AssistedDep1 factoryAssistedDep1, AssistedDepT factoryAssistedDepT, int factoryAssistedInt);
- }
-
- @AssistedFactory
- interface ExtendedFooFactory<DepT, AssistedDepT>
- extends ParameterizedFactory<ParameterizedFoo<DepT, AssistedDepT>, DepT, AssistedDepT> {}
-
- @Test
- public void testExtendedFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- AssistedDep2 assistedDep2 = new AssistedDep2();
- int assistedInt = 7;
- ParameterizedFoo<Dep2, AssistedDep2> parameterizedFoo =
- DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
- .extendedParameterizedFooFactory()
- .create(assistedDep1, assistedDep2, assistedInt);
- assertThat(parameterizedFoo.dep1).isNotNull();
- assertThat(parameterizedFoo.depTProvider).isNotNull();
- assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
- assertThat(parameterizedFoo.dep3).isNotNull();
- assertThat(parameterizedFoo.dep4).isNotNull();
- assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep2);
- assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
- assertThat(parameterizedFoo.factory).isNotNull();
- }
-
- static class SomeEntryPoint {
- private final ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory;
-
- @Inject
- SomeEntryPoint(ParameterizedFooFactory<Dep1, AssistedDep1> dupeParameterizedFooFactory) {
- this.dupeParameterizedFooFactory = dupeParameterizedFooFactory;
- }
- }
-
- @Test
- public void testParameterizedFooFactoryFromSomeEntryPoint() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- int assistedInt = 7;
- ParameterizedFoo<Dep1, AssistedDep1> parameterizedFoo =
- DaggerAssistedFactoryParameterizedTest_ParentComponent.create()
- .someEntryPoint()
- .dupeParameterizedFooFactory
- .create(assistedDep1, assistedDep1, assistedInt);
- assertThat(parameterizedFoo.dep1).isNotNull();
- assertThat(parameterizedFoo.depTProvider).isNotNull();
- assertThat(parameterizedFoo.depTProvider.get()).isNotNull();
- assertThat(parameterizedFoo.dep3).isNotNull();
- assertThat(parameterizedFoo.dep4).isNotNull();
- assertThat(parameterizedFoo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedDepT).isEqualTo(assistedDep1);
- assertThat(parameterizedFoo.assistedInt).isEqualTo(assistedInt);
- assertThat(parameterizedFoo.factory).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryTest.java b/javatests/dagger/functional/assisted/AssistedFactoryTest.java
deleted file mode 100644
index 3176add..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryTest.java
+++ /dev/null
@@ -1,332 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-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)
-public final class AssistedFactoryTest {
- @Component
- interface ParentComponent {
- // Simple factory using a nested factory.
- SimpleFoo.Factory nestedSimpleFooFactory();
-
- // Simple factory using a non-nested factory.
- SimpleFooFactory nonNestedSimpleFooFactory();
-
- // Simple factory using a factory that extends a supertype.
- ExtendedSimpleFooFactory extendedSimpleFooFactory();
-
- // Factory as interface
- FooFactory fooFactory();
-
- // Factory as abstract class
- AbstractFooFactory abstractFooFactory();
-
- // Factory without any assisted parameters
- NoAssistedParametersFooFactory noAssistedParametersFooFactory();
-
- // Test injecting the factories from another class
- SomeEntryPoint someEntryPoint();
- }
-
- // This class tests the request of factories from another binding.
- static class SomeEntryPoint {
- private final SimpleFoo.Factory nestedSimpleFooFactory;
- private final SimpleFooFactory nonNestedSimpleFooFactory;
- private final ExtendedSimpleFooFactory extendedSimpleFooFactory;
- private final FooFactory fooFactory;
- private final AbstractFooFactory abstractFooFactory;
- private final NoAssistedParametersFooFactory noAssistedParametersFooFactory;
-
- @Inject
- SomeEntryPoint(
- SimpleFoo.Factory nestedSimpleFooFactory,
- SimpleFooFactory nonNestedSimpleFooFactory,
- ExtendedSimpleFooFactory extendedSimpleFooFactory,
- FooFactory fooFactory,
- AbstractFooFactory abstractFooFactory,
- NoAssistedParametersFooFactory noAssistedParametersFooFactory) {
- this.nestedSimpleFooFactory = nestedSimpleFooFactory;
- this.nonNestedSimpleFooFactory = nonNestedSimpleFooFactory;
- this.extendedSimpleFooFactory = extendedSimpleFooFactory;
- this.fooFactory = fooFactory;
- this.abstractFooFactory = abstractFooFactory;
- this.noAssistedParametersFooFactory = noAssistedParametersFooFactory;
- }
- }
-
- static final class Dep1 {
- @Inject
- Dep1(Dep2 dep2, Dep3 dep3) {}
- }
-
- static final class Dep2 {
- @Inject
- Dep2(Dep3 dep3) {}
- }
-
- static final class Dep3 {
- @Inject
- Dep3(Dep4 dep4) {}
- }
-
- static final class Dep4 {
- @Inject
- Dep4() {}
- }
-
- // A base interface to test that factories can reference subclasses of the assisted parameter.
- interface AssistedDep {}
-
- static final class AssistedDep1 implements AssistedDep {}
-
- static final class AssistedDep2 implements AssistedDep {}
-
- static final class SimpleFoo {
- private final AssistedDep assistedDep;
-
- @AssistedInject
- SimpleFoo(@Assisted AssistedDep assistedDep) {
- this.assistedDep = assistedDep;
- }
-
- @AssistedFactory
- interface Factory {
- // Use different parameter names than Foo to make sure we're not assuming they're the same.
- SimpleFoo createSimpleFoo(AssistedDep factoryAssistedDep);
-
- // A no-op method to test static methods in assisted factories
- static void staticMethod() {
- return;
- }
-
- // A no-op method to test default methods in assisted factories
- default void defaultMethod() {
- return;
- }
- }
- }
-
- @AssistedFactory
- interface SimpleFooFactory {
- // Use different parameter names than Foo to make sure we're not assuming they're the same.
- SimpleFoo createSimpleFoo(AssistedDep factoryAssistedDep1);
-
- // A no-op method to test static methods are allowed
- static void staticMethod() {
- return;
- }
-
- // A no-op method to test static methods that return assisted type are allowed
- static SimpleFoo staticSimpleFooMethod() {
- return null;
- }
-
- // A no-op method to test default methods are allowed
- default void defaultMethod() {
- return;
- }
-
- // A no-op method to test default methods that return assisted type are allowed
- default SimpleFoo defaultSimpleFooMethod() {
- return null;
- }
- }
-
- @AssistedFactory
- interface ExtendedSimpleFooFactory extends SimpleFooFactory {}
-
- abstract static class BaseFoo {
- @Inject Dep4 dep4;
- }
-
- static final class Foo extends BaseFoo {
- private final Dep1 dep1;
- private final Provider<Dep2> dep2Provider;
- private final AssistedDep1 assistedDep1;
- private final AssistedDep2 assistedDep2;
- private final int assistedInt;
- private final FooFactory factory;
-
- @Inject Dep3 dep3;
-
- @AssistedInject
- Foo(
- Dep1 dep1,
- @Assisted AssistedDep1 assistedDep1,
- Provider<Dep2> dep2Provider,
- @Assisted AssistedDep2 assistedDep2,
- @Assisted int assistedInt,
- FooFactory factory) {
- this.dep1 = dep1;
- this.dep2Provider = dep2Provider;
- this.assistedDep1 = assistedDep1;
- this.assistedDep2 = assistedDep2;
- this.assistedInt = assistedInt;
- this.factory = factory;
- }
- }
-
- @AssistedFactory
- interface FooFactory {
- // Use different parameter names than Foo to make sure we're not assuming they're the same.
- Foo createFoo(
- AssistedDep1 factoryAssistedDep1, AssistedDep2 factoryAssistedDep2, int factoryAssistedInt);
- }
-
- @AssistedFactory
- abstract static class AbstractFooFactory {
- // Use different parameter names than Foo to make sure we're not assuming they're the same.
- abstract Foo createFoo(
- AssistedDep1 factoryAssistedDep1, AssistedDep2 factoryAssistedDep2, int factoryAssistedInt);
-
- // A no-op method to test static methods are allowed
- static void staticMethod() {
- return;
- }
-
- // A no-op method to test static methods that return assisted type are allowed
- static Foo staticFooMethod() {
- return null;
- }
-
- // A no-op method to test concrete methods are allowed
- void concreteMethod() {
- return;
- }
-
- // A no-op method to test concrete methods that return assisted type are allowed
- Foo concreteFooMethod() {
- return null;
- }
- }
-
- static final class NoAssistedParametersFoo extends BaseFoo {
- private final Dep1 dep1;
- private final Provider<Dep2> dep2Provider;
- private final NoAssistedParametersFooFactory factory;
-
- @Inject Dep3 dep3;
-
- @AssistedInject
- NoAssistedParametersFoo(
- Dep1 dep1, Provider<Dep2> dep2Provider, NoAssistedParametersFooFactory factory) {
- this.dep1 = dep1;
- this.dep2Provider = dep2Provider;
- this.factory = factory;
- }
- }
-
- @AssistedFactory
- interface NoAssistedParametersFooFactory {
- NoAssistedParametersFoo createNoAssistedParametersFoo();
- }
-
- @Test
- public void testNestedSimpleFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- SimpleFoo simpleFoo1 =
- DaggerAssistedFactoryTest_ParentComponent.create()
- .nestedSimpleFooFactory()
- .createSimpleFoo(assistedDep1);
- assertThat(simpleFoo1.assistedDep).isEqualTo(assistedDep1);
-
- AssistedDep2 assistedDep2 = new AssistedDep2();
- SimpleFoo simpleFoo2 =
- DaggerAssistedFactoryTest_ParentComponent.create()
- .nestedSimpleFooFactory()
- .createSimpleFoo(assistedDep2);
- assertThat(simpleFoo2.assistedDep).isEqualTo(assistedDep2);
- }
-
- @Test
- public void testNonNestedSimpleFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- SimpleFoo simpleFoo =
- DaggerAssistedFactoryTest_ParentComponent.create()
- .nonNestedSimpleFooFactory()
- .createSimpleFoo(assistedDep1);
- assertThat(simpleFoo.assistedDep).isEqualTo(assistedDep1);
- }
-
- @Test
- public void testExtendedSimpleFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- SimpleFoo simpleFoo =
- DaggerAssistedFactoryTest_ParentComponent.create()
- .extendedSimpleFooFactory()
- .createSimpleFoo(assistedDep1);
- assertThat(simpleFoo.assistedDep).isEqualTo(assistedDep1);
- }
-
- @Test
- public void testFooFactory() {
- AssistedDep1 assistedDep1 = new AssistedDep1();
- AssistedDep2 assistedDep2 = new AssistedDep2();
- int assistedInt = 7;
- Foo foo =
- DaggerAssistedFactoryTest_ParentComponent.create()
- .fooFactory()
- .createFoo(assistedDep1, assistedDep2, assistedInt);
- assertThat(foo.dep1).isNotNull();
- assertThat(foo.dep2Provider).isNotNull();
- assertThat(foo.dep2Provider.get()).isNotNull();
- assertThat(foo.dep3).isNotNull();
- assertThat(foo.dep4).isNotNull();
- assertThat(foo.assistedDep1).isEqualTo(assistedDep1);
- assertThat(foo.assistedDep2).isEqualTo(assistedDep2);
- assertThat(foo.assistedInt).isEqualTo(assistedInt);
- assertThat(foo.factory).isNotNull();
- }
-
- @Test
- public void testNoAssistedParametersFooFactory() {
- NoAssistedParametersFoo foo =
- DaggerAssistedFactoryTest_ParentComponent.create()
- .noAssistedParametersFooFactory()
- .createNoAssistedParametersFoo();
- assertThat(foo.dep1).isNotNull();
- assertThat(foo.dep2Provider).isNotNull();
- assertThat(foo.dep2Provider.get()).isNotNull();
- assertThat(foo.dep3).isNotNull();
- assertThat(foo.dep4).isNotNull();
- assertThat(foo.factory).isNotNull();
- }
-
- @Test
- public void testAssistedFactoryFromSomeEntryPoint() {
- SomeEntryPoint someEntryPoint =
- DaggerAssistedFactoryTest_ParentComponent.create().someEntryPoint();
- assertThat(someEntryPoint.nestedSimpleFooFactory).isNotNull();
- assertThat(someEntryPoint.nonNestedSimpleFooFactory).isNotNull();
- assertThat(someEntryPoint.extendedSimpleFooFactory).isNotNull();
- assertThat(someEntryPoint.fooFactory).isNotNull();
- assertThat(someEntryPoint.abstractFooFactory).isNotNull();
- assertThat(someEntryPoint.noAssistedParametersFooFactory).isNotNull();
- }
-}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryWithArrayTypesTest.java b/javatests/dagger/functional/assisted/AssistedFactoryWithArrayTypesTest.java
deleted file mode 100644
index 91f7e42..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryWithArrayTypesTest.java
+++ /dev/null
@@ -1,61 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class AssistedFactoryWithArrayTypesTest {
- @Component
- interface TestComponent {
- FooFactory fooFactory();
- }
-
- @AssistedFactory
- interface FooFactory {
- Foo create(Dep[] depArray);
- }
-
- static class Dep {}
-
- static class Foo {
- private final Dep[] depArray;
-
- @AssistedInject
- Foo(@Assisted Dep[] depArray) {
- this.depArray = depArray;
- }
- }
-
- @Test
- public void testFooFactory() {
- Dep[] depArray = {new Dep(), new Dep()};
- Foo foo =
- DaggerAssistedFactoryWithArrayTypesTest_TestComponent.create()
- .fooFactory()
- .create(depArray);
- assertThat(foo.depArray).isEqualTo(depArray);
- }
-}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryWithAssistedInjectParamTest.java b/javatests/dagger/functional/assisted/AssistedFactoryWithAssistedInjectParamTest.java
deleted file mode 100644
index 9b794fd..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryWithAssistedInjectParamTest.java
+++ /dev/null
@@ -1,74 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-// This is a regression test for https://github.com/google/dagger/issues/2278
-@RunWith(JUnit4.class)
-public final class AssistedFactoryWithAssistedInjectParamTest {
- @Component
- interface ParentComponent {
- FooFactory fooFactory();
-
- BarFactory barFactory();
- }
-
- static class Foo {
- private final Bar bar;
-
- @AssistedInject
- Foo(@Assisted Bar bar) {
- this.bar = bar;
- }
- }
-
- static class Bar {
- @AssistedInject
- Bar() {}
- }
-
- @AssistedFactory
- interface FooFactory {
- Foo create(Bar bar);
- }
-
- @AssistedFactory
- interface BarFactory {
- Bar create();
- }
-
- @Test
- public void testFooFactory() {
- ParentComponent component =
- DaggerAssistedFactoryWithAssistedInjectParamTest_ParentComponent.create();
- FooFactory fooFactory = component.fooFactory();
- BarFactory barFactory = component.barFactory();
-
- Bar bar = barFactory.create();
- Foo foo = fooFactory.create(bar);
- assertThat(foo.bar).isEqualTo(bar);
- }
-}
diff --git a/javatests/dagger/functional/assisted/AssistedFactoryWithQualifiedTypesTest.java b/javatests/dagger/functional/assisted/AssistedFactoryWithQualifiedTypesTest.java
deleted file mode 100644
index 952b94d..0000000
--- a/javatests/dagger/functional/assisted/AssistedFactoryWithQualifiedTypesTest.java
+++ /dev/null
@@ -1,151 +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.functional.assisted;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedFactory;
-import dagger.assisted.AssistedInject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-// See https://github.com/google/dagger/issues/2281
-@RunWith(JUnit4.class)
-public final class AssistedFactoryWithQualifiedTypesTest {
- @Component
- interface TestComponent {
- // Test a factory with duplicate types with unique qualifiers.
- DupeTypeFactory dupeTypeFactory();
-
- // Test a factory with duplicate qualifiers with unique types.
- DupeQualifierFactory dupeQualifierFactory();
-
- // Test a factory with unnecessary qualifiers on the factory.
- UnnecessaryQualifierFactory unnecessaryQualifierFactory();
-
- // Test a factory with different parameter order than the constructor.
- SwappedDupeTypeFactory swappedDupeTypeFactory();
- }
-
- static class DupeType {
- private final String str1;
- private final String str2;
-
- @AssistedInject
- DupeType(@Assisted("1") String str1, @Assisted("2") String str2) {
- this.str1 = str1;
- this.str2 = str2;
- }
- }
-
- @AssistedFactory
- interface DupeTypeFactory {
- DupeType create(@Assisted("1") String str1, @Assisted("2") String str2);
- }
-
- @Test
- public void testDupeTypeFactory() {
- String str1 = "str1";
- String str2 = "str2";
- DupeType dupeType =
- DaggerAssistedFactoryWithQualifiedTypesTest_TestComponent.create()
- .dupeTypeFactory()
- .create(str1, str2);
- assertThat(dupeType.str1).isEqualTo(str1);
- assertThat(dupeType.str2).isEqualTo(str2);
- }
-
- @AssistedFactory
- interface SwappedDupeTypeFactory {
- DupeType create(@Assisted("2") String str2, @Assisted("1") String str1);
- }
-
- @Test
- public void testSwappedDupeTypeFactory() {
- String str1 = "str1";
- String str2 = "str2";
- DupeType dupeType =
- DaggerAssistedFactoryWithQualifiedTypesTest_TestComponent.create()
- .swappedDupeTypeFactory()
- .create(str2, str1);
- assertThat(dupeType.str1).isEqualTo(str1);
- assertThat(dupeType.str2).isEqualTo(str2);
- }
-
- static class DupeQualifier {
- private final String str;
- private final int i;
-
- @AssistedInject
- DupeQualifier(@Assisted("1") String str, @Assisted("1") int i) {
- this.str = str;
- this.i = i;
- }
- }
-
- @AssistedFactory
- interface DupeQualifierFactory {
- DupeQualifier create(@Assisted("1") String str, @Assisted("1") int i);
- }
-
- @Test
- public void testDupeQualifierFactory() {
- String str = "str";
- int i = 11;
- DupeQualifier dupeQualifier =
- DaggerAssistedFactoryWithQualifiedTypesTest_TestComponent.create()
- .dupeQualifierFactory()
- .create(str, i);
- assertThat(dupeQualifier.str).isEqualTo(str);
- assertThat(dupeQualifier.i).isEqualTo(i);
- }
-
- static class UnnecessaryQualifier {
- private final String str;
- private final double d;
- private final int i;
-
- @AssistedInject
- UnnecessaryQualifier(@Assisted String str, @Assisted double d, @Assisted("") int i) {
- this.str = str;
- this.d = d;
- this.i = i;
- }
- }
-
- @AssistedFactory
- interface UnnecessaryQualifierFactory {
- UnnecessaryQualifier create(@Assisted int i, @Assisted("") String str, double d);
- }
-
- @Test
- public void testUnnecessaryQualifierFactory() {
- String str = "str";
- double d = 2.2;
- int i = 11;
- UnnecessaryQualifier unnecessaryQualifier =
- DaggerAssistedFactoryWithQualifiedTypesTest_TestComponent.create()
- .unnecessaryQualifierFactory()
- .create(i, str, d);
- assertThat(unnecessaryQualifier.str).isEqualTo(str);
- assertThat(unnecessaryQualifier.d).isEqualTo(d);
- assertThat(unnecessaryQualifier.i).isEqualTo(i);
- }
-}
diff --git a/javatests/dagger/functional/assisted/BUILD b/javatests/dagger/functional/assisted/BUILD
deleted file mode 100644
index 5e663e7..0000000
--- a/javatests/dagger/functional/assisted/BUILD
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Functional tests for Dagger
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "SOURCE_7_TARGET_7")
-load("//:test_defs.bzl", "GenJavaTests")
-
-package(default_visibility = ["//:src"])
-
-GenJavaTests(
- name = "assisted",
- srcs = glob(["*.java"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- lib_javacopts = SOURCE_7_TARGET_7,
- test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
- "@google_bazel_common//third_party/java/guava:testlib",
- "@google_bazel_common//third_party/java/truth",
- "@google_bazel_common//third_party/java/junit",
- "//javatests/dagger/functional/assisted/subpackage",
- ],
- # NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
- # used without Guava and jsr305 deps.
- deps = [
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/auto:factory",
- "@google_bazel_common//third_party/java/auto:value",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
diff --git a/javatests/dagger/functional/assisted/kotlin/BUILD b/javatests/dagger/functional/assisted/kotlin/BUILD
deleted file mode 100644
index 3c3421d..0000000
--- a/javatests/dagger/functional/assisted/kotlin/BUILD
+++ /dev/null
@@ -1,49 +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.
-# Description:
-# Tests for internal code for implementing Hilt processors.
-
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "SOURCE_7_TARGET_7")
-load("//:test_defs.bzl", "GenJavaTests")
-
-package(default_visibility = ["//:src"])
-
-kt_jvm_library(
- name = "KotlinAssistedInjectionClasses",
- srcs = ["KotlinAssistedInjectionClasses.kt"],
- deps = [
- "//:dagger_with_compiler",
- ],
-)
-
-GenJavaTests(
- name = "kotlin",
- srcs = glob(
- ["*.java"],
- exclude = ["*.kt"],
- ),
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- lib_javacopts = SOURCE_7_TARGET_7,
- test_only_deps = [
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
- # NOTE: This should not depend on Guava or jsr305 to ensure that Dagger can be
- # used without Guava and jsr305 deps.
- deps = [
- ":KotlinAssistedInjectionClasses",
- ],
-)
diff --git a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
deleted file mode 100644
index e78873d..0000000
--- a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionClasses.kt
+++ /dev/null
@@ -1,44 +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.functional.assisted.kotlin
-
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedFactory
-import dagger.assisted.AssistedInject
-import javax.inject.Inject
-
-class Dep @Inject constructor()
-
-class AssistedDep
-
-/** Assisted injection for a kotlin class. */
-class Foo @AssistedInject constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
-
-/** Assisted injection for a kotlin data class. */
-data class FooData @AssistedInject constructor(val dep: Dep, @Assisted val assistedDep: AssistedDep)
-
-/** Assisted factory for a kotlin class */
-@AssistedFactory
-interface FooFactory {
- fun create(assistedDep: AssistedDep): Foo
-}
-
-/** Assisted factory for a kotlin data class */
-@AssistedFactory
-interface FooDataFactory {
- fun create(assistedDep: AssistedDep): FooData
-}
diff --git a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java b/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
deleted file mode 100644
index 7c597f8..0000000
--- a/javatests/dagger/functional/assisted/kotlin/KotlinAssistedInjectionTest.java
+++ /dev/null
@@ -1,52 +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.functional.assisted.kotlin;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import dagger.Component;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-// This is a regression test for https://github.com/google/dagger/issues/2299
-@RunWith(JUnit4.class)
-public final class KotlinAssistedInjectionTest {
- @Component
- interface TestComponent {
- FooFactory fooFactory();
-
- FooDataFactory fooDataFactory();
- }
-
- @Test
- public void testFooFactory() {
- FooFactory fooFactory = DaggerKotlinAssistedInjectionTest_TestComponent.create().fooFactory();
- AssistedDep assistedDep = new AssistedDep();
- Foo foo = fooFactory.create(assistedDep);
- assertThat(foo.getAssistedDep()).isEqualTo(assistedDep);
- }
-
- @Test
- public void testFooDataFactory() {
- FooDataFactory fooDataFactory =
- DaggerKotlinAssistedInjectionTest_TestComponent.create().fooDataFactory();
- AssistedDep assistedDep = new AssistedDep();
- FooData fooData = fooDataFactory.create(assistedDep);
- assertThat(fooData.getAssistedDep()).isEqualTo(assistedDep);
- }
-}
diff --git a/javatests/dagger/functional/assisted/subpackage/AccessibleFoo.java b/javatests/dagger/functional/assisted/subpackage/AccessibleFoo.java
deleted file mode 100644
index 16d420a..0000000
--- a/javatests/dagger/functional/assisted/subpackage/AccessibleFoo.java
+++ /dev/null
@@ -1,33 +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.functional.assisted.subpackage;
-
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedInject;
-
-/** An accessible type using assisted inject from a separate package. */
-public final class AccessibleFoo {
- // Accessible for testing
- public final Dep dep;
- public final AssistedDep assistedDep;
-
- @AssistedInject
- AccessibleFoo(Dep dep, @Assisted AssistedDep assistedDep) {
- this.dep = dep;
- this.assistedDep = assistedDep;
- }
-}
diff --git a/javatests/dagger/functional/assisted/subpackage/AssistedDep.java b/javatests/dagger/functional/assisted/subpackage/AssistedDep.java
deleted file mode 100644
index b27b029..0000000
--- a/javatests/dagger/functional/assisted/subpackage/AssistedDep.java
+++ /dev/null
@@ -1,20 +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.functional.assisted.subpackage;
-
-/** An assisted dependency. */
-public final class AssistedDep {}
diff --git a/javatests/dagger/functional/assisted/subpackage/BUILD b/javatests/dagger/functional/assisted/subpackage/BUILD
deleted file mode 100644
index 644cf44..0000000
--- a/javatests/dagger/functional/assisted/subpackage/BUILD
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Functional tests for Dagger
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "subpackage",
- srcs = glob(["*.java"]),
- deps = [
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr330_inject",
- ],
-)
diff --git a/javatests/dagger/functional/assisted/subpackage/Dep.java b/javatests/dagger/functional/assisted/subpackage/Dep.java
deleted file mode 100644
index a519b3f..0000000
--- a/javatests/dagger/functional/assisted/subpackage/Dep.java
+++ /dev/null
@@ -1,25 +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.functional.assisted.subpackage;
-
-import javax.inject.Inject;
-
-/** An {@link Inject} constructor dependency. */
-public final class Dep {
- @Inject
- Dep() {}
-}
diff --git a/javatests/dagger/functional/assisted/subpackage/InaccessibleFoo.java b/javatests/dagger/functional/assisted/subpackage/InaccessibleFoo.java
deleted file mode 100644
index e093365..0000000
--- a/javatests/dagger/functional/assisted/subpackage/InaccessibleFoo.java
+++ /dev/null
@@ -1,33 +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.functional.assisted.subpackage;
-
-import dagger.assisted.Assisted;
-import dagger.assisted.AssistedInject;
-
-/** An inaccessible type using assisted inject from a separate package. */
-// TODO(bcorso): Remove public once we allow inaccessible types in fastInit.
-public final class InaccessibleFoo {
- private final Dep dep;
- private final AssistedDep assistedDep;
-
- @AssistedInject
- InaccessibleFoo(Dep dep, @Assisted AssistedDep assistedDep) {
- this.dep = dep;
- this.assistedDep = assistedDep;
- }
-}
diff --git a/javatests/dagger/functional/assisted/subpackage/InaccessibleFooFactory.java b/javatests/dagger/functional/assisted/subpackage/InaccessibleFooFactory.java
deleted file mode 100644
index a7efe57..0000000
--- a/javatests/dagger/functional/assisted/subpackage/InaccessibleFooFactory.java
+++ /dev/null
@@ -1,25 +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.functional.assisted.subpackage;
-
-import dagger.assisted.AssistedFactory;
-
-/** An accessible factory that creates an inaccessible type. */
-@AssistedFactory
-public interface InaccessibleFooFactory {
- InaccessibleFoo create(AssistedDep assistedDep);
-}
diff --git a/javatests/dagger/functional/binds/SimpleBindingModule.java b/javatests/dagger/functional/binds/SimpleBindingModule.java
index e8c3ca6..e1d5227 100644
--- a/javatests/dagger/functional/binds/SimpleBindingModule.java
+++ b/javatests/dagger/functional/binds/SimpleBindingModule.java
@@ -20,7 +20,6 @@
import dagger.Module;
import dagger.Provides;
import dagger.Reusable;
-import dagger.functional.NeedsFactory;
import dagger.functional.SomeQualifier;
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntKey;
@@ -36,12 +35,6 @@
@Module(includes = InterfaceModule.class)
abstract class SimpleBindingModule {
-
- // Regression test for b/161853413 that binds an implementation that extends a generated class
- // that is processed in the same build unit as the @Binds method.
- @Binds
- abstract NeedsFactory.SomethingFactory bindFooFactory(NeedsFactory.SomethingFactoryImpl impl);
-
@Binds
abstract Object bindObject(FooOfStrings impl);
@@ -154,7 +147,7 @@
@IntKey(123)
@SomeQualifier
abstract Object bindFooOfStringsIntoQualifiedMap(FooOfStrings fooOfStrings);
-
+
@Provides
@Named("For-123")
static String provide123String() {
diff --git a/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.java b/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.java
index 9b1447c..07ebbc8 100644
--- a/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.java
+++ b/javatests/dagger/functional/builder/BuildMethodCovariantReturnInherited.java
@@ -18,7 +18,6 @@
import dagger.Component;
-
interface BuildMethodCovariantReturnInherited {
@Component
interface Simple {
diff --git a/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.java b/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.java
index d47c892..33d3816 100644
--- a/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.java
+++ b/javatests/dagger/functional/builder/BuilderBindsInstanceParameterTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-
import dagger.BindsInstance;
import dagger.Component;
import org.junit.Test;
diff --git a/javatests/dagger/functional/builder/GenericParent.java b/javatests/dagger/functional/builder/GenericParent.java
index 949514e..9563103 100644
--- a/javatests/dagger/functional/builder/GenericParent.java
+++ b/javatests/dagger/functional/builder/GenericParent.java
@@ -16,7 +16,6 @@
package dagger.functional.builder;
-
interface GenericParent<B> {
B subcomponentBuilder();
}
diff --git a/javatests/dagger/functional/cycle/Cycles.java b/javatests/dagger/functional/cycle/Cycles.java
index e17d619..f4faeab 100644
--- a/javatests/dagger/functional/cycle/Cycles.java
+++ b/javatests/dagger/functional/cycle/Cycles.java
@@ -97,7 +97,7 @@
this.sProvider = sProvider;
}
}
-
+
static class X {
public final Y y;
@@ -143,10 +143,10 @@
A a();
C c();
-
+
ChildCycleComponent child();
}
-
+
@Module
static class CycleModule {
@Provides
@@ -160,12 +160,12 @@
interface SelfCycleComponent {
S s();
}
-
+
@Subcomponent
interface ChildCycleComponent {
@SuppressWarnings("dependency-cycle")
A a();
-
+
@SuppressWarnings("dependency-cycle")
Object object();
}
diff --git a/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java b/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java
index d77a713..b77ee3e 100644
--- a/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java
+++ b/javatests/dagger/functional/cycle/DoubleCheckCycleTest.java
@@ -181,7 +181,6 @@
})
.build();
-
int numThreads = 10;
CountDownLatch remainingTasks = new CountDownLatch(numThreads);
List<Thread> tasks = new ArrayList<>(numThreads);
diff --git a/javatests/dagger/functional/guava/BUILD b/javatests/dagger/functional/guava/BUILD
index ed8efd3..66492eb 100644
--- a/javatests/dagger/functional/guava/BUILD
+++ b/javatests/dagger/functional/guava/BUILD
@@ -15,20 +15,19 @@
# Description:
# Functional tests for Dagger that depend on Guava
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "guava_tests",
srcs = glob(["**/*.java"]),
javacopts = DOCLINT_HTML_AND_SYNTAX,
deps = [
"//:dagger_with_compiler",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
"@google_bazel_common//third_party/java/auto:value",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr305_annotations",
"@google_bazel_common//third_party/java/jsr330_inject",
"@google_bazel_common//third_party/java/junit",
diff --git a/javatests/dagger/functional/jdk8/BUILD b/javatests/dagger/functional/jdk8/BUILD
index 5e35c75..6b76ba3 100644
--- a/javatests/dagger/functional/jdk8/BUILD
+++ b/javatests/dagger/functional/jdk8/BUILD
@@ -15,20 +15,19 @@
# Description:
# Functional tests for Dagger that depend on Guava
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "jdk8_tests",
srcs = glob(["**/*.java"]),
javacopts = DOCLINT_HTML_AND_SYNTAX,
test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
+ "@google_bazel_common//third_party/java/truth:truth8",
],
deps = [
"//:dagger_with_compiler",
diff --git a/javatests/dagger/functional/kotlin/BUILD b/javatests/dagger/functional/kotlin/BUILD
deleted file mode 100644
index 529eb69..0000000
--- a/javatests/dagger/functional/kotlin/BUILD
+++ /dev/null
@@ -1,79 +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.
-#
-# Description:
-# Functional test code for Dagger-Android
-
-load("@rules_java//java:defs.bzl", "java_library")
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-load("//:test_defs.bzl", "GenJavaTests")
-
-package(default_visibility = ["//:src"])
-
-kt_jvm_library(
- name = "kotlin",
- srcs = glob(
- [
- "*.java",
- "*.kt",
- ],
- exclude = [
- "*Test.java",
- "JavaTestQualifier.java",
- "FooWithInjectedQualifier.kt",
- ],
- ),
- # TODO(danysantiago): Remove 'plugins' once kt_jvm_library supports 'exported_plugins'.
- plugins = ["//javatests/dagger/functional/kotlin/processor:plugin"],
- deps = [
- ":foo_with_injected_qualifier",
- ":java_qualifier",
- "//:dagger_with_compiler",
- "//javatests/dagger/functional/kotlin/processor:annotation",
- ],
-)
-
-kt_jvm_library(
- name = "foo_with_injected_qualifier",
- srcs = ["FooWithInjectedQualifier.kt"],
- deps = [
- ":java_qualifier",
- "//:dagger_with_compiler",
- ],
-)
-
-java_library(
- name = "java_qualifier",
- srcs = ["JavaTestQualifier.java"],
- deps = [
- "//:dagger_with_compiler",
- ],
-)
-
-GenJavaTests(
- name = "kotlin_tests",
- srcs = glob(["*Test.java"]),
- functional = True,
- test_only_deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
- deps = [
- ":foo_with_injected_qualifier",
- ":kotlin",
- "//:dagger_with_compiler",
- ],
-)
diff --git a/javatests/dagger/functional/kotlin/CompanionModuleTest.java b/javatests/dagger/functional/kotlin/CompanionModuleTest.java
deleted file mode 100644
index 591c5d6..0000000
--- a/javatests/dagger/functional/kotlin/CompanionModuleTest.java
+++ /dev/null
@@ -1,43 +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.functional.kotlin;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class CompanionModuleTest {
-
- @Test
- public void verifyCompanionModule() {
- TestKotlinComponentWithCompanionModule component =
- DaggerTestKotlinComponentWithCompanionModule.create();
- assertThat(component.getDataA()).isNotNull();
- assertThat(component.getDataB()).isNotNull();
- assertThat(component.getBoolean()).isTrue();
- assertThat(component.getStringType()).isNotNull();
- assertThat(component.getCatNamedStringType()).isEqualTo("Cat");
- assertThat(component.getDogNamedStringType()).isEqualTo("Dog");
- assertThat(component.getInterface()).isNotNull();
- assertThat(component.getLong()).isEqualTo(4L);
- assertThat(component.getDouble()).isEqualTo(1.0);
- assertThat(component.getInteger()).isEqualTo(2);
- }
-}
diff --git a/javatests/dagger/functional/kotlin/FooWithInjectedQualifier.kt b/javatests/dagger/functional/kotlin/FooWithInjectedQualifier.kt
deleted file mode 100644
index 6602f10..0000000
--- a/javatests/dagger/functional/kotlin/FooWithInjectedQualifier.kt
+++ /dev/null
@@ -1,33 +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.functional.kotlin
-
-import javax.inject.Inject
-
-class FooWithInjectedQualifier {
- @Inject
- @JavaTestQualifier
- lateinit var qualifiedString: String
-
- @Inject
- @field:JavaTestQualifier
- @NotAQualifier
- lateinit var qualifiedStringWithPropertyAnnotaion: String
-}
-
-@Target(AnnotationTarget.PROPERTY)
-annotation class NotAQualifier
diff --git a/javatests/dagger/functional/kotlin/JavaTestQualifier.java b/javatests/dagger/functional/kotlin/JavaTestQualifier.java
deleted file mode 100644
index 156f436..0000000
--- a/javatests/dagger/functional/kotlin/JavaTestQualifier.java
+++ /dev/null
@@ -1,26 +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.functional.kotlin;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Retention;
-import javax.inject.Qualifier;
-
-@Qualifier
-@Retention(RUNTIME)
-public @interface JavaTestQualifier {}
diff --git a/javatests/dagger/functional/kotlin/JavaTestQualifierWithTarget.java b/javatests/dagger/functional/kotlin/JavaTestQualifierWithTarget.java
deleted file mode 100644
index 3bc2e4e..0000000
--- a/javatests/dagger/functional/kotlin/JavaTestQualifierWithTarget.java
+++ /dev/null
@@ -1,29 +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.functional.kotlin;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-import javax.inject.Qualifier;
-
-@Qualifier
-@Retention(RUNTIME)
-@Target({ElementType.FIELD, ElementType.METHOD})
-public @interface JavaTestQualifierWithTarget {}
diff --git a/javatests/dagger/functional/kotlin/ObjectModuleTest.java b/javatests/dagger/functional/kotlin/ObjectModuleTest.java
deleted file mode 100644
index a37be44..0000000
--- a/javatests/dagger/functional/kotlin/ObjectModuleTest.java
+++ /dev/null
@@ -1,39 +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.functional.kotlin;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ObjectModuleTest {
-
- @Test
- public void verifyObjectModule() {
- TestKotlinComponentWithObjectModule component =
- DaggerTestKotlinComponentWithObjectModule.create();
- assertThat(component.getDataA()).isNotNull();
- assertThat(component.getDataAFromNestedModule()).isNotNull();
- assertThat(component.getDataB()).isNotNull();
- assertThat(component.getSetOfDataA()).isNotNull();
- assertThat(component.getSetOfDataA()).hasSize(1);
- assertThat(component.getPrimitiveType()).isTrue();
- }
-}
diff --git a/javatests/dagger/functional/kotlin/PropertyQualifierTest.java b/javatests/dagger/functional/kotlin/PropertyQualifierTest.java
deleted file mode 100644
index e0ebf3c..0000000
--- a/javatests/dagger/functional/kotlin/PropertyQualifierTest.java
+++ /dev/null
@@ -1,50 +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.functional.kotlin;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class PropertyQualifierTest {
-
- @Test
- public void verifyQualifiedBinding() {
- TestMemberInjectedClassWithQualifier injectedClass = new TestMemberInjectedClassWithQualifier();
- DaggerTestKotlinComponentWithQualifier.create().inject(injectedClass);
-
- assertThat(injectedClass.javaDataA).isNotNull();
- assertThat(injectedClass.javaDataB).isNotNull();
- assertThat(injectedClass.javaWithTargetDataA).isNotNull();
- assertThat(injectedClass.kotlinDataA).isNotNull();
- assertThat(injectedClass.dataWithConstructionInjection).isNotNull();
- assertThat(injectedClass.dataWithConstructionInjection.getData()).isNotNull();
- }
-
- @Test
- public void verifyQualifiedBinding_acrossCompilation() {
- FooWithInjectedQualifier injectedClass = new FooWithInjectedQualifier();
- DaggerTestKotlinComponentWithQualifier.create().inject(injectedClass);
-
- assertThat(injectedClass.getQualifiedString()).isEqualTo("qualified string");
- assertThat(injectedClass.getQualifiedStringWithPropertyAnnotaion())
- .isEqualTo("qualified string");
- }
-}
diff --git a/javatests/dagger/functional/kotlin/PublicModuleWithNonPublicInclude.java b/javatests/dagger/functional/kotlin/PublicModuleWithNonPublicInclude.java
deleted file mode 100644
index f927186..0000000
--- a/javatests/dagger/functional/kotlin/PublicModuleWithNonPublicInclude.java
+++ /dev/null
@@ -1,23 +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.functional.kotlin;
-
-import dagger.Module;
-
-/** Verifies that a non-public included Kotlin object module does not fail compilation. */
-@Module(includes = {NonPublicObjectModule.class})
-public class PublicModuleWithNonPublicInclude {}
diff --git a/javatests/dagger/functional/kotlin/TestComponentWithCompanionModule.kt b/javatests/dagger/functional/kotlin/TestComponentWithCompanionModule.kt
deleted file mode 100644
index 1eaa3f5..0000000
--- a/javatests/dagger/functional/kotlin/TestComponentWithCompanionModule.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-package dagger.functional.kotlin
-
-import dagger.Binds
-import dagger.Component
-import dagger.Module
-import dagger.Provides
-import javax.inject.Named
-
-@Component(
- modules = [
- TestKotlinModuleWithCompanion::class,
- TestKotlinModuleWithNamedCompanion::class,
- TestKotlinAbstractModuleWithCompanion::class,
- TestKotlinWorkaroundModuleWithCompanion::class,
- TestKotlinModuleWithPrivateCompanion::class
- ]
-)
-interface TestKotlinComponentWithCompanionModule {
- fun getDataA(): TestDataA
- fun getDataB(): TestDataB
- fun getBoolean(): Boolean
- fun getStringType(): String
- @Named("Cat")
- fun getCatNamedStringType(): String
- @Named("Dog")
- fun getDogNamedStringType(): String
-
- fun getInterface(): TestInterface
- fun getLong(): Long
- fun getDouble(): Double
- fun getInteger(): Int
-}
-
-@Module
-class TestKotlinModuleWithCompanion {
- @Provides
- fun provideDataA() = TestDataA("test")
-
- companion object {
- @Provides
- fun provideDataB() = TestDataB("test")
-
- @Provides
- fun provideBoolean(): Boolean = true
- }
-}
-
-@Module
-class TestKotlinModuleWithNamedCompanion {
-
- @Provides
- @Named("Cat")
- fun provideNamedString() = "Cat"
-
- companion object Foo {
- @Provides
- fun provideStringType(): String = ""
- }
-}
-
-@Module
-abstract class TestKotlinAbstractModuleWithCompanion {
-
- @Binds
- abstract fun bindInterface(injectable: TestInjectable): TestInterface
-
- companion object {
- @Provides
- fun provideLong() = 4L
- }
-}
-
-@Module
-class TestKotlinWorkaroundModuleWithCompanion {
-
- @Provides
- fun provideDouble() = 1.0
-
- @Module
- companion object {
- @Provides
- @JvmStatic
- fun provideInteger() = 2
- }
-}
-
-@Module
-class TestKotlinModuleWithPrivateCompanion {
-
- @Provides
- @Named("Dog")
- fun getNamedStringType() = "Dog"
-
- private companion object {
- fun randomFunction() = ""
- }
-}
diff --git a/javatests/dagger/functional/kotlin/TestComponentWithObjectModule.kt b/javatests/dagger/functional/kotlin/TestComponentWithObjectModule.kt
deleted file mode 100644
index e390aba..0000000
--- a/javatests/dagger/functional/kotlin/TestComponentWithObjectModule.kt
+++ /dev/null
@@ -1,70 +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.functional.kotlin
-
-import dagger.Component
-import dagger.Module
-import dagger.Provides
-import dagger.multibindings.IntoSet
-import javax.inject.Named
-
-@Component(
- modules = [
- TestKotlinObjectModule::class,
- TestModuleForNesting.TestNestedKotlinObjectModule::class
- ]
-)
-interface TestKotlinComponentWithObjectModule {
- fun getDataA(): TestDataA
- @Named("nested-data-a")
- fun getDataAFromNestedModule(): TestDataA
- fun getDataB(): TestDataB
- fun getSetOfDataA(): Set<TestDataA>
- fun getPrimitiveType(): Boolean
-}
-
-@Module
-object TestKotlinObjectModule {
- @Provides
- fun provideDataA() = TestDataA("test")
-
- @Provides
- fun providePrimitiveType(): Boolean = true
-
- @Provides
- @JvmStatic
- fun provideDataB() = TestDataB("test")
-
- @Provides
- @IntoSet
- fun provideIntoMapDataA() = TestDataA("set-test")
-}
-
-class TestModuleForNesting {
- @Module
- object TestNestedKotlinObjectModule {
- @Provides
- @Named("nested-data-a")
- fun provideDataA() = TestDataA("test")
- }
-}
-
-@Module
-private object NonPublicObjectModule {
- @Provides
- fun provideInt() = 42
-}
diff --git a/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt b/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt
deleted file mode 100644
index 9aeb2d8..0000000
--- a/javatests/dagger/functional/kotlin/TestComponentWithQualifier.kt
+++ /dev/null
@@ -1,87 +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.functional.kotlin
-
-import dagger.Component
-import dagger.Module
-import dagger.Provides
-import dagger.functional.kotlin.processor.TriggerGeneratedTypeProcessor
-import javax.inject.Inject
-
-@Component(modules = [TestKotlinModuleWithQualifier::class])
-interface TestKotlinComponentWithQualifier {
- fun inject(testInjectedClassWithQualifier: TestMemberInjectedClassWithQualifier)
- fun inject(fooWithInjectedQualifier: FooWithInjectedQualifier)
-}
-
-@Module
-class TestKotlinModuleWithQualifier {
- @Provides
- @JavaTestQualifier
- fun provideJavaDataA() = TestDataA("test")
-
- @Provides
- @JavaTestQualifier
- fun provideJavaDataB() = TestDataB("test")
-
- @Provides
- @JavaTestQualifierWithTarget
- fun provideJavaWithTargetDataA() = TestDataA("test")
-
- @Provides
- @KotlinTestQualifier
- fun provideKotlinDataA() = TestDataA("test")
-
- @Provides
- @JavaTestQualifier
- fun provideString() = "qualified string"
-}
-
-class TestConstructionInjectedClassWithQualifier @Inject constructor(
- @JavaTestQualifier val data: TestDataA
-)
-
-@TriggerGeneratedTypeProcessor
-class TestMemberInjectedClassWithQualifier {
- @Inject
- @JavaTestQualifier
- lateinit var javaDataA: TestDataA
-
- @Inject
- @field:JavaTestQualifier
- lateinit var javaDataB: TestDataB
-
- @Inject
- @JavaTestQualifierWithTarget
- lateinit var javaWithTargetDataA: TestDataA
-
- @Inject
- @JavaTestQualifier
- lateinit var kotlinDataA: TestDataA
-
- @Inject
- lateinit var dataWithConstructionInjection: TestConstructionInjectedClassWithQualifier
-
- val noBackingFieldProperty: Int
- get() = 0
-
- val delegatedProperty by lazy { "" }
-
- val generatedTypeProperty = dagger.functional.kotlin.GeneratedType()
-
- val generatedTypeDelegatedProperty by lazy { dagger.functional.kotlin.GeneratedType() }
-}
diff --git a/javatests/dagger/functional/kotlin/TestKotlinClasses.kt b/javatests/dagger/functional/kotlin/TestKotlinClasses.kt
deleted file mode 100644
index 5d151fc..0000000
--- a/javatests/dagger/functional/kotlin/TestKotlinClasses.kt
+++ /dev/null
@@ -1,30 +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.functional.kotlin
-
-import javax.inject.Inject
-import javax.inject.Qualifier
-
-data class TestDataA(val data: String)
-data class TestDataB(val data: String)
-
-interface TestInterface
-class TestInjectable @Inject constructor() : TestInterface
-
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-annotation class KotlinTestQualifier
diff --git a/javatests/dagger/functional/kotlin/processor/BUILD b/javatests/dagger/functional/kotlin/processor/BUILD
deleted file mode 100644
index 31a45c7..0000000
--- a/javatests/dagger/functional/kotlin/processor/BUILD
+++ /dev/null
@@ -1,37 +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.
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-
-package(default_visibility = ["//:src"])
-
-java_plugin(
- name = "plugin",
- generates_api = 1,
- processor_class = "dagger.functional.kotlin.processor.TestGeneratedTypeProcessor",
- deps = [":processor"],
-)
-
-kt_jvm_library(
- name = "processor",
- srcs = ["TestGeneratedTypeProcessor.kt"],
- deps = [
- "@google_bazel_common//third_party/java/auto:service",
- "@google_bazel_common//third_party/java/javapoet",
- ],
-)
-
-kt_jvm_library(
- name = "annotation",
- srcs = ["TriggerGeneratedTypeProcessor.kt"],
-)
diff --git a/javatests/dagger/functional/kotlin/processor/TestGeneratedTypeProcessor.kt b/javatests/dagger/functional/kotlin/processor/TestGeneratedTypeProcessor.kt
deleted file mode 100644
index 4a1d6e2..0000000
--- a/javatests/dagger/functional/kotlin/processor/TestGeneratedTypeProcessor.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-package dagger.functional.kotlin.processor
-
-import com.google.auto.service.AutoService
-import com.squareup.javapoet.JavaFile
-import com.squareup.javapoet.TypeSpec
-import javax.annotation.processing.AbstractProcessor
-import javax.annotation.processing.Processor
-import javax.annotation.processing.RoundEnvironment
-import javax.lang.model.SourceVersion
-import javax.lang.model.element.Modifier
-import javax.lang.model.element.TypeElement
-
-/**
- * A processor to be used in functional tests that will generate a simple class with fqname
- * 'dagger.functional.kotlin.GeneratedType'. This processor is useful for testing situations
- * with KAPT where a type is not resolvable and for which KAPT will generate stubs containing
- * the 'error.NonExistentClass' type.
- */
-@AutoService(Processor::class)
-class TestGeneratedTypeProcessor : AbstractProcessor() {
-
- private var isSourceGenerated = false
-
- override fun getSupportedAnnotationTypes() =
- mutableSetOf("dagger.functional.kotlin.processor.TriggerGeneratedTypeProcessor")
-
- override fun getSupportedSourceVersion() = SourceVersion.latestSupported()
-
- override fun process(
- annotations: MutableSet<out TypeElement>,
- roundEnv: RoundEnvironment
- ): Boolean {
- if (isSourceGenerated) {
- return false
- }
-
- JavaFile.builder(
- "dagger.functional.kotlin",
- TypeSpec.classBuilder("GeneratedType")
- .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
- .build()
- ).build().writeTo(processingEnv.filer)
-
- isSourceGenerated = true
-
- return false
- }
-}
diff --git a/javatests/dagger/functional/kotlin/processor/TriggerGeneratedTypeProcessor.kt b/javatests/dagger/functional/kotlin/processor/TriggerGeneratedTypeProcessor.kt
deleted file mode 100644
index c240fd3..0000000
--- a/javatests/dagger/functional/kotlin/processor/TriggerGeneratedTypeProcessor.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package dagger.functional.kotlin.processor
-
-@Retention(AnnotationRetention.BINARY)
-annotation class TriggerGeneratedTypeProcessor
diff --git a/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java b/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java
index 4a08455..3519348 100644
--- a/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java
+++ b/javatests/dagger/functional/membersinject/MembersInjectGenericParent.java
@@ -18,7 +18,6 @@
import javax.inject.Inject;
-
class MembersInjectGenericParent<T> {
@Inject T t;
diff --git a/javatests/dagger/functional/membersinject/MembersInjectModule.java b/javatests/dagger/functional/membersinject/MembersInjectModule.java
index 6e182dd..d60a7d1 100644
--- a/javatests/dagger/functional/membersinject/MembersInjectModule.java
+++ b/javatests/dagger/functional/membersinject/MembersInjectModule.java
@@ -26,7 +26,7 @@
@Provides int[] provideIntArray() { return new int[10]; }
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings("unchecked")
@Provides MembersInjectGenericParent<String[]>[] provideFooArrayOfStringArray() { return new MembersInjectGenericParent[10]; }
}
diff --git a/javatests/dagger/functional/membersinject/MembersInjectTest.java b/javatests/dagger/functional/membersinject/MembersInjectTest.java
index 31e4f45..0617fd5 100644
--- a/javatests/dagger/functional/membersinject/MembersInjectTest.java
+++ b/javatests/dagger/functional/membersinject/MembersInjectTest.java
@@ -18,15 +18,12 @@
import static com.google.common.truth.Truth.assertThat;
-import dagger.BindsInstance;
-import dagger.Component;
import dagger.MembersInjector;
import dagger.functional.multipackage.DaggerMembersInjectionVisibilityComponent;
import dagger.functional.multipackage.MembersInjectionVisibilityComponent;
import dagger.functional.multipackage.a.AGrandchild;
import dagger.functional.multipackage.a.AParent;
import dagger.functional.multipackage.b.BChild;
-import javax.inject.Inject;
import javax.inject.Provider;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -96,35 +93,4 @@
injector.injectMembers(child);
assertThat(child.t).isEqualTo("field!");
}
-
- public static final class A extends B {
- // No injected members
- }
-
- public static class B extends C {
- // No injected members
- }
-
- public static class C {
- @Inject String value;
- }
-
- @Component
- interface NonLocalMembersComponent {
- MembersInjector<A> getAMembersInjector();
-
- @Component.Factory
- interface Factory {
- NonLocalMembersComponent create(@BindsInstance String value);
- }
- }
-
- @Test
- public void testNonLocalMembersInjection() {
- MembersInjector<A> membersInjector = DaggerMembersInjectTest_NonLocalMembersComponent.factory()
- .create("test").getAMembersInjector();
- A testA = new A();
- membersInjector.injectMembers(testA);
- assertThat(testA.value).isEqualTo("test");
- }
}
diff --git a/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java b/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java
deleted file mode 100644
index 7cd97d9..0000000
--- a/javatests/dagger/functional/membersinject/MembersWithInstanceNameTest.java
+++ /dev/null
@@ -1,59 +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.functional.membersinject;
-
-import static 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)
-public final class MembersWithInstanceNameTest {
-
- static final class Foo {
- // Checks that member injection fields can use "instance" as a name (b/175818837).
- @Inject String instance;
-
- @Inject Foo() {}
- }
-
- @Module
- interface TestModule {
- @Provides
- static String provideString() {
- return "test";
- }
- }
-
- @Component(modules = TestModule.class)
- interface TestComponent {
- Foo foo();
- }
-
- @Test
- public void testMemberWithInstanceName() {
- TestComponent component = DaggerMembersWithInstanceNameTest_TestComponent.create();
- Foo foo = component.foo();
- assertThat(foo).isNotNull();
- assertThat(foo.instance).isEqualTo("test");
- }
-}
diff --git a/javatests/dagger/functional/modules/ModuleIncludesTest.java b/javatests/dagger/functional/modules/ModuleIncludesTest.java
index 474cb80..38f7d97 100644
--- a/javatests/dagger/functional/modules/ModuleIncludesTest.java
+++ b/javatests/dagger/functional/modules/ModuleIncludesTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import dagger.Component;
-import dagger.functional.modules.subpackage.FooForProvision;
import dagger.functional.modules.subpackage.PublicModule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,8 +30,6 @@
@Component(modules = PublicModule.class)
interface TestComponent {
Object object();
-
- FooForProvision fooForProvision();
}
@Test
diff --git a/javatests/dagger/functional/modules/subpackage/FooForProvision.java b/javatests/dagger/functional/modules/subpackage/FooForProvision.java
deleted file mode 100644
index 60b4482..0000000
--- a/javatests/dagger/functional/modules/subpackage/FooForProvision.java
+++ /dev/null
@@ -1,20 +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.functional.modules.subpackage;
-
-/** This object is provisioned by NonAbstractPackagePrivate module */
-public class FooForProvision {}
diff --git a/javatests/dagger/functional/modules/subpackage/NonAbstractPackagePrivateModule.java b/javatests/dagger/functional/modules/subpackage/NonAbstractPackagePrivateModule.java
deleted file mode 100644
index 47d2441..0000000
--- a/javatests/dagger/functional/modules/subpackage/NonAbstractPackagePrivateModule.java
+++ /dev/null
@@ -1,36 +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.functional.modules.subpackage;
-
-import dagger.Module;
-import dagger.Provides;
-
-/**
- * We needed a separate test for non-abstract transitively included pkg-private modules. The reason
- * is that this caused a build failures when the component was generated in a separate package
- * because the generated no-op method references the inaccessible package-private type, so we
- * omitted those no-op methods to support such modules.
- */
-@Module
-class NonAbstractPackagePrivateModule {
- @Provides
- static FooForProvision provideFoo() {
- return new FooForProvision();
- }
-
- private NonAbstractPackagePrivateModule() {}
-}
diff --git a/javatests/dagger/functional/modules/subpackage/PublicModule.java b/javatests/dagger/functional/modules/subpackage/PublicModule.java
index 9eade52..7c5fd29 100644
--- a/javatests/dagger/functional/modules/subpackage/PublicModule.java
+++ b/javatests/dagger/functional/modules/subpackage/PublicModule.java
@@ -19,7 +19,7 @@
import dagger.Module;
import dagger.Provides;
-@Module(includes = {PackagePrivateModule.class, NonAbstractPackagePrivateModule.class})
+@Module(includes = PackagePrivateModule.class)
public abstract class PublicModule {
@Provides
static int provideInt() {
diff --git a/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java b/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
index 801d120..f2b5598 100644
--- a/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
+++ b/javatests/dagger/functional/multibindings/ComplexMapKeysInDifferentOrderTest.java
@@ -17,7 +17,6 @@
package dagger.functional.multibindings;
import static com.google.common.truth.Truth.assertThat;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.auto.value.AutoAnnotation;
import dagger.Component;
@@ -25,7 +24,6 @@
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
-import java.lang.annotation.Retention;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,7 +31,6 @@
@RunWith(JUnit4.class)
public final class ComplexMapKeysInDifferentOrderTest {
- @Retention(RUNTIME)
@MapKey(unwrapValue = false)
@interface ComplexMapKey {
int i();
diff --git a/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java b/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java
index 70260e7..f188405 100644
--- a/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java
+++ b/javatests/dagger/functional/multibindings/MapKeyWithDefaultTest.java
@@ -17,7 +17,6 @@
package dagger.functional.multibindings;
import static com.google.common.truth.Truth.assertThat;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.auto.value.AutoAnnotation;
import dagger.Component;
@@ -25,7 +24,6 @@
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
-import java.lang.annotation.Retention;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,7 +31,6 @@
@RunWith(JUnit4.class)
public final class MapKeyWithDefaultTest {
- @Retention(RUNTIME)
@MapKey(unwrapValue = false)
@interface MapKeyWithDefault {
boolean hasDefault() default true;
diff --git a/javatests/dagger/functional/producers/BUILD b/javatests/dagger/functional/producers/BUILD
index f69b3cb..36c9701 100644
--- a/javatests/dagger/functional/producers/BUILD
+++ b/javatests/dagger/functional/producers/BUILD
@@ -15,6 +15,8 @@
# Description:
# Functional tests for Dagger Producers
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
@@ -23,24 +25,20 @@
)
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "producers-functional-tests",
srcs = glob(["**/*.java"]),
- javacopts = DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
- lib_javacopts = SOURCE_7_TARGET_7,
+ javacopts = SOURCE_7_TARGET_7 + DOCLINT_HTML_AND_SYNTAX + DOCLINT_REFERENCES,
deps = [
"//:producers_with_compiler",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
"@google_bazel_common//third_party/java/auto:value",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr305_annotations",
"@google_bazel_common//third_party/java/jsr330_inject",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/mockito",
"@google_bazel_common//third_party/java/truth",
+ "@google_bazel_common//third_party/java/truth:truth8",
],
)
diff --git a/javatests/dagger/functional/producers/ComponentDependenciesTest.java b/javatests/dagger/functional/producers/ComponentDependenciesTest.java
deleted file mode 100644
index d4ad9f0..0000000
--- a/javatests/dagger/functional/producers/ComponentDependenciesTest.java
+++ /dev/null
@@ -1,96 +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.functional.producers;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import dagger.producers.ProductionComponent;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests component dependencies.
- */
-@RunWith(JUnit4.class)
-public final class ComponentDependenciesTest {
- public interface One {
- ListenableFuture<String> getString();
- }
-
- public interface Two {
- ListenableFuture<String> getString();
- }
-
- public interface Merged extends One, Two {
- }
-
- @ProductionComponent(dependencies = Merged.class)
- interface TestProductionComponent {
- ListenableFuture<String> getString();
-
- @ProductionComponent.Builder
- interface Builder {
- Builder dep(Merged dep);
-
- TestProductionComponent build();
- }
- }
-
- @Test
- public void testSameMethodTwiceProduction() throws Exception {
- TestProductionComponent component =
- DaggerComponentDependenciesTest_TestProductionComponent.builder().dep(
- () -> Futures.immediateFuture("test")).build();
- assertThat(component.getString().get()).isEqualTo("test");
- }
-
- public interface OneOverride {
- ListenableFuture<?> getString();
- }
-
- public interface TwoOverride {
- ListenableFuture<?> getString();
- }
-
- public interface MergedOverride extends OneOverride, TwoOverride {
- @Override
- ListenableFuture<String> getString();
- }
-
- @ProductionComponent(dependencies = MergedOverride.class)
- interface TestOverrideComponent {
- ListenableFuture<String> getString();
-
- @ProductionComponent.Builder
- interface Builder {
- Builder dep(MergedOverride dep);
-
- TestOverrideComponent build();
- }
- }
-
- @Test
- public void testPolymorphicOverridesStillCompiles() throws Exception {
- TestOverrideComponent component =
- DaggerComponentDependenciesTest_TestOverrideComponent.builder().dep(
- () -> Futures.immediateFuture("test")).build();
- assertThat(component.getString().get()).isEqualTo("test");
- }
-}
diff --git a/javatests/dagger/functional/producers/ProducerFactoryTest.java b/javatests/dagger/functional/producers/ProducerFactoryTest.java
index 6df526e..c85e342 100644
--- a/javatests/dagger/functional/producers/ProducerFactoryTest.java
+++ b/javatests/dagger/functional/producers/ProducerFactoryTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.when;
diff --git a/javatests/dagger/functional/producers/monitoring/MonitoringTest.java b/javatests/dagger/functional/producers/monitoring/MonitoringTest.java
index 32007a9..543835f 100644
--- a/javatests/dagger/functional/producers/monitoring/MonitoringTest.java
+++ b/javatests/dagger/functional/producers/monitoring/MonitoringTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions;
diff --git a/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java b/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
index a5eb8a3..fa5c6ee 100644
--- a/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
+++ b/javatests/dagger/functional/producers/multibindings/MultibindingComponent.java
@@ -30,7 +30,6 @@
import java.util.Map;
import java.util.Set;
-
@ProductionComponent(
modules = {ExecutorModule.class, MultibindingProducerModule.class, MultibindingModule.class}
)
diff --git a/javatests/dagger/functional/spi/BUILD b/javatests/dagger/functional/spi/BUILD
index 8119bdd..fffaddb 100644
--- a/javatests/dagger/functional/spi/BUILD
+++ b/javatests/dagger/functional/spi/BUILD
@@ -15,19 +15,18 @@
# Description:
# Functional tests for the experimental Dagger SPI
-load("@rules_java//java:defs.bzl", "java_library", "java_plugin")
-load("//:test_defs.bzl", "GenJavaTests")
-
package(default_visibility = ["//:src"])
+load("//:test_defs.bzl", "GenJavaTests")
+
java_plugin(
name = "test_plugin",
srcs = ["TestPlugin.java"],
deps = [
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "//java/dagger/model",
"//java/dagger/spi",
"@google_bazel_common//third_party/java/auto:service",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
],
)
diff --git a/javatests/dagger/functional/subcomponent/GenericParentComponent.java b/javatests/dagger/functional/subcomponent/GenericParentComponent.java
index 10745d7..f49083b 100644
--- a/javatests/dagger/functional/subcomponent/GenericParentComponent.java
+++ b/javatests/dagger/functional/subcomponent/GenericParentComponent.java
@@ -16,7 +16,6 @@
package dagger.functional.subcomponent;
-
interface GenericParentComponent<B> {
B subcomponent();
}
diff --git a/javatests/dagger/functional/subcomponent/SubcomponentTest.java b/javatests/dagger/functional/subcomponent/SubcomponentTest.java
index 380322b..c34de0a 100644
--- a/javatests/dagger/functional/subcomponent/SubcomponentTest.java
+++ b/javatests/dagger/functional/subcomponent/SubcomponentTest.java
@@ -50,7 +50,6 @@
this.childComponent = childComponent;
}
-
@Test
public void scopePropagatesUpward_class() {
assertThat(childComponent.requiresSingleton().singletonType())
diff --git a/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java b/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java
index 846ceb0..7cb4fce 100644
--- a/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java
+++ b/javatests/dagger/functional/subcomponent/hiding/ChildComponent.java
@@ -16,7 +16,6 @@
package dagger.functional.subcomponent.hiding;
-
import dagger.Subcomponent;
@Subcomponent(modules = dagger.functional.subcomponent.hiding.b.CommonModuleName.class)
diff --git a/javatests/dagger/functional/tck/BUILD b/javatests/dagger/functional/tck/BUILD
index 9cad2a0..7526bf0 100644
--- a/javatests/dagger/functional/tck/BUILD
+++ b/javatests/dagger/functional/tck/BUILD
@@ -15,6 +15,8 @@
# Description:
# TCK tests for Dagger
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
@@ -22,8 +24,6 @@
)
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "tck_tests",
srcs = glob(["*.java"]),
diff --git a/javatests/dagger/grpc/functional/server/BUILD b/javatests/dagger/grpc/functional/server/BUILD
index 0603801..1e8c2e6 100644
--- a/javatests/dagger/grpc/functional/server/BUILD
+++ b/javatests/dagger/grpc/functional/server/BUILD
@@ -1,9 +1,10 @@
# Functional tests for Dagger-gRPC
-load("@rules_java//java:defs.bzl", "java_proto_library")
-
package(default_visibility = ["//:src"])
+load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX", "DOCLINT_REFERENCES")
+load("//:test_defs.bzl", "GenJavaTests")
+
# TODO(dpb): enable tests once java_grpc_library is ready in bazel:
# https://github.com/grpc/grpc-java/issues/2756
diff --git a/javatests/dagger/hilt/android/processor/AndroidCompilers.java b/javatests/dagger/hilt/android/processor/AndroidCompilers.java
deleted file mode 100644
index 5ce0a2a..0000000
--- a/javatests/dagger/hilt/android/processor/AndroidCompilers.java
+++ /dev/null
@@ -1,79 +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.processor;
-
-import static java.util.stream.Collectors.toMap;
-
-import com.google.common.collect.ImmutableList;
-import com.google.testing.compile.Compiler;
-import dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor;
-import dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor;
-import dagger.hilt.android.processor.internal.uninstallmodules.UninstallModulesProcessor;
-import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor;
-import dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor;
-import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor;
-import dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor;
-import dagger.hilt.processor.internal.root.RootProcessor;
-import dagger.internal.codegen.ComponentProcessor;
-import dagger.testing.compile.CompilerTests;
-import java.util.Arrays;
-import java.util.Map;
-import javax.annotation.processing.Processor;
-import com.tschuchort.compiletesting.KotlinCompilation;
-
-/** {@link Compiler} instances for testing Android Hilt. */
-public final class AndroidCompilers {
-
- public static Compiler compiler(Processor... extraProcessors) {
- Map<Class<?>, Processor> processors =
- defaultProcessors().stream()
- .collect(toMap((Processor e) -> e.getClass(), (Processor e) -> e));
-
- // Adds extra processors, and allows overriding any processors of the same class.
- Arrays.stream(extraProcessors)
- .forEach(processor -> processors.put(processor.getClass(), processor));
-
- return CompilerTests.compiler().withProcessors(processors.values());
- }
-
- public static KotlinCompilation kotlinCompiler() {
- KotlinCompilation compilation = new KotlinCompilation();
- compilation.setAnnotationProcessors(defaultProcessors());
- compilation.setClasspaths(
- ImmutableList.<java.io.File>builder()
- .addAll(compilation.getClasspaths())
- .add(CompilerTests.compilerDepsJar())
- .build()
- );
- return compilation;
- }
-
- private static ImmutableList<Processor> defaultProcessors() {
- return ImmutableList.of(
- new AggregatedDepsProcessor(),
- new AndroidEntryPointProcessor(),
- new ComponentProcessor(),
- new DefineComponentProcessor(),
- new GeneratesRootInputProcessor(),
- new OriginatingElementProcessor(),
- new CustomTestApplicationProcessor(),
- new UninstallModulesProcessor(),
- new RootProcessor());
- }
-
- private AndroidCompilers() {}
-}
diff --git a/javatests/dagger/hilt/android/processor/BUILD b/javatests/dagger/hilt/android/processor/BUILD
deleted file mode 100644
index 7fb2320..0000000
--- a/javatests/dagger/hilt/android/processor/BUILD
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# Description:
-# Tests for internal code for implementing Hilt processors.
-
-package(default_visibility = ["//:src"])
-
-java_library(
- name = "android_compilers",
- srcs = ["AndroidCompilers.java"],
- deps = [
- "//java/dagger/hilt/android/processor/internal/androidentrypoint:processor_lib",
- "//java/dagger/hilt/android/processor/internal/customtestapplication:processor_lib",
- "//java/dagger/hilt/android/processor/internal/uninstallmodules:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
- "//java/dagger/hilt/processor/internal/definecomponent:processor_lib",
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "//java/dagger/hilt/processor/internal/originatingelement:processor_lib",
- "//java/dagger/hilt/processor/internal/root:processor_lib",
- "//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/testing/compile",
- "@google_bazel_common//third_party/java/compile_testing",
- "@maven//:com_github_tschuchortdev_kotlin_compile_testing",
- ],
-)
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
deleted file mode 100644
index bf2ed4c..0000000
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/BUILD
+++ /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.
-# Description:
-# Tests for internal code for implementing Hilt processors.
-
-load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
-
-package(default_visibility = ["//:src"])
-
-compiler_test(
- name = "TestInstallInTest",
- srcs = ["TestInstallInTest.java"],
- compiler_deps = [
- ":InstallInModule",
- "//:dagger_with_compiler",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt:entry_point",
- "//java/dagger/hilt/components",
- "//java/dagger/hilt/android/internal/modules",
- "//java/dagger/hilt/testing:test_install_in",
- "//java/dagger/hilt/android/testing:hilt_android_test",
- "@androidsdk//:platforms/android-30/android.jar",
- ],
- deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- ],
-)
-
-java_library(
- name = "InstallInModule",
- srcs = ["InstallInModule.java"],
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/components",
- ],
-)
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/InstallInModule.java b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/InstallInModule.java
deleted file mode 100644
index af535f5..0000000
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/InstallInModule.java
+++ /dev/null
@@ -1,30 +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.processor.internal.aggregateddeps;
-
-import dagger.Module;
-import dagger.hilt.InstallIn;
-import dagger.hilt.components.SingletonComponent;
-
-/**
- * This is used in TestInstallInTest to test that the wrapper module, HiltWrapper_InstallInModule,
- * cannot be replaced. This needs to be compiled in a separate library because
- * AggregatedDepsProcesor does not defer modules that have not been generated yet.
- */
-@Module
-@InstallIn(SingletonComponent.class)
-interface InstallInModule {}
diff --git a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java b/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
deleted file mode 100644
index 3af5be6..0000000
--- a/javatests/dagger/hilt/android/processor/internal/aggregateddeps/TestInstallInTest.java
+++ /dev/null
@@ -1,365 +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.processor.internal.aggregateddeps;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class TestInstallInTest {
-
- @Test
- public void testMissingValues() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@Module",
- "@TestInstallIn",
- "interface TestInstallInModule {}");
- Compilation compilation = compiler().compile(testInstallInModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@dagger.hilt.testing.TestInstallIn is missing default values for elements "
- + "components,replaces")
- .inFile(testInstallInModule)
- .onLine(7);
- }
-
- @Test
- public void testEmptyComponentValues() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
- "test.InstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@Module",
- "@InstallIn(SingletonComponent.class)",
- "interface InstallInModule {}");
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@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})");
- }
-
- @Test
- public void testEmptyReplacesValues() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.testing.TestInstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@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={})");
- }
-
- @Test
- public void testMissingModuleAnnotation() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
- "test.InstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@Module",
- "@InstallIn(SingletonComponent.class)",
- "interface InstallInModule {}");
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@TestInstallIn(",
- " 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);
- }
-
- @Test
- public void testInvalidUsageOnEntryPoint() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
- "test.InstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@Module",
- "@InstallIn(SingletonComponent.class)",
- "interface InstallInModule {}");
- JavaFileObject testInstallInEntryPoint =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInEntryPoint",
- "package test;",
- "",
- "import dagger.hilt.EntryPoint;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@EntryPoint",
- "@TestInstallIn(",
- " 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);
- }
-
- @Test
- public void testInvalidReplaceModules() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "class Foo {}");
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@Module",
- "@TestInstallIn(",
- " 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);
- }
-
- @Test
- public void testInternalDaggerReplaceModules() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@Module",
- "@TestInstallIn(",
- " 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);
- }
-
- @Test
- public void testHiltWrapperDaggerReplaceModules() {
- JavaFileObject testInstallInModule =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "import"
- + " dagger.hilt.android.processor.internal.aggregateddeps.HiltWrapper_InstallInModule;",
- "",
- "@Module",
- "@TestInstallIn(",
- " components = SingletonComponent.class,",
- // Note: this module is built in a separate library since AggregatedDepsProcessor can't
- // 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);
- }
-
- @Test
- public void testCannotReplaceLocalInstallInModule() {
- JavaFileObject test =
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "",
- "@HiltAndroidTest",
- "public class MyTest {",
- " @Module",
- " @InstallIn(SingletonComponent.class)",
- " interface LocalInstallInModule {}",
- "}");
- JavaFileObject testInstallIn =
- JavaFileObjects.forSourceLines(
- "test.TestInstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "",
- "@Module",
- "@TestInstallIn(",
- " 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);
- }
-
- @Test
- public void testThatTestInstallInCannotOriginateFromTest() {
- JavaFileObject installInModule =
- JavaFileObjects.forSourceLines(
- "test.InstallInModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.InstallIn;",
- "import dagger.hilt.components.SingletonComponent;",
- "",
- "@Module",
- "@InstallIn(SingletonComponent.class)",
- "interface InstallInModule {}");
- JavaFileObject test =
- JavaFileObjects.forSourceLines(
- "test.MyTest",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.testing.TestInstallIn;",
- "import dagger.hilt.android.testing.HiltAndroidTest;",
- "",
- "@HiltAndroidTest",
- "public class MyTest {",
- " @Module",
- " @TestInstallIn(",
- " components = SingletonComponent.class,",
- " 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);
- }
-}
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
deleted file mode 100644
index 25a1abd..0000000
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/ActivityGeneratorTest.java
+++ /dev/null
@@ -1,76 +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.processor.internal.androidentrypoint;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ActivityGeneratorTest {
-
- @Test
- public void generate_componentActivity() {
- JavaFileObject myActivity =
- JavaFileObjects.forSourceLines(
- "test.MyActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint(ComponentActivity.class)",
- "public class MyActivity extends Hilt_MyActivity {",
- "}");
- Compilation compilation = compiler().compile(myActivity);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void generate_baseHiltComponentActivity() {
- JavaFileObject baseActivity =
- JavaFileObjects.forSourceLines(
- "test.BaseActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint(ComponentActivity.class)",
- "public class BaseActivity extends Hilt_BaseActivity {",
- "}");
- JavaFileObject myActivity =
- JavaFileObjects.forSourceLines(
- "test.MyActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint(BaseActivity.class)",
- "public class MyActivity extends Hilt_MyActivity {",
- "}");
- Compilation compilation = compiler().compile(baseActivity, myActivity);
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
deleted file mode 100644
index c024a9c..0000000
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointProcessorTest.java
+++ /dev/null
@@ -1,169 +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.processor.internal.androidentrypoint;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AndroidEntryPointProcessorTest {
-
- @Test
- public void missingBaseClass() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
- "test.MyActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint",
- "public class MyActivity extends ComponentActivity { }");
- Compilation compilation = compiler().compile(testActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Expected @AndroidEntryPoint to have a value.")
- ;
- }
-
- @Test
- public void incorrectSuperclass() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
- "test.MyActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@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")
- ;
- }
-
- @Test
- public void disableSuperclassValidation_activity() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
- "test.MyActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint",
- "public class MyActivity extends ComponentActivity { }");
- Compilation compilation =
- compiler()
- .withOptions("-Adagger.hilt.android.internal.disableAndroidSuperclassValidation=true")
- .compile(testActivity);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void disableSuperclassValidation_application() {
- JavaFileObject testApplication =
- JavaFileObjects.forSourceLines(
- "test.MyApp",
- "package test;",
- "",
- "import android.app.Application;",
- "import dagger.hilt.android.HiltAndroidApp;",
- "",
- "@HiltAndroidApp",
- "public class MyApp extends Application { }");
- Compilation compilation =
- compiler()
- .withOptions("-Adagger.hilt.android.internal.disableAndroidSuperclassValidation=true")
- .compile(testApplication);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void checkBaseActivityExtendsComponentActivity() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
- "test.MyActivity",
- "package test;",
- "",
- "import android.app.Activity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint(Activity.class)",
- "public class MyActivity extends Hilt_MyActivity { }");
- Compilation compilation = compiler().compile(testActivity);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Activities annotated with @AndroidEntryPoint must be a subclass of "
- + "androidx.activity.ComponentActivity. (e.g. FragmentActivity, AppCompatActivity, "
- + "etc.)");
- }
-
- @Test
- public void checkBaseActivityWithTypeParameters() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
- "test.BaseActivity",
- "package test;",
- "",
- "import androidx.activity.ComponentActivity;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@AndroidEntryPoint(ComponentActivity.class)",
- "public class BaseActivity<T> extends Hilt_BaseActivity {}");
- Compilation compilation = compiler().compile(testActivity);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation).hadErrorContaining(
- "cannot find symbol\n symbol: class Hilt_BaseActivity");
- assertThat(compilation).hadErrorContaining(
- "@AndroidEntryPoint-annotated classes cannot have type parameters.");
- }
-
- @Test
- public void checkAndroidEntryPointOnApplicationRecommendsHiltAndroidApp() {
- JavaFileObject testActivity =
- JavaFileObjects.forSourceLines(
- "test.MyApplication",
- "package test;",
- "",
- "import android.app.Application;",
- "import dagger.hilt.android.AndroidEntryPoint;",
- "",
- "@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.");
- }
-}
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
deleted file mode 100644
index e53d9e2..0000000
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/BUILD
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-# Description:
-# Tests for internal code for implementing Hilt processors.
-
-load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
-
-package(default_visibility = ["//:src"])
-
-compiler_test(
- name = "ActivityGeneratorTest",
- srcs = ["ActivityGeneratorTest.java"],
- compiler_deps = [
- "//java/dagger/hilt/android:android_entry_point",
- "@androidsdk//:platforms/android-30/android.jar",
- ],
- deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- ],
-)
-
-compiler_test(
- name = "AndroidEntryPointProcessorTest",
- srcs = ["AndroidEntryPointProcessorTest.java"],
- compiler_deps = [
- "//java/dagger/hilt/android:hilt_android_app",
- "//java/dagger/hilt/android:android_entry_point",
- "@androidsdk//:platforms/android-30/android.jar",
- ],
- deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- ],
-)
-
-compiler_test(
- name = "KotlinAndroidEntryPointProcessorTest",
- srcs = ["KotlinAndroidEntryPointProcessorTest.java"],
- compiler_deps = [
- "//java/dagger/hilt/android:hilt_android_app",
- "//java/dagger/hilt/android:android_entry_point",
- "@androidsdk//:platforms/android-30/android.jar",
- ],
- deps = [
- "//java/dagger/internal/guava:collect",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@maven//:com_github_tschuchortdev_kotlin_compile_testing",
- ],
-)
diff --git a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java b/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java
deleted file mode 100644
index 739c87c..0000000
--- a/javatests/dagger/hilt/android/processor/internal/androidentrypoint/KotlinAndroidEntryPointProcessorTest.java
+++ /dev/null
@@ -1,66 +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.processor.internal.androidentrypoint;
-
-import static dagger.hilt.android.processor.AndroidCompilers.kotlinCompiler;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.truth.Truth;
-import com.tschuchort.compiletesting.KotlinCompilation;
-import com.tschuchort.compiletesting.KotlinCompilation.ExitCode;
-import com.tschuchort.compiletesting.SourceFile;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class KotlinAndroidEntryPointProcessorTest {
- @Test
- public void checkBaseClassConstructorHasNotDefaultParameters() {
- SourceFile fragmentSrc = SourceFile.Companion.kotlin("MyFragment.kt",
- String.join("\n",
- "package test",
- "",
- "import dagger.hilt.android.AndroidEntryPoint",
- "",
- "@AndroidEntryPoint",
- "class MyFragment : BaseFragment()"
- ),
- false);
- SourceFile baseFragmentSrc = SourceFile.Companion.kotlin("BaseFragment.kt",
- String.join("\n",
- "package test",
- "",
- "import androidx.fragment.app.Fragment",
- "",
- "abstract class BaseFragment(layoutId: Int = 0) : Fragment()"
- ),
- false);
- KotlinCompilation compilation = kotlinCompiler();
- compilation.setSources(ImmutableList.of(fragmentSrc, baseFragmentSrc));
- compilation.setKaptArgs(ImmutableMap.of(
- "dagger.hilt.android.internal.disableAndroidSuperclassValidation", "true"));
- KotlinCompilation.Result result = compilation.compile();
- Truth.assertThat(result.getExitCode()).isEqualTo(ExitCode.COMPILATION_ERROR);
- Truth.assertThat(result.getMessages()).contains("The base class, 'test.BaseFragment', of the "
- + "@AndroidEntryPoint, 'test.MyFragment', contains a constructor with default parameters. "
- + "This is currently not supported by the Gradle plugin. Either specify the base class as "
- + "described at https://dagger.dev/hilt/gradle-setup#why-use-the-plugin or remove the "
- + "default value declaration.");
- }
-}
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD b/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
deleted file mode 100644
index 030efd9..0000000
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/BUILD
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Tests for internal code for implementing Hilt processors.
-
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
-load("//java/dagger/testing/compile:macros.bzl", "kt_compiler_test")
-
-package(default_visibility = ["//:src"])
-
-java_test(
- name = "ViewModelProcessorTest",
- runtime_deps = [
- ":ViewModelProcessorTestLib",
- "//java/dagger/hilt/android/lifecycle",
- "@androidsdk//:platforms/android-30/android.jar",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- ],
-)
-
-kt_jvm_library(
- name = "ViewModelProcessorTestLib",
- srcs = [
- "ViewModelProcessorTest.kt",
- ],
- deps = [
- ":test_utils",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-java_test(
- name = "ViewModelGeneratorTest",
- runtime_deps = [
- ":ViewModelGeneratorTestLib",
- "//java/dagger/hilt/android/lifecycle",
- "@androidsdk//:platforms/android-30/android.jar",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- ],
-)
-
-kt_jvm_library(
- name = "ViewModelGeneratorTestLib",
- srcs = [
- "ViewModelGeneratorTest.kt",
- ],
- deps = [
- ":test_utils",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-kt_compiler_test(
- name = "ViewModelValidationPluginTest",
- srcs = [
- "ViewModelValidationPluginTest.kt",
- ],
- compiler_deps = [
- "@androidsdk//:platforms/android-30/android.jar",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel",
- "@maven//:androidx_lifecycle_lifecycle_viewmodel_savedstate",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/truth",
- "//java/dagger/hilt/android/lifecycle",
- "//java/dagger/hilt/android:android_entry_point",
- "//java/dagger/hilt/android:hilt_android_app",
- ],
- deps = [
- ":test_utils",
- "//:compiler_internals",
- "//java/dagger/hilt/android/processor/internal/viewmodel:processor_lib",
- "//java/dagger/hilt/android/processor/internal/viewmodel:validation_plugin_lib",
- "//javatests/dagger/hilt/android/processor:android_compilers",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-kt_jvm_library(
- name = "test_utils",
- srcs = [
- "TestUtils.kt",
- ],
- deps = [
- "@google_bazel_common//third_party/java/compile_testing",
- ],
-)
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/TestUtils.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/TestUtils.kt
deleted file mode 100644
index 713cd22..0000000
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/TestUtils.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package dagger.hilt.android.processor.internal.viewmodel
-
-import com.google.testing.compile.JavaFileObjects
-
-val GENERATED_TYPE = try {
- Class.forName("javax.annotation.processing.Generated")
- "javax.annotation.processing.Generated"
-} catch (_: ClassNotFoundException) {
- "javax.annotation.Generated"
-}
-
-const val GENERATED_ANNOTATION =
- "@Generated(\"dagger.hilt.android.processor.internal.viewmodel.ViewModelProcessor\")"
-
-fun String.toJFO(qName: String) = JavaFileObjects.forSourceString(qName, this.trimIndent())
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt
deleted file mode 100644
index 7c3e45f..0000000
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelGeneratorTest.kt
+++ /dev/null
@@ -1,527 +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.processor.internal.viewmodel
-
-import com.google.testing.compile.CompilationSubject.assertThat
-import com.google.testing.compile.Compiler
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ViewModelGeneratorTest {
-
- private fun compiler(): Compiler = Compiler.javac().withProcessors(ViewModelProcessor())
-
- @Test
- fun verifyModule_noArg() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import androidx.lifecycle.ViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- MyViewModel() { }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val expected = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
- $GENERATED_ANNOTATION
- @OriginatingElement(
- topLevelClass = MyViewModel.class
- )
- public final class MyViewModel_HiltModules {
- private MyViewModel_HiltModules() {
- }
-
- @Module
- @InstallIn(ViewModelComponent.class)
- public static abstract class BindsModule {
- @Binds
- @IntoMap
- @StringKey("dagger.hilt.android.test.MyViewModel")
- @HiltViewModelMap
- public abstract ViewModel binds(MyViewModel vm);
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- public static final class KeyModule {
- private KeyModule() {
- }
-
- @Provides
- @IntoSet
- @HiltViewModelMap.KeySet
- public static String provide() {
- return "dagger.hilt.android.test.MyViewModel";
- }
- }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModule")
-
- val compilation = compiler()
- .compile(myViewModel)
- assertThat(compilation).apply {
- succeeded()
- generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
- }
- }
-
- @Test
- fun verifyModule_savedStateOnlyArg() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import androidx.lifecycle.ViewModel;
- import androidx.lifecycle.SavedStateHandle;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- MyViewModel(SavedStateHandle savedState) { }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val expected = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
- $GENERATED_ANNOTATION
- @OriginatingElement(
- topLevelClass = MyViewModel.class
- )
- public final class MyViewModel_HiltModules {
- private MyViewModel_HiltModules() {
- }
-
- @Module
- @InstallIn(ViewModelComponent.class)
- public static abstract class BindsModule {
- @Binds
- @IntoMap
- @StringKey("dagger.hilt.android.test.MyViewModel")
- @HiltViewModelMap
- public abstract ViewModel binds(MyViewModel vm);
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- public static final class KeyModule {
- private KeyModule() {
- }
-
- @Provides
- @IntoSet
- @HiltViewModelMap.KeySet
- public static String provide() {
- return "dagger.hilt.android.test.MyViewModel";
- }
- }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModule")
-
- val compilation = compiler()
- .compile(myViewModel)
- assertThat(compilation).apply {
- succeeded()
- generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
- }
- }
-
- @Test
- fun verifyModule_mixedArgs() {
- val foo = """
- package dagger.hilt.android.test;
-
- public class Foo { }
- """.toJFO("dagger.hilt.android.test.Foo")
-
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import androidx.lifecycle.ViewModel;
- import androidx.lifecycle.SavedStateHandle;
- import java.lang.String;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- MyViewModel(String s, Foo f, SavedStateHandle savedState, long l) { }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val expected = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
- $GENERATED_ANNOTATION
- @OriginatingElement(
- topLevelClass = MyViewModel.class
- )
- public final class MyViewModel_HiltModules {
- private MyViewModel_HiltModules() {
- }
-
- @Module
- @InstallIn(ViewModelComponent.class)
- public static abstract class BindsModule {
- @Binds
- @IntoMap
- @StringKey("dagger.hilt.android.test.MyViewModel")
- @HiltViewModelMap
- public abstract ViewModel binds(MyViewModel vm);
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- public static final class KeyModule {
- private KeyModule() {
- }
-
- @Provides
- @IntoSet
- @HiltViewModelMap.KeySet
- public static String provide() {
- return "dagger.hilt.android.test.MyViewModel";
- }
- }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModule")
-
- val compilation = compiler()
- .compile(foo, myViewModel)
- assertThat(compilation).apply {
- succeeded()
- generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
- }
- }
-
- @Test
- fun verifyModule_mixedAndProviderArgs() {
- val foo = """
- package dagger.hilt.android.test;
-
- public class Foo { }
- """.toJFO("dagger.hilt.android.test.Foo")
-
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import androidx.lifecycle.ViewModel;
- import androidx.lifecycle.SavedStateHandle;
- import java.lang.String;
- import javax.inject.Inject;
- import javax.inject.Provider;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- MyViewModel(String s, Provider<Foo> f, SavedStateHandle savedState) { }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val expected = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE;
-
- $GENERATED_ANNOTATION
- @OriginatingElement(
- topLevelClass = MyViewModel.class
- )
- public final class MyViewModel_HiltModules {
- private MyViewModel_HiltModules() {
- }
-
- @Module
- @InstallIn(ViewModelComponent.class)
- public static abstract class BindsModule {
- @Binds
- @IntoMap
- @StringKey("dagger.hilt.android.test.MyViewModel")
- @HiltViewModelMap
- public abstract ViewModel binds(MyViewModel vm);
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- public static final class KeyModule {
- private KeyModule() {
- }
-
- @Provides
- @IntoSet
- @HiltViewModelMap.KeySet
- public static String provide() {
- return "dagger.hilt.android.test.MyViewModel";
- }
- }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModules")
-
- val compilation = compiler()
- .compile(foo, myViewModel)
- assertThat(compilation).apply {
- succeeded()
- generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
- }
- }
-
- @Test
- fun verifyModule_qualifiedArgs() {
- val myQualifier = """
- package dagger.hilt.android.test;
-
- import javax.inject.Qualifier;
-
- @Qualifier
- public @interface MyQualifier { }
- """.toJFO("dagger.hilt.android.test.MyQualifier")
-
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import androidx.lifecycle.ViewModel;
- import androidx.lifecycle.SavedStateHandle;
- import java.lang.Long;
- import java.lang.String;
- import javax.inject.Inject;
- import javax.inject.Named;
- import javax.inject.Provider;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- MyViewModel(@Named("TheString") String s, @MyQualifier Provider<Long> l,
- SavedStateHandle savedState) {
- }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val expected = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE;
-
- $GENERATED_ANNOTATION
- @OriginatingElement(
- topLevelClass = MyViewModel.class
- )
- public final class MyViewModel_HiltModules {
- private MyViewModel_HiltModules() {
- }
-
- @Module
- @InstallIn(ViewModelComponent.class)
- public static abstract class BindsModule {
- @Binds
- @IntoMap
- @StringKey("dagger.hilt.android.test.MyViewModel")
- @HiltViewModelMap
- public abstract ViewModel binds(MyViewModel vm);
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- public static final class KeyModule {
- private KeyModule() {
- }
-
- @Provides
- @IntoSet
- @HiltViewModelMap.KeySet
- public static String provide() {
- return "dagger.hilt.android.test.MyViewModel";
- }
- }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModules")
-
- val compilation = compiler()
- .compile(myQualifier, myViewModel)
- assertThat(compilation).apply {
- succeeded()
- generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules")
- .hasSourceEquivalentTo(expected)
- }
- }
-
- @Test
- fun verifyInnerClass() {
- val viewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import androidx.lifecycle.ViewModel;
- import javax.inject.Inject;
-
- class Outer {
- @HiltViewModel
- static class InnerViewModel extends ViewModel {
- @Inject
- InnerViewModel() { }
- }
- }
- """.toJFO("dagger.hilt.android.test.Outer")
-
- val expectedModule = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.Binds;
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityRetainedComponent;
- import dagger.hilt.android.components.ViewModelComponent;
- import dagger.hilt.android.internal.lifecycle.HiltViewModelMap;
- import dagger.hilt.codegen.OriginatingElement;
- import dagger.multibindings.IntoMap;
- import dagger.multibindings.IntoSet;
- import dagger.multibindings.StringKey;
- import java.lang.String;
- import $GENERATED_TYPE
-
- $GENERATED_ANNOTATION
- @OriginatingElement(
- topLevelClass = Outer.class
- )
- public final class Outer_InnerViewModel_HiltModules {
- private Outer_InnerViewModel_HiltModules() {
- }
-
- @Module
- @InstallIn(ViewModelComponent.class)
- public static abstract class BindsModule {
- @Binds
- @IntoMap
- @StringKey("dagger.hilt.android.test.Outer${'$'}InnerViewModel")
- @HiltViewModelMap
- public abstract ViewModel binds(Outer.InnerViewModel vm);
- }
-
- @Module
- @InstallIn(ActivityRetainedComponent.class)
- public static final class KeyModule {
- private KeyModule() {
- }
-
- @Provides
- @IntoSet
- @HiltViewModelMap.KeySet
- public static String provide() {
- return "dagger.hilt.android.test.Outer${'$'}InnerViewModel";
- }
- }
- }
- """.toJFO("dagger.hilt.android.test.Outer_InnerViewModel_HiltModules")
-
- val compilation = compiler()
- .compile(viewModel)
- assertThat(compilation).apply {
- succeeded()
- generatedSourceFile("dagger.hilt.android.test.Outer_InnerViewModel_HiltModules")
- .hasSourceEquivalentTo(expectedModule)
- }
- }
-}
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt
deleted file mode 100644
index b3eaeab..0000000
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelProcessorTest.kt
+++ /dev/null
@@ -1,184 +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.processor.internal.viewmodel
-
-import com.google.testing.compile.CompilationSubject.assertThat
-import com.google.testing.compile.Compiler
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ViewModelProcessorTest {
-
- private fun compiler(): Compiler = Compiler.javac().withProcessors(ViewModelProcessor())
-
- @Test
- fun validViewModel() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel() { }
- }
- """.toJFO("dagger.hilt.android.test.MyViewModel")
-
- val compilation = compiler().compile(myViewModel)
- assertThat(compilation).succeeded()
- }
-
- @Test
- fun verifyEnclosingElementExtendsViewModel() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel {
- @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."
- )
- }
- }
-
- @Test
- fun verifySingleAnnotatedConstructor() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- MyViewModel() { }
-
- @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."
- )
- }
- }
-
- @Test
- fun verifyNonPrivateConstructor() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @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."
- )
- }
- }
-
- @Test
- fun verifyInnerClassIsStatic() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- class Outer {
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject
- 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."
- )
- }
- }
-
- @Test
- fun verifyNoScopeAnnotation() {
- val myViewModel = """
- package dagger.hilt.android.test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
- import javax.inject.Singleton;
-
- @Singleton
- @HiltViewModel
- 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"
- )
- }
- }
-}
diff --git a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt b/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
deleted file mode 100644
index b5c22c1..0000000
--- a/javatests/dagger/hilt/android/processor/internal/viewmodel/ViewModelValidationPluginTest.kt
+++ /dev/null
@@ -1,352 +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.processor.internal.viewmodel
-
-import com.google.testing.compile.CompilationSubject.assertThat
-import com.google.testing.compile.Compiler
-import dagger.hilt.android.processor.AndroidCompilers.compiler
-import dagger.internal.codegen.ComponentProcessor
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ViewModelValidationPluginTest {
-
- private fun testCompiler(): Compiler = compiler(
- ComponentProcessor.forTesting(ViewModelValidationPlugin()),
- ViewModelProcessor()
- )
-
- private val hiltAndroidApp = """
- package test;
-
- import android.app.Application;
- import dagger.hilt.android.HiltAndroidApp;
-
- @HiltAndroidApp(Application.class)
- public class TestApplication extends Hilt_TestApplication {}
- """.toJFO("test.TestApplication")
-
- @Test
- fun injectViewModelIsProhibited() {
- val hiltActivity = """
- package test;
-
- import androidx.fragment.app.FragmentActivity;
- import dagger.hilt.android.AndroidEntryPoint;
- import javax.inject.Inject;
-
- @AndroidEntryPoint(FragmentActivity.class)
- public class TestActivity extends Hilt_TestActivity {
- @Inject Foo foo;
- }
- """.toJFO("test.TestActivity")
- val hiltViewModel = """
- package test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel() { }
- }
- """.toJFO("test.MyViewModel")
- val foo = """
- package test;
-
- import javax.inject.Inject;
-
- final class Foo {
- @Inject Foo(MyViewModel viewModel) {}
- }
- """.toJFO("test.Foo")
-
- val compilation = testCompiler().compile(foo, hiltViewModel, hiltAndroidApp, hiltActivity)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "Injection of an @HiltViewModel class is prohibited"
- )
- }
- }
-
- @Test
- fun fieldInjectedViewModelIsProhibited() {
- val hiltActivity = """
- package test;
-
- import androidx.fragment.app.FragmentActivity;
- import dagger.hilt.android.AndroidEntryPoint;
- import javax.inject.Inject;
-
- @AndroidEntryPoint(FragmentActivity.class)
- public class TestActivity extends Hilt_TestActivity {
- @Inject MyViewModel viewModel;
- }
- """.toJFO("test.TestActivity")
- val hiltViewModel = """
- package test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel() { }
- }
- """.toJFO("test.MyViewModel")
-
- val compilation = testCompiler().compile(hiltViewModel, hiltAndroidApp, hiltActivity)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "Injection of an @HiltViewModel class is prohibited"
- )
- }
- }
-
- @Test
- fun injectViewModelFromViewModelComponentIsProhibited() {
- // Use an @HiltViewModel that injects a Foo to get the binding inside the ViewModelComponent
- val hiltViewModel = """
- package test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel(Foo foo) { }
- }
- """.toJFO("test.MyViewModel")
-
- val foo = """
- package test;
-
- import javax.inject.Inject;
- import javax.inject.Provider;
-
- final class Foo {
- @Inject Foo(Provider<MyViewModel> viewModelProvider) {}
- }
- """.toJFO("test.Foo")
-
- val compilation = testCompiler().compile(foo, hiltViewModel, hiltAndroidApp)
- assertThat(compilation).apply {
- failed()
- hadErrorCount(1)
- hadErrorContainingMatch(
- "Injection of an @HiltViewModel class is prohibited"
- )
- }
- }
-
- @Test
- fun injectOverriddenViewModelBindingIsAllowed() {
- val hiltActivity = """
- package test;
-
- import androidx.fragment.app.FragmentActivity;
- import dagger.hilt.android.AndroidEntryPoint;
- import javax.inject.Inject;
-
- @AndroidEntryPoint(FragmentActivity.class)
- public class TestActivity extends Hilt_TestActivity {
- @Inject Foo foo;
- }
- """.toJFO("test.TestActivity")
- val hiltViewModel = """
- package test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel() { }
- }
- """.toJFO("test.MyViewModel")
- val foo = """
- package test;
-
- import javax.inject.Inject;
-
- final class Foo {
- @Inject Foo(MyViewModel viewModel) {}
- }
- """.toJFO("test.Foo")
- val activityModule = """
- package test;
-
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityComponent;
-
- @InstallIn(ActivityComponent.class)
- @Module
- public final class ActivityModule {
- @Provides static MyViewModel provideMyViewModel() {
- // Normally you'd expect this to use a ViewModelProvider or something but
- // since this test is just testing the binding graph, for simplicity just return
- // null.
- return null;
- }
- }
- """.toJFO("test.ActivityModule")
-
- val compilation = testCompiler().compile(
- foo, activityModule, hiltViewModel, hiltAndroidApp, hiltActivity
- )
- assertThat(compilation).succeeded()
- }
-
- @Test
- fun injectQualifiedViewModelBindingIsAllowed() {
- val hiltActivity = """
- package test;
-
- import androidx.fragment.app.FragmentActivity;
- import dagger.hilt.android.AndroidEntryPoint;
- import javax.inject.Inject;
-
- @AndroidEntryPoint(FragmentActivity.class)
- public class TestActivity extends Hilt_TestActivity {
- @Inject Foo foo;
- }
- """.toJFO("test.TestActivity")
- val hiltViewModel = """
- package test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel() { }
- }
- """.toJFO("test.MyViewModel")
- val foo = """
- package test;
-
- import javax.inject.Inject;
-
- final class Foo {
- @Inject Foo(@ActivityModule.MyQualifier MyViewModel viewModel) {}
- }
- """.toJFO("test.Foo")
- val activityModule = """
- package test;
-
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityComponent;
- import javax.inject.Qualifier;
-
- @InstallIn(ActivityComponent.class)
- @Module
- public final class ActivityModule {
- @Qualifier
- public @interface MyQualifier {}
-
- @Provides
- @MyQualifier
- static MyViewModel provideMyViewModel() {
- // Normally you'd expect this to use a ViewModelProvider or something but
- // since this test is just testing the binding graph, for simplicity just return
- // null.
- return null;
- }
- }
- """.toJFO("test.ActivityModule")
-
- val compilation = testCompiler().compile(
- foo, activityModule, hiltViewModel, hiltAndroidApp, hiltActivity
- )
- assertThat(compilation).succeeded()
- }
-
- // Regression test for not handling array types properly
- @Test
- fun correctlyAllowsOtherBindings() {
- val hiltActivity = """
- package test;
-
- import androidx.fragment.app.FragmentActivity;
- import dagger.hilt.android.AndroidEntryPoint;
- import javax.inject.Inject;
-
- @AndroidEntryPoint(FragmentActivity.class)
- public class TestActivity extends Hilt_TestActivity {
- @Inject Foo foo;
- }
- """.toJFO("test.TestActivity")
- val hiltViewModel = """
- package test;
-
- import androidx.lifecycle.ViewModel;
- import dagger.hilt.android.lifecycle.HiltViewModel;
- import javax.inject.Inject;
-
- @HiltViewModel
- class MyViewModel extends ViewModel {
- @Inject MyViewModel() { }
- }
- """.toJFO("test.MyViewModel")
- val foo = """
- package test;
-
- import javax.inject.Inject;
-
- final class Foo {
- @Inject Foo(Long[] longArray) {}
- }
- """.toJFO("test.Foo")
- val activityModule = """
- package test;
-
- import dagger.Module;
- import dagger.Provides;
- import dagger.hilt.InstallIn;
- import dagger.hilt.android.components.ActivityComponent;
-
- @InstallIn(ActivityComponent.class)
- @Module
- public final class ActivityModule {
- @Provides
- static Long[] provideLongArray() {
- return null;
- }
- }
- """.toJFO("test.ActivityModule")
-
- val compilation = testCompiler().compile(
- foo, activityModule, hiltViewModel, hiltAndroidApp, hiltActivity
- )
- assertThat(compilation).succeeded()
- }
-}
diff --git a/javatests/dagger/hilt/processor/internal/BUILD b/javatests/dagger/hilt/processor/internal/BUILD
deleted file mode 100644
index e6e1cfb..0000000
--- a/javatests/dagger/hilt/processor/internal/BUILD
+++ /dev/null
@@ -1,40 +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.
-
-# Description:
-# Tests for internal code for implementing Hilt processors.
-
-package(default_visibility = ["//:src"])
-
-java_test(
- name = "ProcessorsTest",
- size = "small",
- srcs = ["ProcessorsTest.java"],
- deps = [
- "//java/dagger/hilt/processor/internal:processors",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-java_library(
- name = "generated_import",
- srcs = ["GeneratedImport.java"],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["**/*"]),
-)
diff --git a/javatests/dagger/hilt/processor/internal/GeneratedImport.java b/javatests/dagger/hilt/processor/internal/GeneratedImport.java
deleted file mode 100644
index 0feaa4e..0000000
--- a/javatests/dagger/hilt/processor/internal/GeneratedImport.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal;
-
-/** Utility class for @Generated usage in tests. */
-public final class GeneratedImport {
- public static final String IMPORT_GENERATED_ANNOTATION =
- isBeforeJava9()
- ? "import javax.annotation.Generated;"
- : "import javax.annotation.processing.Generated;";
-
- private static boolean isBeforeJava9() {
- try {
- Class.forName("java.lang.Module");
- return false;
- } catch (ClassNotFoundException e) {
- return true;
- }
- }
-
- private GeneratedImport() {}
-}
diff --git a/javatests/dagger/hilt/processor/internal/ProcessorsTest.java b/javatests/dagger/hilt/processor/internal/ProcessorsTest.java
deleted file mode 100644
index cad41aa..0000000
--- a/javatests/dagger/hilt/processor/internal/ProcessorsTest.java
+++ /dev/null
@@ -1,85 +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.squareup.javapoet.ClassName;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeVariableName;
-import java.util.List;
-import javax.lang.model.element.Modifier;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ProcessorsTest {
-
- @Test
- public void testCopyMethodSpecWithoutBodyForMethod() throws Exception {
- TypeVariableName t = TypeVariableName.get("T", Number.class);
- ClassName list = ClassName.get(List.class);
- MethodSpec.Builder builder = MethodSpec.methodBuilder("myMethod")
- .addJavadoc("This is a test line 1 in the java doc \n"
- + "This is a test line 2 in the java doc \n"
- + "<p>Test Use of links {@link $T} \n", list)
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(ParameterizedTypeName.get(list, t), "list", Modifier.FINAL)
- .returns(ParameterizedTypeName.get(list, t))
- .addException(IllegalArgumentException.class)
- .addTypeVariable(t);
-
- // Test that method copy is the same as original
- MethodSpec method = builder.build();
- MethodSpec methodCopy = Processors.copyMethodSpecWithoutBody(method).build();
- assertThat(method.toString()).contains(methodCopy.toString());
-
- // Test that method copy removes the body, compare with the old copy
- MethodSpec methodWithBody = builder.addStatement("return list").build();
- MethodSpec methodCopyWithBody = Processors.copyMethodSpecWithoutBody(methodWithBody).build();
- assertThat(methodCopyWithBody.toString()).isEqualTo(methodCopy.toString());
-
- }
-
- @Test
- public void testCopyMethodSpecWithoutBodyForConstructor() throws Exception {
- TypeVariableName t = TypeVariableName.get("T", Number.class);
- ClassName list = ClassName.get(List.class);
- MethodSpec.Builder builder = MethodSpec.constructorBuilder()
- .addJavadoc("This is a test line 1 in the java doc \n"
- + "This is a test line 2 in the java doc \n"
- + "<p>Test Use of links {@link $T} \n", list)
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(ParameterizedTypeName.get(list, t), "list", Modifier.FINAL)
- .addException(IllegalArgumentException.class)
- .addTypeVariable(t);
-
- // Test that method copy is the same as original
- MethodSpec method = builder.build();
- MethodSpec methodCopy = Processors.copyMethodSpecWithoutBody(method).build();
- assertThat(method.toString()).contains(methodCopy.toString());
-
- // Test that method copy removes the body, compare with the old copy
- MethodSpec methodWithBody = builder.addStatement("this.list = list").build();
- MethodSpec methodCopyWithBody = Processors.copyMethodSpecWithoutBody(methodWithBody).build();
- assertThat(methodCopyWithBody.toString()).isEqualTo(methodCopy.toString());
- }
-}
diff --git a/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java b/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java
deleted file mode 100644
index b36a71d..0000000
--- a/javatests/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessorErrorsTest.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.aggregateddeps;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-
-import com.google.common.base.Joiner;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.hilt.processor.internal.GeneratedImport;
-import dagger.testing.compile.CompilerTests;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-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");
-
- @Test
- public void reportMultipleAnnotationTypeKindErrors() {
- JavaFileObject source =
- JavaFileObjects.forSourceString(
- "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{}",
- ""));
-
- 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);
- }
-
- @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 {}");
-
- 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);
- }
-
- @Test
- public void testMissingInstallInAnnotation() {
- JavaFileObject source = JavaFileObjects.forSourceString(
- "foo.bar.AnnotationsOnWrongTypeKind",
- LINES.join(
- "package foo.bar;",
- "",
- "import dagger.Module;",
- "",
- "@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);
- }
-
- @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 {}"));
-
- 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);
- }
-
- @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 \"\";",
- " }",
- "}"));
-
- 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.");
- }
-
- @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 {}",
- "}"));
-
- 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");
- }
-
- @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 {}",
- " }",
- "}"));
-
- 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");
- }
-
- @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 {}",
- "}"));
-
- Compilation compilation =
- CompilerTests.compiler().withProcessors(new AggregatedDepsProcessor()).compile(source);
-
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD b/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
deleted file mode 100644
index f52b051..0000000
--- a/javatests/dagger/hilt/processor/internal/aggregateddeps/BUILD
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Builds and run tests related to AggregatedDepsProcessor.
-
-load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
-
-package(default_visibility = ["//:src"])
-
-compiler_test(
- name = "AggregatedDepsProcessorErrorsTest",
- size = "small",
- srcs = ["AggregatedDepsProcessorErrorsTest.java"],
- compiler_deps = [
- "//java/dagger/hilt/internal:component_entry_point",
- "//java/dagger/hilt/internal:generated_entry_point",
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "//java/dagger/hilt:entry_point",
- "//java/dagger/hilt:install_in",
- "//java/dagger/hilt/android/testing:hilt_android_test",
- "//java/dagger/hilt/android/components",
- ],
- deps = [
- "//java/dagger/hilt/processor/internal/aggregateddeps:processor_lib",
- "//java/dagger/internal/guava:base",
- "//javatests/dagger/hilt/processor/internal:generated_import",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/javatests/dagger/hilt/processor/internal/definecomponent/BUILD b/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
deleted file mode 100644
index ce5cc0a..0000000
--- a/javatests/dagger/hilt/processor/internal/definecomponent/BUILD
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Tests for Hilt's DefineComponentProcessor
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
-
-package(default_visibility = ["//:src"])
-
-GenJavaTests(
- name = "hilt_processor_tests",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//:dagger_with_compiler",
- "//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",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java b/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
deleted file mode 100644
index 901c7a3..0000000
--- a/javatests/dagger/hilt/processor/internal/definecomponent/DefineComponentProcessorTest.java
+++ /dev/null
@@ -1,401 +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.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 dagger.hilt.processor.internal.GeneratedImport;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class DefineComponentProcessorTest {
-
- @Test
- public void testDefineComponentOutput() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.DefineComponent;",
- "",
- "@DefineComponent(parent = SingletonComponent.class)",
- "interface FooComponent {",
- " static int staticField = 1;",
- " static int staticMethod() { return staticField; }",
- "}");
-
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
- "test.FooComponentBuilder",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@DefineComponent.Builder",
- "interface FooComponentBuilder {",
- " static int staticField = 1;",
- " static int staticMethod() { return staticField; }",
- "",
- " FooComponent create();",
- "}");
-
- JavaFileObject componentOutput =
- JavaFileObjects.forSourceLines(
- "dagger.hilt.processor.internal.definecomponent.codegen.test_FooComponent",
- "package dagger.hilt.processor.internal.definecomponent.codegen;",
- "",
- "import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
- GeneratedImport.IMPORT_GENERATED_ANNOTATION,
- "",
- "@DefineComponentClasses(component = \"test.FooComponent\")",
- "@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
- "interface test_FooComponent {}");
-
- JavaFileObject builderOutput =
- JavaFileObjects.forSourceLines(
- "dagger.hilt.processor.internal.definecomponent.codegen.test_FooComponentBuilder",
- "package dagger.hilt.processor.internal.definecomponent.codegen;",
- "",
- "import dagger.hilt.internal.definecomponent.DefineComponentClasses;",
- GeneratedImport.IMPORT_GENERATED_ANNOTATION,
- "",
- "@DefineComponentClasses(builder = \"test.FooComponentBuilder\")",
- "@Generated(\"" + DefineComponentProcessor.class.getName() + "\")",
- "interface test_FooComponentBuilder {}");
-
- Compilation compilation = compiler().compile(component, builder);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile(sourceName(componentOutput))
- .hasSourceEquivalentTo(componentOutput);
- assertThat(compilation)
- .generatedSourceFile(sourceName(builderOutput))
- .hasSourceEquivalentTo(builderOutput);
- }
-
- private static String sourceName(JavaFileObject fileObject) {
- return fileObject.getName().replace(".java", "").replace('.', '/');
- }
-
- @Test
- public void testDefineComponentClass_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.DefineComponent;",
- "",
- "@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");
- }
-
- @Test
- public void testDefineComponentWithTypeParameters_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.DefineComponent;",
- "",
- "@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.");
- }
-
- @Test
- public void testDefineComponentWithInvalidComponent_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "import dagger.hilt.android.qualifiers.ApplicationContext;",
- "",
- "@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);
- }
-
- @Test
- public void testDefineComponentExtendsInterface_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.DefineComponent;",
- "",
- "interface Foo {}",
- "",
- "@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");
- }
-
- @Test
- public void testDefineComponentNonStaticMethod_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.components.SingletonComponent;",
- "import dagger.hilt.DefineComponent;",
- "",
- "@DefineComponent( parent = SingletonComponent.class )",
- "interface FooComponent {",
- " 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()]");
- }
-
- @Test
- public void testDefineComponentDependencyCycle_fails() {
- JavaFileObject component1 =
- JavaFileObjects.forSourceLines(
- "test.Component1",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@DefineComponent(parent = Component2.class)",
- "interface Component1 {}");
-
- JavaFileObject component2 =
- JavaFileObjects.forSourceLines(
- "test.Component2",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@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");
- }
-
- @Test
- public void testDefineComponentNoParent_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@DefineComponent",
- "interface FooComponent {}");
- Compilation compilation = compiler().compile(component);
- assertThat(compilation)
- .hadErrorContaining("@DefineComponent test.FooComponent is missing a parent declaration.");
- }
-
- @Test
- public void testDefineComponentBuilderClass_fails() {
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
- "test.FooComponentBuilder",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@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");
- }
-
- @Test
- public void testDefineComponentBuilderWithTypeParameters_fails() {
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
- "test.FooComponentBuilder",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@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.");
- }
-
- @Test
- public void testDefineComponentBuilderExtendsInterface_fails() {
- JavaFileObject builder =
- JavaFileObjects.forSourceLines(
- "test.FooComponentBuilder",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "interface Foo {}",
- "",
- "@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");
- }
-
- @Test
- public void testDefineComponentBuilderNoBuilderMethod_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@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: []");
- }
-
- @Test
- public void testDefineComponentBuilderPrimitiveReturnType_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "@DefineComponent.Builder",
- "interface FooComponentBuilder {",
- " 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");
- }
-
- @Test
- public void testDefineComponentBuilderWrongReturnType_fails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.hilt.DefineComponent;",
- "",
- "interface Foo {}",
- "",
- "@DefineComponent.Builder",
- "interface FooComponentBuilder {",
- " 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());
- }
-}
diff --git a/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD b/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
deleted file mode 100644
index 90b0596..0000000
--- a/javatests/dagger/hilt/processor/internal/disableinstallincheck/BUILD
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Description:
-# Builds and run tests related to DisableInstallInCheckProcessor.
-
-load("//java/dagger/testing/compile:macros.bzl", "compiler_test")
-
-package(default_visibility = ["//:src"])
-
-compiler_test(
- name = "DisableInstallInCheckProcessorErrorsTest",
- size = "small",
- srcs = ["DisableInstallInCheckProcessorErrorsTest.java"],
- compiler_deps = [
- "//java/dagger/hilt/migration:disable_install_in_check",
- "//:dagger_with_compiler",
- "@google_bazel_common//third_party/java/jsr250_annotations",
- "//java/dagger/hilt:entry_point",
- ],
- deps = [
- "//java/dagger/hilt/processor/internal/disableinstallincheck:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["*"]),
-)
diff --git a/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java b/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java
deleted file mode 100644
index 8ea715d..0000000
--- a/javatests/dagger/hilt/processor/internal/disableinstallincheck/DisableInstallInCheckProcessorErrorsTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2020 The Dagger Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package dagger.hilt.processor.internal.disableinstallincheck;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-
-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;
-
-/** Tests for errors generated by {@link DisableInstallInCheckProcessor} */
-@RunWith(JUnit4.class)
-public class DisableInstallInCheckProcessorErrorsTest {
-
- @Test
- public void testIllegalCombinationInstallIn() {
- JavaFileObject source =
- JavaFileObjects.forSourceLines(
- "foo.bar",
- "package foo.bar;",
- "",
- "import dagger.hilt.migration.DisableInstallInCheck;",
- "import dagger.hilt.EntryPoint;",
- "",
- "@DisableInstallInCheck",
- "final class NotModule {}",
- "",
- "@DisableInstallInCheck",
- "@EntryPoint",
- "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);
- }
-}
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD b/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
deleted file mode 100644
index c5dacd9..0000000
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/BUILD
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2017 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:
-# Tests the functionality of GeneratesRootInputProcessor.
-
-load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
-load("//:test_defs.bzl", "GenJavaTests")
-
-package(default_visibility = ["//:src"])
-
-GenJavaTests(
- name = "GeneratesRootInputProcessorTest",
- srcs = glob(["*.java"]),
- functional = False,
- javacopts = DOCLINT_HTML_AND_SYNTAX,
- deps = [
- "//:dagger_with_compiler",
- "//java/dagger/hilt:generates_root_input",
- "//java/dagger/hilt/processor/internal:base_processor",
- "//java/dagger/hilt/processor/internal/generatesrootinput:generates_root_inputs",
- "//java/dagger/hilt/processor/internal/generatesrootinput:processor_lib",
- "@google_bazel_common//third_party/java/compile_testing",
- "@google_bazel_common//third_party/java/javapoet",
- "@google_bazel_common//third_party/java/junit",
- "@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
- ],
-)
-
-filegroup(
- name = "srcs_filegroup",
- srcs = glob(["**/*"]),
-)
diff --git a/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java b/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
deleted file mode 100644
index fb62c3d..0000000
--- a/javatests/dagger/hilt/processor/internal/generatesrootinput/GeneratesRootInputProcessorTest.java
+++ /dev/null
@@ -1,99 +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.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 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 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;
-
-/** Tests that {@link GeneratesRootInputs} returns the elements to wait for. */
-@RunWith(JUnit4.class)
-public final class GeneratesRootInputProcessorTest {
- 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 int generatedClasses = 0;
-
- @SupportedAnnotationTypes("*")
- public final class TestAnnotationProcessor extends BaseProcessor {
- private GeneratesRootInputs generatesRootInputs;
-
- @Override
- public synchronized void init(ProcessingEnvironment processingEnv) {
- super.init(processingEnv);
- generatesRootInputs = new GeneratesRootInputs(processingEnv);
- }
-
- @Override
- protected void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
- if (generatedClasses > 0) {
- elementsToWaitFor.addAll(generatesRootInputs.getElementsToWaitFor(roundEnv));
- }
- if (generatedClasses < GENERATED_CLASSES) {
- TypeSpec typeSpec =
- TypeSpec.classBuilder("Foo" + generatedClasses++)
- .addAnnotation(TEST_ANNOTATION)
- .build();
- JavaFile.builder("foo", typeSpec).build().writeTo(processingEnv.getFiler());
- }
- }
- }
-
- @Test
- public void succeeds_ComponentProcessorWaitsForAnnotationsWithgeneratesstinginput() {
- JavaFileObject testAnnotation =
- JavaFileObjects.forSourceLines(
- "test.TestAnnotation",
- "package test;",
- "@dagger.hilt.GeneratesRootInput",
- "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();
- }
-}
diff --git a/javatests/dagger/internal/MapProviderFactoryTest.java b/javatests/dagger/internal/MapProviderFactoryTest.java
index c55bee3..5598ff2 100644
--- a/javatests/dagger/internal/MapProviderFactoryTest.java
+++ b/javatests/dagger/internal/MapProviderFactoryTest.java
@@ -46,7 +46,6 @@
MapProviderFactory.<String, Integer>builder(1).put("Hello", null);
}
-
@Test
public void iterationOrder() {
Provider<Integer> p1 = incrementingIntegerProvider(10);
@@ -75,7 +74,6 @@
.inOrder();
}
-
private static Provider<Integer> incrementingIntegerProvider(int seed) {
return new AtomicInteger(seed)::getAndIncrement;
}
diff --git a/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsMultibindingsTest.java b/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsMultibindingsTest.java
new file mode 100644
index 0000000..bb967b1
--- /dev/null
+++ b/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsMultibindingsTest.java
@@ -0,0 +1,2838 @@
+/*
+ * Copyright (C) 2018 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.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.CompilerMode.AHEAD_OF_TIME_SUBCOMPONENTS_MODE;
+import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
+import static dagger.internal.codegen.Compilers.CLASS_PATH_WITHOUT_GUAVA_OPTION;
+import static dagger.internal.codegen.Compilers.compilerWithOptions;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.GENERATION_OPTIONS_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
+
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AheadOfTimeSubcomponentsMultibindingsTest {
+ @Test
+ public void setMultibindings_contributionsInLeaf() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Set<InLeaf> contributionsInLeaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoSet",
+ " static InLeaf provideInLeaf() {",
+ " return new InLeaf();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Set<InLeaf> contributionsInLeaf() {",
+ " return ImmutableSet.<InLeaf>of(",
+ " LeafModule_ProvideInLeafFactory.provideInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+ }
+
+ @Test
+ public void setMultibindings_contributionsInAncestorOnly() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Set<InAncestor> contributionsInAncestor();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract Set<InAncestor> contributionsInAncestor();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @ElementsIntoSet",
+ " static Set<InAncestor> provideInAncestors() {",
+ " return ImmutableSet.of(new InAncestor(), new InAncestor());",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Set<InAncestor> contributionsInAncestor() {",
+ " return ImmutableSet.<InAncestor>copyOf(",
+ " AncestorModule_ProvideInAncestorsFactory.provideInAncestors());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void setMultibindings_contributionsInLeafAndAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InEachSubcomponent");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Set<InEachSubcomponent> contributionsInEachSubcomponent();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoSet",
+ " static InEachSubcomponent provideInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static InEachSubcomponent provideAnotherInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Set<InEachSubcomponent> contributionsInEachSubcomponent() {",
+ " return ImmutableSet.<InEachSubcomponent>of(",
+ " LeafModule_ProvideInLeafFactory.provideInLeaf(),",
+ " LeafModule_ProvideAnotherInLeafFactory.provideAnotherInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @ElementsIntoSet",
+ " static Set<InEachSubcomponent> provideInAncestor() {",
+ " return ImmutableSet.of(new InEachSubcomponent(), new InEachSubcomponent());",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Set<InEachSubcomponent> contributionsInEachSubcomponent() {",
+ " return ImmutableSet.<InEachSubcomponent>builderWithExpectedSize(3)",
+ " .addAll(AncestorModule_ProvideInAncestorFactory.provideInAncestor())",
+ " .addAll(super.contributionsInEachSubcomponent())",
+ " .build();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void setMultibindings_contributionsInLeafAndGrandAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InLeafAndGrandAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Set<InLeafAndGrandAncestor> contributionsInLeafAndGrandAncestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoSet",
+ " static InLeafAndGrandAncestor provideInLeaf() {",
+ " return new InLeafAndGrandAncestor();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static InLeafAndGrandAncestor provideAnotherInLeaf() {",
+ " return new InLeafAndGrandAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Set<InLeafAndGrandAncestor> contributionsInLeafAndGrandAncestor() {",
+ " return ImmutableSet.<InLeafAndGrandAncestor>of(",
+ " LeafModule_ProvideInLeafFactory.provideInLeaf(),",
+ " LeafModule_ProvideAnotherInLeafFactory.provideAnotherInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = GrandAncestorModule.class)",
+ "interface GrandAncestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestorModule",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class GrandAncestorModule {",
+ " @Provides",
+ " @ElementsIntoSet",
+ " static Set<InLeafAndGrandAncestor> provideInGrandAncestor() {",
+ " return ImmutableSet.of(new InLeafAndGrandAncestor(),",
+ " new InLeafAndGrandAncestor());",
+ " }",
+ "}"));
+ JavaFileObject generatedGrandAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerGrandAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerGrandAncestor implements GrandAncestor {",
+ " protected DaggerGrandAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Set<InLeafAndGrandAncestor> contributionsInLeafAndGrandAncestor() {",
+ " return ImmutableSet.<InLeafAndGrandAncestor>builderWithExpectedSize(3)",
+ " .addAll(GrandAncestorModule_ProvideInGrandAncestorFactory",
+ " .provideInGrandAncestor())",
+ " .addAll(super.contributionsInLeafAndGrandAncestor())",
+ " .build();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerGrandAncestor")
+ .hasSourceEquivalentTo(generatedGrandAncestor);
+ }
+
+ @Test
+ public void setMultibindings_nonComponentMethodDependency() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(
+ filesToCompile, "InAllSubcomponents", "RequresInAllSubcomponentsSet");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " RequresInAllSubcomponentsSet requiresNonComponentMethod();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoSet",
+ " static InAllSubcomponents provideInAllSubcomponents() {",
+ " return new InAllSubcomponents();",
+ " }",
+ "",
+ " @Provides",
+ " static RequresInAllSubcomponentsSet providesRequresInAllSubcomponentsSet(",
+ " Set<InAllSubcomponents> inAllSubcomponents) {",
+ " return new RequresInAllSubcomponentsSet();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public RequresInAllSubcomponentsSet requiresNonComponentMethod() {",
+ " return LeafModule_ProvidesRequresInAllSubcomponentsSetFactory",
+ " .providesRequresInAllSubcomponentsSet(getSetOfInAllSubcomponents());",
+ " }",
+ "",
+ " protected Set getSetOfInAllSubcomponents() {",
+ " return ImmutableSet.<InAllSubcomponents>of(",
+ " LeafModule_ProvideInAllSubcomponentsFactory",
+ " .provideInAllSubcomponents());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoSet",
+ " static InAllSubcomponents provideInAllSubcomponents() {",
+ " return new InAllSubcomponents();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected Set getSetOfInAllSubcomponents() {",
+ " return ImmutableSet.<InAllSubcomponents>builderWithExpectedSize(2)",
+ " .add(AncestorModule_ProvideInAllSubcomponentsFactory",
+ " .provideInAllSubcomponents())",
+ " .addAll(super.getSetOfInAllSubcomponents())",
+ " .build();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void setMultibindings_newSubclass() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InAncestor", "RequiresInAncestorSet");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " RequiresInAncestorSet missingWithSetDependency();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract RequiresInAncestorSet missingWithSetDependency();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ "",
+ " @Provides",
+ " static RequiresInAncestorSet provideRequiresInAncestorSet(",
+ " Set<InAncestor> inAncestors) {",
+ " return new RequiresInAncestorSet();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static InAncestor provideInAncestor() {",
+ " return new InAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " private RequiresInAncestorSet getRequiresInAncestorSet() {",
+ " return AncestorModule_ProvideRequiresInAncestorSetFactory",
+ " .provideRequiresInAncestorSet(getSetOfInAncestor());",
+ " }",
+ "",
+ " protected Set getSetOfInAncestor() {",
+ " return ImmutableSet.<InAncestor>of(",
+ " AncestorModule_ProvideInAncestorFactory.provideInAncestor());",
+ " }",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final RequiresInAncestorSet missingWithSetDependency() {",
+ " return DaggerAncestor.this.getRequiresInAncestorSet();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void setMultibinding_requestedAsInstanceInLeaf_requestedAsFrameworkInstanceFromAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(
+ filesToCompile, "Multibound", "MissingInLeaf_WillDependOnFrameworkInstance");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Set<Multibound> instance();",
+ " MissingInLeaf_WillDependOnFrameworkInstance willDependOnFrameworkInstance();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Multibound contribution() {",
+ " return new Multibound();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Set<Multibound> instance() {",
+ " return ImmutableSet.<Multibound>of(",
+ " LeafModule_ContributionFactory.contribution());",
+ " }",
+ "",
+ " @Override",
+ " public abstract MissingInLeaf_WillDependOnFrameworkInstance",
+ " willDependOnFrameworkInstance();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Set;",
+ "import javax.inject.Provider;",
+ "",
+ "@Module",
+ "interface AncestorModule {",
+ " @Provides",
+ " static MissingInLeaf_WillDependOnFrameworkInstance providedInAncestor(",
+ " Provider<Set<Multibound>> frameworkInstance) {",
+ " return null;",
+ " }",
+ "",
+ " @Multibinds Set<Multibound> multibinds();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Set<Multibound>> setOfMultiboundProvider;",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " protected void configureInitialization() { ",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() { ",
+ " this.setOfMultiboundProvider =",
+ " SetFactory.<Multibound>builder(1, 0)",
+ " .addProvider(LeafModule_ContributionFactory.create())",
+ " .build();",
+ " }",
+ "",
+ " protected Provider getSetOfMultiboundProvider() {",
+ " return setOfMultiboundProvider;",
+ " }",
+ "",
+ " @Override",
+ " public final MissingInLeaf_WillDependOnFrameworkInstance ",
+ " willDependOnFrameworkInstance() {",
+ " return AncestorModule_ProvidedInAncestorFactory.providedInAncestor(",
+ " getSetOfMultiboundProvider());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void missingMultibindingInLeaf_onlyContributionsInAncestor_notReModifiedInRoot() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Set<Object> set();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract Set<Object> set();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Object onlyContribution() {",
+ " return new Object();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Set<Object> set() {",
+ " return ImmutableSet.<Object>of(",
+ " AncestorModule_OnlyContributionFactory.onlyContribution());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Ancestor ancestor() {",
+ " return new AncestorImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " private AncestorImpl() {}",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " private LeafImpl() {}",
+ // This tests a regression case where Dagger used to reimplement Leaf.set(), even though
+ // there were no new contributions, because the state change from missing ->
+ // multibinding wasn't properly recorded
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void setMultibindings_contributionsInLeafAndAncestor_frameworkInstances() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InEachSubcomponent");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Provider<Set<InEachSubcomponent>> contributionsInEachSubcomponent();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoSet",
+ " static InEachSubcomponent provideInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static InEachSubcomponent provideAnotherInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private Provider<Set<InEachSubcomponent>> setOfInEachSubcomponentProvider;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.setOfInEachSubcomponentProvider =",
+ " SetFactory.<InEachSubcomponent>builder(2, 0)",
+ " .addProvider(LeafModule_ProvideInLeafFactory.create())",
+ " .addProvider(LeafModule_ProvideAnotherInLeafFactory.create())",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Set<InEachSubcomponent>> contributionsInEachSubcomponent() {",
+ " return setOfInEachSubcomponentProvider;",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.ElementsIntoSet;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @ElementsIntoSet",
+ " static Set<InEachSubcomponent> provideInAncestor() {",
+ " return ImmutableSet.of(new InEachSubcomponent(), new InEachSubcomponent());",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Set<InEachSubcomponent>> setOfInEachSubcomponentProvider = ",
+ " new DelegateFactory<>();",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected void configureInitialization() {",
+ " super.configureInitialization();",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " DelegateFactory.setDelegate(",
+ " setOfInEachSubcomponentProvider,",
+ " SetFactory.<InEachSubcomponent>builder(0, 2)",
+ " .addCollectionProvider(super.contributionsInEachSubcomponent())",
+ " .addCollectionProvider(",
+ " AncestorModule_ProvideInAncestorFactory.create())",
+ " .build());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Set<InEachSubcomponent>> contributionsInEachSubcomponent() {",
+ " return setOfInEachSubcomponentProvider;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void mapMultibindings_contributionsInLeaf() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Map<String, InLeaf> contributionsInLeaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"leafmodule\")",
+ " static InLeaf provideInLeaf() {",
+ " return new InLeaf();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Map<String, InLeaf> contributionsInLeaf() {",
+ " return ImmutableMap.<String, InLeaf>of(",
+ " \"leafmodule\",",
+ " LeafModule_ProvideInLeafFactory.provideInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+ }
+
+ @Test
+ public void mapMultibindings_contributionsInAncestorOnly() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Map<String, InAncestor> contributionsInAncestor();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract Map<String, InAncestor> contributionsInAncestor();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"ancestormodule\")",
+ " static InAncestor provideInAncestor() {",
+ " return new InAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Map<String, InAncestor> contributionsInAncestor() {",
+ " return ImmutableMap.<String, InAncestor>of(\"ancestormodule\",",
+ " AncestorModule_ProvideInAncestorFactory.provideInAncestor());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void mapMultibindings_contributionsInLeafAndAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InEachSubcomponent");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Map<String, InEachSubcomponent> contributionsInEachSubcomponent();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"leafmodule\")",
+ " static InEachSubcomponent provideInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Map<String, InEachSubcomponent> contributionsInEachSubcomponent() {",
+ " return ImmutableMap.<String, InEachSubcomponent>of(",
+ " \"leafmodule\", LeafModule_ProvideInLeafFactory.provideInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"ancestormodule\")",
+ " static InEachSubcomponent provideInAncestor() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Map<String, InEachSubcomponent> contributionsInEachSubcomponent() {",
+ " return ImmutableMap.<String, InEachSubcomponent>builderWithExpectedSize(2)",
+ " .put(\"ancestormodule\",",
+ " AncestorModule_ProvideInAncestorFactory.provideInAncestor())",
+ " .putAll(super.contributionsInEachSubcomponent())",
+ " .build();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void mapMultibindings_contributionsInLeafAndAncestor_frameworkInstance() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InEachSubcomponent");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Provider<Map<String, InEachSubcomponent>> contributionsInEachSubcomponent();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"leafmodule\")",
+ " static InEachSubcomponent provideInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.MapFactory;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private Provider<Map<String, InEachSubcomponent>> ",
+ " mapOfStringAndInEachSubcomponentProvider;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.mapOfStringAndInEachSubcomponentProvider =",
+ " MapFactory.<String, InEachSubcomponent>builder(1)",
+ " .put(\"leafmodule\", LeafModule_ProvideInLeafFactory.create())",
+ " .build();",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Map<String, InEachSubcomponent>> ",
+ " contributionsInEachSubcomponent() {",
+ " return mapOfStringAndInEachSubcomponentProvider;",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"ancestormodule\")",
+ " static InEachSubcomponent provideInAncestor() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.MapFactory;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Map<String, InEachSubcomponent>> ",
+ " mapOfStringAndInEachSubcomponentProvider = new DelegateFactory<>();",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected void configureInitialization() { ",
+ " super.configureInitialization();",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() { ",
+ " DelegateFactory.setDelegate(",
+ " mapOfStringAndInEachSubcomponentProvider,",
+ " MapFactory.<String, InEachSubcomponent>builder(2)",
+ " .putAll(super.contributionsInEachSubcomponent())",
+ " .put(",
+ " \"ancestormodule\",",
+ " AncestorModule_ProvideInAncestorFactory.create())",
+ " .build());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Map<String, InEachSubcomponent>> ",
+ " contributionsInEachSubcomponent() {",
+ " return mapOfStringAndInEachSubcomponentProvider;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void mapMultibindings_contributionsInLeafAndGrandAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InLeafAndGrandAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Map<String, InLeafAndGrandAncestor> contributionsInLeafAndGrandAncestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"leafmodule\")",
+ " static InLeafAndGrandAncestor provideInLeaf() {",
+ " return new InLeafAndGrandAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Map<String, InLeafAndGrandAncestor> contributionsInLeafAndGrandAncestor() {",
+ " return ImmutableMap.<String, InLeafAndGrandAncestor>of(",
+ " \"leafmodule\", LeafModule_ProvideInLeafFactory.provideInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = GrandAncestorModule.class)",
+ "interface GrandAncestor {",
+ " Ancestor ancestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class GrandAncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"grandancestormodule\")",
+ " static InLeafAndGrandAncestor provideInGrandAncestor() {",
+ " return new InLeafAndGrandAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedGrandAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerGrandAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerGrandAncestor implements GrandAncestor {",
+ " protected DaggerGrandAncestor() {}",
+ "",
+ " protected abstract class AncestorImpl extends DaggerAncestor {",
+ " protected AncestorImpl() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Map<String, InLeafAndGrandAncestor>",
+ " contributionsInLeafAndGrandAncestor() {",
+ " return",
+ " ImmutableMap.<String, InLeafAndGrandAncestor>builderWithExpectedSize(2)",
+ " .put(\"grandancestormodule\",",
+ " GrandAncestorModule_ProvideInGrandAncestorFactory",
+ " .provideInGrandAncestor())",
+ " .putAll(super.contributionsInLeafAndGrandAncestor())",
+ " .build();",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerGrandAncestor")
+ .hasSourceEquivalentTo(generatedGrandAncestor);
+ }
+
+ @Test
+ public void mapMultibindings_contributionsInLeafAndAncestorWithoutGuava() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InEachSubcomponent");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Map<String, InEachSubcomponent> contributionsInEachSubcomponent();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"leafmodule\")",
+ " static InEachSubcomponent provideInLeaf() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Collections;",
+ "import java.util.Map",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Map<String, InEachSubcomponent> contributionsInEachSubcomponent() {",
+ " return Collections.<String, InEachSubcomponent>singletonMap(",
+ " \"leafmodule\", LeafModule_ProvideInLeafFactory.provideInLeaf());",
+ " }",
+ "}");
+ Compilation compilation = compileWithoutGuava(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.StringKey;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @StringKey(\"ancestormodule\")",
+ " static InEachSubcomponent provideInAncestor() {",
+ " return new InEachSubcomponent();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.MapBuilder;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Map<String, InEachSubcomponent> contributionsInEachSubcomponent() {",
+ " return MapBuilder.<String, InEachSubcomponent>newMapBuilder(2)",
+ " .put(\"ancestormodule\",",
+ " AncestorModule_ProvideInAncestorFactory.provideInAncestor())",
+ " .putAll(super.contributionsInEachSubcomponent())",
+ " .build();",
+ " }",
+ " }",
+ "}");
+ compilation = compileWithoutGuava(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void mapMultibinding_requestedAsInstanceInLeaf_requestedAsFrameworkInstanceFromAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(
+ filesToCompile, "Multibound", "MissingInLeaf_WillDependOnFrameworkInstance");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Map<Integer, Multibound> instance();",
+ " MissingInLeaf_WillDependOnFrameworkInstance willDependOnFrameworkInstance();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntKey;",
+ "import dagger.multibindings.IntoMap;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " @IntoMap",
+ " @IntKey(111)",
+ " static Multibound contribution() {",
+ " return new Multibound();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Map<Integer, Multibound> instance() {",
+ " return ImmutableMap.<Integer, Multibound>of(",
+ " 111, LeafModule_ContributionFactory.contribution());",
+ " }",
+ "",
+ " @Override",
+ " public abstract MissingInLeaf_WillDependOnFrameworkInstance",
+ " willDependOnFrameworkInstance();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Module",
+ "interface AncestorModule {",
+ " @Provides",
+ " static MissingInLeaf_WillDependOnFrameworkInstance providedInAncestor(",
+ " Provider<Map<Integer, Multibound>> frameworkInstance) {",
+ " return null;",
+ " }",
+ "",
+ " @Multibinds Map<Integer, Multibound> multibinds();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.MapFactory;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Map<Integer, Multibound>> mapOfIntegerAndMultiboundProvider;",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " protected void configureInitialization() { ",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() { ",
+ " this.mapOfIntegerAndMultiboundProvider =",
+ " MapFactory.<Integer, Multibound>builder(1)",
+ " .put(111, LeafModule_ContributionFactory.create())",
+ " .build();",
+ " }",
+ "",
+ " protected Provider getMapOfIntegerAndMultiboundProvider() {",
+ " return mapOfIntegerAndMultiboundProvider;",
+ " }",
+ "",
+ " @Override",
+ " public final MissingInLeaf_WillDependOnFrameworkInstance ",
+ " willDependOnFrameworkInstance() {",
+ " return AncestorModule_ProvidedInAncestorFactory.providedInAncestor(",
+ " getMapOfIntegerAndMultiboundProvider());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void emptyMultibinds_set() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Multibound");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Multibinds",
+ " Set<Multibound> set();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Set<Multibound> set();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Set<Multibound> set() {",
+ " return ImmutableSet.<Multibound>of();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Multibound fromAncestor() {",
+ " return new Multibound();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Set<Multibound> set() {",
+ " return ImmutableSet.<Multibound>of(",
+ " AncestorModule_FromAncestorFactory.fromAncestor());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void emptyMultibinds_set_frameworkInstance() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Multibound");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Multibinds",
+ " Set<Multibound> set();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Provider<Set<Multibound>> set();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Provider<Set<Multibound>> set() {",
+ " return SetFactory.<Multibound>empty();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Multibound fromAncestor() {",
+ " return new Multibound();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Set<Multibound>> setOfMultiboundProvider =",
+ " new DelegateFactory<>();",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " DelegateFactory.setDelegate(",
+ " setOfMultiboundProvider,",
+ " SetFactory.<Multibound>builder(1, 0)",
+ " .addProvider(AncestorModule_FromAncestorFactory.create())",
+ " .build());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Set<Multibound>> set() {",
+ " return setOfMultiboundProvider;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void emptyMultibinds_map() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Multibound");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Multibinds",
+ " Map<Integer, Multibound> map();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Map<Integer, Multibound> map();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Map<Integer, Multibound> map() {",
+ " return ImmutableMap.<Integer, Multibound>of();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntKey;",
+ "import dagger.multibindings.IntoMap;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @IntKey(111)",
+ " static Multibound fromAncestor() {",
+ " return new Multibound();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableMap;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Map<Integer, Multibound> map() {",
+ " return ImmutableMap.<Integer, Multibound>of(",
+ " 111, AncestorModule_FromAncestorFactory.fromAncestor());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void emptyMultibinds_map_frameworkInstance() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Multibound");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Map;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Multibinds",
+ " Map<Integer, Multibound> map();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Provider<Map<Integer, Multibound>> map();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.MapFactory;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Provider<Map<Integer, Multibound>> map() {",
+ " return MapFactory.<Integer, Multibound>emptyMapProvider();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntKey;",
+ "import dagger.multibindings.IntoMap;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " @IntoMap",
+ " @IntKey(111)",
+ " static Multibound fromAncestor() {",
+ " return new Multibound();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.MapFactory;",
+ "import java.util.Map;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Map<Integer, Multibound>> mapOfIntegerAndMultiboundProvider =",
+ " new DelegateFactory<>()",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " DelegateFactory.setDelegate(",
+ " mapOfIntegerAndMultiboundProvider,",
+ " MapFactory.<Integer, Multibound>builder(1)",
+ " .put(111, AncestorModule_FromAncestorFactory.create())",
+ " .build());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Map<Integer, Multibound>> map() {",
+ " return mapOfIntegerAndMultiboundProvider;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void bindsMissingDep_Multibindings() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Module;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Binds",
+ " @IntoSet",
+ " CharSequence bindsMultibindingWithMissingDep(String string);",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Set;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Set<CharSequence> set();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Set<CharSequence> set() {",
+ " return ImmutableSet.<CharSequence>of(getBindsMultibindingWithMissingDep());",
+ " }",
+ "",
+ // The expected output here is subtle: the Key of
+ // LeafModule.bindsMultibindingWithMissingDep() is Set<CharSequence>, but the binding
+ // method should only be returning an individual CharSequence. Otherwise the
+ // ImmutableSet factory method above will fail.
+ " protected abstract CharSequence getBindsMultibindingWithMissingDep();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+ }
+
+ @Test
+ public void multibindingsAndFastInit() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "PackagePrivate");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.MultibindingModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntKey;",
+ "import dagger.multibindings.IntoMap;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "interface MultibindingModule {",
+ " @Provides",
+ " @IntoSet",
+ " @LeafScope",
+ " static PackagePrivate setContribution() {",
+ " return new PackagePrivate();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoMap",
+ " @IntKey(1)",
+ " @LeafScope",
+ " static PackagePrivate mapContribution() {",
+ " return new PackagePrivate();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "@interface LeafScope {}"),
+ JavaFileObjects.forSourceLines(
+ "test.UsesMultibindings",
+ "package test;",
+ "",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "import javax.inject.Inject;",
+ "",
+ "class UsesMultibindings {",
+ " @Inject",
+ " UsesMultibindings(Set<PackagePrivate> set, Map<Integer, PackagePrivate> map) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Map;",
+ "import java.util.Set;",
+ "",
+ "@LeafScope",
+ "@Subcomponent(modules = MultibindingModule.class)",
+ "interface Leaf {",
+ " UsesMultibindings entryPoint();",
+ "}"));
+
+ Compilation compilation =
+ compilerWithOptions(AHEAD_OF_TIME_SUBCOMPONENTS_MODE, FAST_INIT_MODE)
+ .compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "@GenerationOptions(fastInit = true)",
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " private PackagePrivate getSetContribution() {",
+ " Object local = setContribution;",
+ " if (local instanceof MemoizedSentinel) {",
+ " synchronized (local) {",
+ " local = setContribution;",
+ " if (local instanceof MemoizedSentinel) {",
+ " local = MultibindingModule_SetContributionFactory.setContribution();",
+ " setContribution = DoubleCheck.reentrantCheck(setContribution, local);",
+ " }",
+ " }",
+ " }",
+ " return (PackagePrivate) local;",
+ " }",
+ "",
+ " private PackagePrivate getMapContribution() {",
+ " Object local = mapContribution;",
+ " if (local instanceof MemoizedSentinel) {",
+ " synchronized (local) {",
+ " local = mapContribution;",
+ " if (local instanceof MemoizedSentinel) {",
+ " local = MultibindingModule_MapContributionFactory.mapContribution();",
+ " mapContribution = DoubleCheck.reentrantCheck(mapContribution, local);",
+ " }",
+ " }",
+ " }",
+ " return (PackagePrivate) local;",
+ " }",
+ "",
+ " @Override",
+ " public UsesMultibindings entryPoint() {",
+ " return new UsesMultibindings(",
+ " getSetOfPackagePrivate(), getMapOfIntegerAndPackagePrivate());",
+ " }",
+ "",
+ " protected Set getSetOfPackagePrivate() {",
+ " return ImmutableSet.<PackagePrivate>of(getSetContribution());",
+ " }",
+ "",
+ " protected Map getMapOfIntegerAndPackagePrivate() {",
+ " return ImmutableMap.<Integer, PackagePrivate>of(1, getMapContribution());",
+ " }",
+ "}");
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .containsElementsIn(generatedLeaf);
+ }
+
+ // TODO(ronshapiro): remove copies from AheadOfTimeSubcomponents*Test classes
+ private void createSimplePackagePrivateClasses(
+ ImmutableList.Builder<JavaFileObject> filesBuilder, String... ancillaryClasses) {
+ for (String className : ancillaryClasses) {
+ filesBuilder.add(
+ JavaFileObjects.forSourceLines(
+ String.format("test.%s", className),
+ "package test;",
+ "",
+ String.format("class %s { }", className)));
+ }
+ }
+
+ private static Compilation compile(Iterable<JavaFileObject> files) {
+ return compilerWithOptions(AHEAD_OF_TIME_SUBCOMPONENTS_MODE).compile(files);
+ }
+
+ private static Compilation compileWithoutGuava(Iterable<JavaFileObject> files) {
+ return daggerCompiler()
+ .withOptions(
+ AHEAD_OF_TIME_SUBCOMPONENTS_MODE.javacopts().append(CLASS_PATH_WITHOUT_GUAVA_OPTION))
+ .compile(files);
+ }
+}
diff --git a/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsTest.java b/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsTest.java
new file mode 100644
index 0000000..1bd221a
--- /dev/null
+++ b/javatests/dagger/internal/codegen/AheadOfTimeSubcomponentsTest.java
@@ -0,0 +1,5677 @@
+/*
+ * Copyright (C) 2018 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.testing.compile.CompilationSubject.assertThat;
+import static dagger.internal.codegen.CompilerMode.AHEAD_OF_TIME_SUBCOMPONENTS_MODE;
+import static dagger.internal.codegen.Compilers.compilerWithOptions;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.GENERATION_OPTIONS_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ObjectArrays;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class AheadOfTimeSubcomponentsTest {
+ private static final String PRUNED_METHOD_BODY =
+ "throw new UnsupportedOperationException(\"This binding is not part of the final binding "
+ + "graph. The key was requested by a binding that was believed to possibly be part of "
+ + "the graph, but is no longer requested. If this exception is thrown, it is the result "
+ + "of a Dagger bug.\");";
+
+ @Test
+ public void missingBindings_fromComponentMethod() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " MissingInLeaf missingFromComponentMethod();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract MissingInLeaf missingFromComponentMethod();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " static MissingInLeaf satisfiedInAncestor() { return new MissingInLeaf(); }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final MissingInLeaf missingFromComponentMethod() {",
+ " return AncestorModule_SatisfiedInAncestorFactory.satisfiedInAncestor();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void missingBindings_dependsOnBindingWithMatchingComponentMethod() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " MissingInLeaf missingComponentMethod();",
+ " DependsOnComponentMethod dependsOnComponentMethod();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.DependsOnComponentMethod",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class DependsOnComponentMethod {",
+ " @Inject DependsOnComponentMethod(MissingInLeaf missingInLeaf) {}",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract MissingInLeaf missingComponentMethod();",
+ "",
+ " @Override",
+ " public DependsOnComponentMethod dependsOnComponentMethod() {",
+ " return new DependsOnComponentMethod(missingComponentMethod());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+ }
+
+ @Test
+ public void missingBindings_dependsOnMissingBinding() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " DependsOnMissingBinding dependsOnMissingBinding();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.DependsOnMissingBinding",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class DependsOnMissingBinding {",
+ " @Inject DependsOnMissingBinding(MissingInLeaf missing) {}",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public DependsOnMissingBinding dependsOnMissingBinding() {",
+ " return new DependsOnMissingBinding((MissingInLeaf) getMissingInLeaf());",
+ " }",
+ "",
+ " protected abstract Object getMissingInLeaf();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " static MissingInLeaf satisfiedInAncestor() { return new MissingInLeaf(); }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected final Object getMissingInLeaf() {",
+ " return AncestorModule_SatisfiedInAncestorFactory.satisfiedInAncestor();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void missingBindings_satisfiedInGreatAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " DependsOnMissingBinding dependsOnMissingBinding();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.DependsOnMissingBinding",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class DependsOnMissingBinding {",
+ " @Inject DependsOnMissingBinding(MissingInLeaf missing) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.GreatAncestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = SatisfiesMissingBindingModule.class)",
+ "interface GreatAncestor {",
+ " Ancestor ancestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.SatisfiesMissingBindingModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class SatisfiesMissingBindingModule {",
+ " @Provides",
+ " static MissingInLeaf satisfy() { return new MissingInLeaf(); }",
+ "}"));
+ // DaggerLeaf+DaggerAncestor generated types are ignored - they're not the focus of this test
+ // and are tested elsewhere
+ JavaFileObject generatedGreatAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerGreatAncestor implements GreatAncestor {",
+ " protected DaggerGreatAncestor() {}",
+ "",
+ " protected abstract class AncestorImpl extends DaggerAncestor {",
+ " protected AncestorImpl() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected final Object getMissingInLeaf() {",
+ " return SatisfiesMissingBindingModule_SatisfyFactory.satisfy();",
+ " }",
+ " }",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerGreatAncestor")
+ .hasSourceEquivalentTo(generatedGreatAncestor);
+ }
+
+ @Test
+ public void moduleInstanceDependency() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface Leaf {",
+ " String string();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class TestModule {",
+ " @Provides String provideString() { return \"florp\"; }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public String string() {",
+ " return TestModule_ProvideStringFactory.provideString(testModule());",
+ " }",
+ "",
+ " protected abstract TestModule testModule();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Ancestor ancestor() {",
+ " return new AncestorImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " private AncestorImpl() {}",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " private final TestModule testModule;",
+ "",
+ " private LeafImpl() {",
+ " this.testModule = new TestModule();",
+ " }",
+ "",
+ " @Override",
+ " protected TestModule testModule() {",
+ " return testModule;",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void moduleInstanceDependency_withModuleParams() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = TestModule.class)",
+ "interface Leaf {",
+ " int getInt();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "final class TestModule {",
+ " private int i;",
+ "",
+ " TestModule(int i) {}",
+ "",
+ " @Provides int provideInt() {",
+ " return i++;",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public int getInt() {",
+ " return testModule().provideInt();",
+ " }",
+ "",
+ " protected abstract TestModule testModule();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf(TestModule module);",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Ancestor ancestor() {",
+ " return new AncestorImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " private AncestorImpl() {}",
+ "",
+ " @Override",
+ " public Leaf leaf(TestModule module) {",
+ " Preconditions.checkNotNull(module);",
+ " return new LeafImpl(module);",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " private final TestModule testModule;",
+ "",
+ " private LeafImpl(TestModule module) {",
+ " this.testModule = module;",
+ " }",
+ "",
+ " @Override",
+ " protected TestModule testModule() {",
+ " return testModule;",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void generatedInstanceBinding() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " Leaf build();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf.Builder leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " @Override",
+ " public abstract Leaf.Builder leaf();",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Ancestor ancestor() {",
+ " return new AncestorImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " private AncestorImpl() {}",
+ "",
+ " @Override",
+ " public Leaf.Builder leaf() {",
+ " return new LeafBuilder();",
+ " }",
+ "",
+ " private final class LeafBuilder implements Leaf.Builder {",
+ " @Override",
+ " public Leaf build() {",
+ " return new LeafImpl();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " private LeafImpl() {}",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void prunedGeneratedInstanceBinding() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.PrunedSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface PrunedSubcomponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " PrunedSubcomponent build();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.InstallsPrunedSubcomponentModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "",
+ "@Module(subcomponents = PrunedSubcomponent.class)",
+ "interface InstallsPrunedSubcomponentModule {}"),
+ JavaFileObjects.forSourceLines(
+ "test.DependsOnPrunedSubcomponentBuilder",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class DependsOnPrunedSubcomponentBuilder {",
+ " @Inject DependsOnPrunedSubcomponentBuilder(PrunedSubcomponent.Builder builder) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.MaybeLeaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = InstallsPrunedSubcomponentModule.class)",
+ "interface MaybeLeaf {",
+ " DependsOnPrunedSubcomponentBuilder dependsOnPrunedSubcomponentBuilder();",
+ "}"));
+ JavaFileObject generatedMaybeLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerMaybeLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerMaybeLeaf implements MaybeLeaf {",
+ " protected DaggerMaybeLeaf() {}",
+ "",
+ " @Override",
+ " public DependsOnPrunedSubcomponentBuilder dependsOnPrunedSubcomponentBuilder() {",
+ " return new DependsOnPrunedSubcomponentBuilder(",
+ " (PrunedSubcomponent.Builder) getPrunedSubcomponentBuilder());",
+ " }",
+ "",
+ " protected abstract Object getPrunedSubcomponentBuilder();",
+ "",
+ " protected abstract class PrunedSubcomponentImpl extends DaggerPrunedSubcomponent {",
+ " protected PrunedSubcomponentImpl() {}",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerMaybeLeaf")
+ .hasSourceEquivalentTo(generatedMaybeLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.PrunesGeneratedInstanceModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface PrunesGeneratedInstanceModule {",
+ " @Provides",
+ " static DependsOnPrunedSubcomponentBuilder pruneGeneratedInstance() {",
+ " return new DependsOnPrunedSubcomponentBuilder(null);",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = PrunesGeneratedInstanceModule.class)",
+ "interface Root {",
+ " MaybeLeaf actuallyLeaf();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public MaybeLeaf actuallyLeaf() {",
+ " return new MaybeLeafImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class MaybeLeafImpl extends DaggerMaybeLeaf {",
+ " private MaybeLeafImpl() {}",
+ "",
+ " @Override",
+ " protected Object getPrunedSubcomponentBuilder() {",
+ " " + PRUNED_METHOD_BODY,
+ " }",
+ "",
+ " @Override",
+ " public DependsOnPrunedSubcomponentBuilder dependsOnPrunedSubcomponentBuilder() {",
+ " return PrunesGeneratedInstanceModule_PruneGeneratedInstanceFactory",
+ " .pruneGeneratedInstance();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void optionalBindings_boundAndSatisfiedInSameSubcomponent() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "SatisfiedInSub");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Sub",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Optional;",
+ "",
+ "@Subcomponent(modules = {SubModule.class, BindsSatisfiedInSubModule.class})",
+ "interface Sub {",
+ " Optional<SatisfiedInSub> satisfiedInSub();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.SubModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "abstract class SubModule {",
+ " @BindsOptionalOf abstract SatisfiedInSub optionalSatisfiedInSub();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.BindsSatisfiedInSubModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class BindsSatisfiedInSubModule {",
+ " @Provides static SatisfiedInSub provideSatisfiedInSub() {",
+ " return new SatisfiedInSub();",
+ " }",
+ "}"));
+ JavaFileObject generatedSubcomponent =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerSub",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerSub implements Sub {",
+ " protected DaggerSub() {}",
+ "",
+ " @Override",
+ " public Optional<SatisfiedInSub> satisfiedInSub() {",
+ " return Optional.of(",
+ " BindsSatisfiedInSubModule_ProvideSatisfiedInSubFactory",
+ " .provideSatisfiedInSub());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerSub")
+ .hasSourceEquivalentTo(generatedSubcomponent);
+ }
+
+ @Test
+ public void optionalBindings_satisfiedInAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "SatisfiedInAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Optional;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Optional<SatisfiedInAncestor> satisfiedInAncestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "abstract class LeafModule {",
+ " @BindsOptionalOf abstract SatisfiedInAncestor optionalSatisfiedInAncestor();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Optional<SatisfiedInAncestor> satisfiedInAncestor() {",
+ " return Optional.<SatisfiedInAncestor>empty();",
+ " }",
+ "}");
+ Compilation compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class AncestorModule {",
+ " @Provides",
+ " static SatisfiedInAncestor satisfiedInAncestor(){",
+ " return new SatisfiedInAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final Optional<SatisfiedInAncestor> satisfiedInAncestor() {",
+ " return Optional.of(AncestorModule_SatisfiedInAncestorFactory",
+ " .satisfiedInAncestor());",
+ " }",
+ "",
+ " }",
+ "}");
+ compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void optionalBindings_satisfiedInGrandAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "SatisfiedInGrandAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Optional;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Optional<SatisfiedInGrandAncestor> satisfiedInGrandAncestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "abstract class LeafModule {",
+ " @BindsOptionalOf",
+ " abstract SatisfiedInGrandAncestor optionalSatisfiedInGrandAncestor();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Optional<SatisfiedInGrandAncestor> satisfiedInGrandAncestor() {",
+ " return Optional.<SatisfiedInGrandAncestor>empty();",
+ " }",
+ "}");
+ Compilation compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.GreatAncestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = GreatAncestorModule.class)",
+ "interface GreatAncestor {",
+ " Ancestor ancestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.GreatAncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class GreatAncestorModule {",
+ " @Provides",
+ " static SatisfiedInGrandAncestor satisfiedInGrandAncestor(){",
+ " return new SatisfiedInGrandAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedGreatAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerGreatAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerGreatAncestor implements GreatAncestor {",
+ " protected DaggerGreatAncestor() {}",
+ "",
+ " protected abstract class AncestorImpl extends DaggerAncestor {",
+ " protected AncestorImpl() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final Optional<SatisfiedInGrandAncestor> satisfiedInGrandAncestor() {",
+ " return Optional.of(",
+ " GreatAncestorModule_SatisfiedInGrandAncestorFactory",
+ " .satisfiedInGrandAncestor());",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerGreatAncestor")
+ .hasSourceEquivalentTo(generatedGreatAncestor);
+ }
+
+ @Test
+ public void optionalBindings_nonComponentMethodDependencySatisfiedInAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(
+ filesToCompile, "SatisfiedInAncestor", "RequiresOptionalSatisfiedInAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Optional;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " RequiresOptionalSatisfiedInAncestor requiresOptionalSatisfiedInAncestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import java.util.Optional;",
+ "",
+ "@Module",
+ "abstract class LeafModule {",
+ " @Provides static RequiresOptionalSatisfiedInAncestor",
+ " provideRequiresOptionalSatisfiedInAncestor(",
+ " Optional<SatisfiedInAncestor> satisfiedInAncestor) {",
+ " return new RequiresOptionalSatisfiedInAncestor();",
+ " }",
+ "",
+ " @BindsOptionalOf abstract SatisfiedInAncestor optionalSatisfiedInAncestor();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public RequiresOptionalSatisfiedInAncestor",
+ " requiresOptionalSatisfiedInAncestor() {",
+ " return LeafModule_ProvideRequiresOptionalSatisfiedInAncestorFactory",
+ " .provideRequiresOptionalSatisfiedInAncestor(",
+ " getOptionalOfSatisfiedInAncestor());",
+ " }",
+ "",
+ " protected Optional getOptionalOfSatisfiedInAncestor() {",
+ " return Optional.<SatisfiedInAncestor>empty();",
+ " }",
+ "}");
+ Compilation compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class AncestorModule {",
+ " @Provides",
+ " static SatisfiedInAncestor satisfiedInAncestor(){",
+ " return new SatisfiedInAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected final Optional getOptionalOfSatisfiedInAncestor() {",
+ " return Optional.of(",
+ " AncestorModule_SatisfiedInAncestorFactory.satisfiedInAncestor());",
+ " }",
+ " }",
+ "}");
+ compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void optionalBindings_boundInAncestorAndSatisfiedInGrandAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "SatisfiedInGrandAncestor");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import java.util.Optional;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Optional<SatisfiedInGrandAncestor> boundInAncestorSatisfiedInGrandAncestor();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract Optional<SatisfiedInGrandAncestor>",
+ " boundInAncestorSatisfiedInGrandAncestor();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "abstract class AncestorModule {",
+ " @BindsOptionalOf",
+ " abstract SatisfiedInGrandAncestor optionalSatisfiedInGrandAncestor();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public Optional<SatisfiedInGrandAncestor>",
+ " boundInAncestorSatisfiedInGrandAncestor() {",
+ " return Optional.<SatisfiedInGrandAncestor>empty();",
+ " }",
+ " }",
+ "}");
+ compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = GrandAncestorModule.class)",
+ "interface GrandAncestor {",
+ " Ancestor ancestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class GrandAncestorModule {",
+ " @Provides static SatisfiedInGrandAncestor provideSatisfiedInGrandAncestor() {",
+ " return new SatisfiedInGrandAncestor();",
+ " }",
+ "}"));
+ JavaFileObject generatedGrandAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerGrandAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Optional;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerGrandAncestor implements GrandAncestor {",
+ " protected DaggerGrandAncestor() {}",
+ "",
+ " protected abstract class AncestorImpl extends DaggerAncestor {",
+ " protected AncestorImpl() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final Optional<SatisfiedInGrandAncestor>",
+ " boundInAncestorSatisfiedInGrandAncestor() {",
+ " return Optional.of(",
+ " GrandAncestorModule_ProvideSatisfiedInGrandAncestorFactory",
+ " .provideSatisfiedInGrandAncestor());",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation =
+ compile(
+ filesToCompile.build()
+ , CompilerMode.JAVA7
+ );
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerGrandAncestor")
+ .hasSourceEquivalentTo(generatedGrandAncestor);
+ }
+
+ @Test
+ public void provisionOverInjection_providedInAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.ProvidedInAncestor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class ProvidedInAncestor {",
+ " @Inject",
+ " ProvidedInAncestor(String string) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " ProvidedInAncestor injectedInLeaf();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public ProvidedInAncestor injectedInLeaf() {",
+ " return new ProvidedInAncestor(getString());",
+ " }",
+ "",
+ " protected abstract String getString();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " static ProvidedInAncestor provideProvidedInAncestor() {",
+ " return new ProvidedInAncestor(\"static\");",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final ProvidedInAncestor injectedInLeaf() {",
+ " return AncestorModule_ProvideProvidedInAncestorFactory",
+ " .provideProvidedInAncestor();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void provisionOverInjection_providedInGrandAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.ProvidedInGrandAncestor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class ProvidedInGrandAncestor {",
+ " @Inject",
+ " ProvidedInGrandAncestor(String string) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " ProvidedInGrandAncestor injectedInLeaf();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public ProvidedInGrandAncestor injectedInLeaf() {",
+ " return new ProvidedInGrandAncestor(getString());",
+ " }",
+ "",
+ " protected abstract String getString();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = GrandAncestorModule.class)",
+ "interface GrandAncestor {",
+ " Ancestor ancestor();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.GrandAncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class GrandAncestorModule {",
+ " @Provides",
+ " static ProvidedInGrandAncestor provideProvidedInGrandAncestor() {",
+ " return new ProvidedInGrandAncestor(\"static\");",
+ " }",
+ "}"));
+ JavaFileObject generatedGrandAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerGrandAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerGrandAncestor implements GrandAncestor {",
+ " protected DaggerGrandAncestor() {}",
+ "",
+ " protected abstract class AncestorImpl extends DaggerAncestor {",
+ " protected AncestorImpl() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final ProvidedInGrandAncestor injectedInLeaf() {",
+ " return GrandAncestorModule_ProvideProvidedInGrandAncestorFactory",
+ " .provideProvidedInGrandAncestor();",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerGrandAncestor")
+ .hasSourceEquivalentTo(generatedGrandAncestor);
+ }
+
+ @Test
+ public void provisionOverInjection_indirectDependency() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.ProvidedInAncestor",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class ProvidedInAncestor {",
+ " @Inject",
+ " ProvidedInAncestor(String string) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.InjectedInLeaf",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectedInLeaf {",
+ " @Inject",
+ " InjectedInLeaf(ProvidedInAncestor providedInAncestor) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " InjectedInLeaf injectedInLeaf();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public InjectedInLeaf injectedInLeaf() {",
+ " return new InjectedInLeaf((ProvidedInAncestor) getProvidedInAncestor());",
+ " }",
+ "",
+ " protected abstract String getString();",
+ "",
+ " protected Object getProvidedInAncestor() {",
+ " return new ProvidedInAncestor(getString());",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " static ProvidedInAncestor provideProvidedInAncestor() {",
+ " return new ProvidedInAncestor(\"static\");",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected final Object getProvidedInAncestor() {",
+ " return AncestorModule_ProvideProvidedInAncestorFactory",
+ " .provideProvidedInAncestor();",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void provisionOverInjection_prunedIndirectDependency() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "PrunedDependency");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.InjectsPrunedDependency",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectsPrunedDependency {",
+ " @Inject",
+ " InjectsPrunedDependency(PrunedDependency prunedDependency) {}",
+ "",
+ " private InjectsPrunedDependency() { }",
+ "",
+ " static InjectsPrunedDependency create() { return new InjectsPrunedDependency(); }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " InjectsPrunedDependency injectsPrunedDependency();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public InjectsPrunedDependency injectsPrunedDependency() {",
+ " return new InjectsPrunedDependency((PrunedDependency) getPrunedDependency());",
+ " }",
+ "",
+ " protected abstract Object getPrunedDependency();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class RootModule {",
+ " @Provides",
+ " static InjectsPrunedDependency injectsPrunedDependency() {",
+ " return InjectsPrunedDependency.create();",
+ " }",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " @Deprecated",
+ " public Builder rootModule(RootModule rootModule) {",
+ " Preconditions.checkNotNull(rootModule);",
+ " return this;",
+ " }",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private LeafImpl() {}",
+ "",
+ " @Override",
+ " protected Object getPrunedDependency() {",
+ " " + PRUNED_METHOD_BODY,
+ " }",
+ "",
+ " @Override",
+ " public InjectsPrunedDependency injectsPrunedDependency() {",
+ " return RootModule_InjectsPrunedDependencyFactory",
+ " .injectsPrunedDependency();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void provisionOverInjection_prunedDirectDependency_prunedInConcreteImplementation() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ // The binding for PrunedDependency will always exist, but will change from
+ // ModifiableBindingType.INJECTION to ModifiableBindingType.MISSING. We should correctly
+ // ignore this change leave the modifiable binding method alone
+ JavaFileObjects.forSourceLines(
+ "test.PrunedDependency",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrunedDependency {",
+ " @Inject PrunedDependency() {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.InjectsPrunedDependency",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectsPrunedDependency {",
+ " @Inject",
+ " InjectsPrunedDependency(PrunedDependency prunedDependency) {}",
+ "",
+ " private InjectsPrunedDependency() { }",
+ "",
+ " static InjectsPrunedDependency create() { return new InjectsPrunedDependency(); }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " InjectsPrunedDependency injectsPrunedDependency();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public InjectsPrunedDependency injectsPrunedDependency() {",
+ " return new InjectsPrunedDependency((PrunedDependency) getPrunedDependency());",
+ " }",
+ "",
+ " protected Object getPrunedDependency() {",
+ " return new PrunedDependency();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class RootModule {",
+ " @Provides",
+ " static InjectsPrunedDependency injectsPrunedDependency() {",
+ " return InjectsPrunedDependency.create();",
+ " }",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " @Deprecated",
+ " public Builder rootModule(RootModule rootModule) {",
+ " Preconditions.checkNotNull(rootModule);",
+ " return this;",
+ " }",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private LeafImpl() {}",
+ "",
+ " @Override",
+ " public InjectsPrunedDependency injectsPrunedDependency() {",
+ " return RootModule_InjectsPrunedDependencyFactory",
+ " .injectsPrunedDependency();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void provisionOverInjection_prunedDirectDependency_prunedInAbstractImplementation() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ // The binding for PrunedDependency will always exist, but will change from
+ // ModifiableBindingType.INJECTION to ModifiableBindingType.MISSING. We should correctly
+ // ignore this change leave the modifiable binding method alone
+ JavaFileObjects.forSourceLines(
+ "test.PrunedDependency",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class PrunedDependency {",
+ " @Inject PrunedDependency() {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.InjectsPrunedDependency",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectsPrunedDependency {",
+ " @Inject",
+ " InjectsPrunedDependency(PrunedDependency prunedDependency) {}",
+ "",
+ " private InjectsPrunedDependency() { }",
+ "",
+ " static InjectsPrunedDependency create() { return new InjectsPrunedDependency(); }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " InjectsPrunedDependency injectsPrunedDependency();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public InjectsPrunedDependency injectsPrunedDependency() {",
+ " return new InjectsPrunedDependency((PrunedDependency) getPrunedDependency());",
+ " }",
+ "",
+ " protected Object getPrunedDependency() {",
+ " return new PrunedDependency();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " static InjectsPrunedDependency injectsPrunedDependency() {",
+ " return InjectsPrunedDependency.create();",
+ " }",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " public final InjectsPrunedDependency injectsPrunedDependency() {",
+ " return AncestorModule_InjectsPrunedDependencyFactory",
+ " .injectsPrunedDependency();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Ancestor ancestor() {",
+ " return new AncestorImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " private AncestorImpl() {}",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " private LeafImpl() {}",
+ // even though DaggerAncestor.LeafImpl.getPrunedDependency() was
+ // ModifiableBindingType.MISSING, it doesn't need to be reimplemented because there was
+ // a base implementation
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void productionSubcomponentAndModifiableFrameworkInstance() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Response", "ResponseDependency");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProductionSubcomponent;",
+ "import java.util.Set;",
+ "",
+ "@ProductionSubcomponent(modules = ResponseProducerModule.class)",
+ "interface Leaf {",
+ " ListenableFuture<Set<Response>> responses();",
+ "",
+ " @ProductionSubcomponent.Builder",
+ " interface Builder {",
+ " Leaf build();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.ResponseProducerModule",
+ "package test;",
+ "",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class ResponseProducerModule {",
+ " @Produces",
+ " @IntoSet",
+ " static Response response(ResponseDependency responseDependency) {",
+ " return new Response();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.internal.CancellationListener;",
+ "import dagger.producers.internal.Producers;",
+ "import dagger.producers.internal.SetProducer;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import java.util.Set;",
+ "import java.util.concurrent.Executor;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf, CancellationListener {",
+ " private Producer<Set<Response>> responsesEntryPoint;",
+ " private Producer<Response> responseProducer;",
+ " private Producer<Set<Response>> setOfResponseProducer;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.responseProducer =",
+ " ResponseProducerModule_ResponseFactory.create(",
+ " getProductionImplementationExecutorProvider(),",
+ " getProductionComponentMonitorProvider(),",
+ " getResponseDependencyProducer());",
+ " this.setOfResponseProducer =",
+ " SetProducer.<Response>builder(1, 0)",
+ " .addProducer(responseProducer).build();",
+ " this.responsesEntryPoint =",
+ " Producers.entryPointViewOf(getSetOfResponseProducer(), this);",
+ " }",
+ "",
+ " @Override",
+ " public ListenableFuture<Set<Response>> responses() {",
+ " return responsesEntryPoint.get();",
+ " }",
+ "",
+ " protected abstract Provider<Executor>",
+ " getProductionImplementationExecutorProvider();",
+ "",
+ " protected abstract Provider<ProductionComponentMonitor>",
+ " getProductionComponentMonitorProvider();",
+ "",
+ " protected abstract Producer getResponseDependencyProducer();",
+ "",
+ " protected Producer getSetOfResponseProducer() {",
+ " return setOfResponseProducer;",
+ " }",
+ "",
+ " @Override",
+ " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
+ " Producers.cancel(getSetOfResponseProducer(), mayInterruptIfRunning);",
+ " Producers.cancel(responseProducer, mayInterruptIfRunning);",
+ " }",
+ "}");
+
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.ExecutorModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.MoreExecutors;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.Production;",
+ "import java.util.concurrent.Executor;",
+ "",
+ "@Module",
+ "final class ExecutorModule {",
+ " @Provides",
+ " @Production",
+ " static Executor executor() {",
+ " return MoreExecutors.directExecutor();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent(",
+ " modules = {",
+ " ExecutorModule.class,",
+ " ResponseDependencyProducerModule.class,",
+ " RootMultibindingModule.class,",
+ " })",
+ "interface Root {",
+ " Leaf.Builder leaf();",
+ "",
+ " @ProductionComponent.Builder",
+ " interface Builder {",
+ " Root build();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.ResponseDependencyProducerModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.Futures;",
+ "import com.google.common.util.concurrent.ListenableFuture;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class ResponseDependencyProducerModule {",
+ " @Produces",
+ " static ListenableFuture<ResponseDependency> responseDependency() {",
+ " return Futures.immediateFuture(new ResponseDependency());",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.RootMultibindingModule",
+ "package test;",
+ "",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "final class RootMultibindingModule {",
+ " @Produces",
+ " @IntoSet",
+ " static Response response() {",
+ " return new Response();",
+ " }",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.DoubleCheck;",
+ "import dagger.internal.InstanceFactory;",
+ "import dagger.internal.SetFactory;",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.internal.CancellationListener;",
+ "import dagger.producers.internal.DelegateProducer;",
+ "import dagger.producers.internal.Producers;",
+ "import dagger.producers.internal.SetProducer;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import java.util.Set;",
+ "import java.util.concurrent.Executor;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root, CancellationListener {",
+ " private Provider<Executor> productionImplementationExecutorProvider;",
+ " private Provider<Root> rootProvider;",
+ " private Provider<ProductionComponentMonitor> monitorProvider;",
+ " private Producer<ResponseDependency> responseDependencyProducer;",
+ " private Producer<Response> responseProducer;",
+ "",
+ " private DaggerRoot() {",
+ " initialize();",
+ " }",
+ "",
+ " public static Root.Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.productionImplementationExecutorProvider =",
+ " DoubleCheck.provider((Provider) ExecutorModule_ExecutorFactory.create());",
+ " this.rootProvider = InstanceFactory.create((Root) this);",
+ " this.monitorProvider =",
+ " DoubleCheck.provider(",
+ " Root_MonitoringModule_MonitorFactory.create(",
+ " rootProvider,",
+ " SetFactory.<ProductionComponentMonitor.Factory>empty()));",
+ " this.responseDependencyProducer =",
+ " ResponseDependencyProducerModule_ResponseDependencyFactory.create(",
+ " productionImplementationExecutorProvider, monitorProvider);",
+ " this.responseProducer =",
+ " RootMultibindingModule_ResponseFactory.create(",
+ " productionImplementationExecutorProvider, monitorProvider);",
+ " }",
+ "",
+ " @Override",
+ " public Leaf.Builder leaf() {",
+ " return new LeafBuilder();",
+ " }",
+ "",
+ " @Override",
+ " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
+ " Producers.cancel(responseProducer, mayInterruptIfRunning);",
+ " Producers.cancel(responseDependencyProducer, mayInterruptIfRunning);",
+ " }",
+ "",
+ " private static final class Builder implements Root.Builder {",
+ " @Override",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " private final class LeafBuilder implements Leaf.Builder {",
+ " @Override",
+ " public Leaf build() {",
+ " return new LeafImpl();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf implements CancellationListener {",
+ " private Producer<Set<Response>> setOfResponseProducer = new DelegateProducer<>();",
+ "",
+ " private LeafImpl() {",
+ " configureInitialization();",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " DelegateProducer.setDelegate(",
+ " setOfResponseProducer,",
+ " SetProducer.<Response>builder(1, 1)",
+ " .addCollectionProducer(super.getSetOfResponseProducer())",
+ " .addProducer(DaggerRoot.this.responseProducer)",
+ " .build());",
+ " }",
+ "",
+ " @Override",
+ " protected Provider<Executor> getProductionImplementationExecutorProvider() {",
+ " return DaggerRoot.this.productionImplementationExecutorProvider;",
+ " }",
+ "",
+ " @Override",
+ " protected Provider<ProductionComponentMonitor>",
+ " getProductionComponentMonitorProvider() {",
+ " return DaggerRoot.this.monitorProvider;",
+ " }",
+ "",
+ " @Override",
+ " protected Producer getResponseDependencyProducer() {",
+ " return DaggerRoot.this.responseDependencyProducer;",
+ " }",
+ "",
+ " @Override",
+ " protected Producer getSetOfResponseProducer() {",
+ " return setOfResponseProducer;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void lazyOfModifiableBinding() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import dagger.Subcomponent;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Lazy<MissingInLeaf> lazy();",
+ " Provider<Lazy<MissingInLeaf>> providerOfLazy();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.Lazy;",
+ "import dagger.internal.DoubleCheck;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.ProviderOfLazy;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Lazy<MissingInLeaf> lazy() {",
+ " return DoubleCheck.lazy(getMissingInLeafProvider());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<Lazy<MissingInLeaf>> providerOfLazy() {",
+ " return ProviderOfLazy.create(getMissingInLeafProvider());",
+ " }",
+ "",
+ " protected abstract Provider getMissingInLeafProvider();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class AncestorModule {",
+ " @Provides",
+ " static MissingInLeaf satisfiedInAncestor() { return new MissingInLeaf(); }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected final Provider getMissingInLeafProvider() {",
+ " return AncestorModule_SatisfiedInAncestorFactory.create();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void missingBindingAccessInLeafAndAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(
+ filesToCompile, "Missing", "DependsOnMissing", "ProvidedInAncestor_InducesSetBinding");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.Provides;",
+ "import javax.inject.Provider;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " static DependsOnMissing test(",
+ " Missing missing,",
+ " Provider<Missing> missingProvider,",
+ " ProvidedInAncestor_InducesSetBinding missingInLeaf) {",
+ " return new DependsOnMissing();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static Object unresolvedSetBinding(",
+ " Missing missing, Provider<Missing> missingProvider) {",
+ " return new Object();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " DependsOnMissing instance();",
+ " Provider<DependsOnMissing> frameworkInstance();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private Provider<DependsOnMissing> testProvider;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.testProvider =",
+ " LeafModule_TestFactory.create(",
+ " getMissingProvider(), getProvidedInAncestor_InducesSetBindingProvider());",
+ " }",
+ "",
+ " @Override",
+ " public DependsOnMissing instance() {",
+ " return LeafModule_TestFactory.test(",
+ // TODO(b/117833324): remove these unnecessary casts
+ " (Missing) getMissing(),",
+ " getMissingProvider(),",
+ " (ProvidedInAncestor_InducesSetBinding)",
+ " getProvidedInAncestor_InducesSetBinding());",
+ " }",
+ "",
+ " @Override",
+ " public Provider<DependsOnMissing> frameworkInstance() {",
+ " return testProvider;",
+ " }",
+ "",
+ " protected abstract Object getMissing();",
+ " protected abstract Provider getMissingProvider();",
+ " protected abstract Object getProvidedInAncestor_InducesSetBinding();",
+ " protected abstract Provider getProvidedInAncestor_InducesSetBindingProvider();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "interface AncestorModule {",
+ " @Provides",
+ " static ProvidedInAncestor_InducesSetBinding providedInAncestor(",
+ " Set<Object> setThatInducesMissingBindingInChildSubclassImplementation) {",
+ " return new ProvidedInAncestor_InducesSetBinding();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static Object setContribution() {",
+ " return new Object();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.SetFactory;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private Provider<Object> unresolvedSetBindingProvider;",
+ " private Provider<Set<Object>> setOfObjectProvider;",
+ " private Provider<ProvidedInAncestor_InducesSetBinding> ",
+ " providedInAncestorProvider = ",
+ " new DelegateFactory<>();",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " @Override",
+ " protected void configureInitialization() {",
+ " super.configureInitialization();",
+ " initialize();",
+ " }",
+ "",
+ " private Object getUnresolvedSetBinding() {",
+ " return LeafModule_UnresolvedSetBindingFactory.unresolvedSetBinding(",
+ // TODO(b/117833324): remove this unnecessary cast
+ " (Missing) getMissing(), getMissingProvider());",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.unresolvedSetBindingProvider =",
+ " LeafModule_UnresolvedSetBindingFactory.create(getMissingProvider());",
+ " this.setOfObjectProvider =",
+ " SetFactory.<Object>builder(2, 0)",
+ " .addProvider(AncestorModule_SetContributionFactory.create())",
+ " .addProvider(unresolvedSetBindingProvider)",
+ " .build();",
+ " DelegateFactory.setDelegate(",
+ " providedInAncestorProvider,",
+ " AncestorModule_ProvidedInAncestorFactory.create(getSetOfObjectProvider()));",
+ " }",
+ "",
+ " protected Set<Object> getSetOfObject() {",
+ " return ImmutableSet.<Object>of(",
+ " AncestorModule_SetContributionFactory.setContribution(),",
+ " getUnresolvedSetBinding());",
+ " }",
+ "",
+ " @Override",
+ " protected final Object getProvidedInAncestor_InducesSetBinding() {",
+ " return AncestorModule_ProvidedInAncestorFactory.providedInAncestor(",
+ " getSetOfObject());",
+ " }",
+ "",
+ " protected Provider<Set<Object>> getSetOfObjectProvider() {",
+ " return setOfObjectProvider;",
+ " }",
+ "",
+ " @Override",
+ " protected final Provider getProvidedInAncestor_InducesSetBindingProvider() {",
+ " return providedInAncestorProvider;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void subcomponentBuilders() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "InducesDependenciesOnBuilderFields");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " private final Object object;",
+ "",
+ " LeafModule(Object object) {",
+ " this.object = object;",
+ " }",
+ "",
+ " @Provides",
+ " Object fromModule() {",
+ " return object;",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.MultibindingsModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Module;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "interface MultibindingsModule {",
+ " @Binds",
+ " @IntoSet",
+ " String string(String string);",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Subcomponent;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent(modules = {LeafModule.class, MultibindingsModule.class})",
+ "interface Leaf {",
+ " int bindsInstance();",
+ " Object fromModule();",
+ " InducesDependenciesOnBuilderFields inducesDependenciesOnBuilderFields();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " @BindsInstance Builder bindsInstance(int boundInstance);",
+ " @BindsInstance Builder inducedInSubclass(String induced);",
+ " Builder module(LeafModule module);",
+ "",
+ " Leaf build();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private Integer bindsInstance;",
+ " private LeafModule leafModule;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization(",
+ " LeafModule leafModuleParam, Integer bindsInstanceParam) {",
+ " this.bindsInstance = bindsInstanceParam;",
+ " this.leafModule = leafModuleParam;",
+ " }",
+ "",
+ " @Override",
+ " public int bindsInstance() {",
+ " return bindsInstance;",
+ " }",
+ "",
+ " @Override",
+ " public Object fromModule() {",
+ " return LeafModule_FromModuleFactory.fromModule(leafModule());",
+ " }",
+ "",
+ " @Override",
+ " public abstract InducesDependenciesOnBuilderFields",
+ " inducesDependenciesOnBuilderFields();",
+ "",
+ " protected LeafModule leafModule() {",
+ " return leafModule;",
+ " }",
+ "",
+ " public abstract static class Builder implements Leaf.Builder {",
+ " protected Integer bindsInstance;",
+ " protected String inducedInSubclass;",
+ " protected LeafModule leafModule;",
+ "",
+ " @Override",
+ " public Builder bindsInstance(int boundInstance) {",
+ " this.bindsInstance = Preconditions.checkNotNull(boundInstance);",
+ " return this;",
+ " }",
+ "",
+ " @Override",
+ " public Builder inducedInSubclass(String induced) {",
+ " this.inducedInSubclass = Preconditions.checkNotNull(induced);",
+ " return this;",
+ " }",
+ "",
+ " @Override",
+ " public Builder module(LeafModule module) {",
+ " this.leafModule = Preconditions.checkNotNull(module);",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = MultibindingInducingModule.class)",
+ "interface Ancestor {",
+ " Leaf.Builder leaf();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.MultibindingInducingModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.multibindings.Multibinds;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "interface MultibindingInducingModule {",
+ " @Provides",
+ " static InducesDependenciesOnBuilderFields induce(",
+ " Set<String> multibindingWithBuilderFieldDeps) { ",
+ " return new InducesDependenciesOnBuilderFields();",
+ " }",
+ "",
+ " @Multibinds",
+ " Set<String> multibinding();",
+ "}"));
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " @Override",
+ " public abstract Leaf.Builder leaf();",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " private String inducedInSubclass;",
+ "",
+ " protected LeafImpl() {}",
+ "",
+ " protected void configureInitialization(",
+ " LeafModule leafModule,",
+ " Integer bindsInstance,",
+ " String inducedInSubclassParam) {",
+ " this.inducedInSubclass = inducedInSubclassParam;",
+ " configureInitialization(leafModule, bindsInstance);",
+ " }",
+ "",
+ " protected Set<String> getSetOfString() {",
+ " return ImmutableSet.<String>of(inducedInSubclass);",
+ " }",
+ "",
+ " @Override",
+ " public final InducesDependenciesOnBuilderFields",
+ " inducesDependenciesOnBuilderFields() {",
+ " return MultibindingInducingModule_InduceFactory.induce(getSetOfString());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Ancestor ancestor() {",
+ " return new AncestorImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " private AncestorImpl() {}",
+ "",
+ " @Override",
+ " public Leaf.Builder leaf() {",
+ " return new LeafBuilder();",
+ " }",
+ "",
+ " private final class LeafBuilder extends DaggerLeaf.Builder {",
+ " @Override",
+ " public Leaf build() {",
+ // TODO(b/117833324): Can we stick the validations into a method on the base class
+ // builder so that the contents of this method are just call to that and then new
+ // FooImpl? But repeated modules may make this more complicated, since those *should*
+ // be null
+ " Preconditions.checkBuilderRequirement(bindsInstance, Integer.class);",
+ " Preconditions.checkBuilderRequirement(inducedInSubclass, String.class);",
+ " Preconditions.checkBuilderRequirement(leafModule, LeafModule.class);",
+ " return new LeafImpl(leafModule, bindsInstance, inducedInSubclass);",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " private final LeafModule leafModule;",
+ "",
+ " private LeafImpl(",
+ " LeafModule leafModuleParam,",
+ " Integer bindsInstance,",
+ " String inducedInSubclass) {",
+ " this.leafModule = leafModuleParam;",
+ " configureInitialization(leafModuleParam, bindsInstance, inducedInSubclass);",
+ " }",
+ "",
+ " @Override",
+ " protected LeafModule leafModule() {",
+ " return leafModule;",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void subcomponentBuilders_moduleWithUnusedInstanceBindings() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Used", "Unused");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.ModuleWithUsedBinding",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ModuleWithUsedBinding {",
+ " @Provides",
+ " Used used() {",
+ " return new Used();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.ModuleWithUnusedBinding",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class ModuleWithUnusedBinding {",
+ " @Provides",
+ " Unused unused() {",
+ " return new Unused();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = {ModuleWithUsedBinding.class, ModuleWithUnusedBinding.class})",
+ "interface Leaf {",
+ " Used used();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " Builder setUsed(ModuleWithUsedBinding module);",
+ " Builder setUnused(ModuleWithUnusedBinding module);",
+ " Leaf build();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private ModuleWithUsedBinding moduleWithUsedBinding;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization(",
+ " ModuleWithUsedBinding moduleWithUsedBindingParam) {",
+ " this.moduleWithUsedBinding = moduleWithUsedBindingParam;",
+ " }",
+ "",
+ " @Override",
+ " public Used used() {",
+ " return ModuleWithUsedBinding_UsedFactory.used(",
+ " moduleWithUsedBinding());",
+ " }",
+ "",
+ " protected ModuleWithUsedBinding moduleWithUsedBinding() {",
+ " return moduleWithUsedBinding;",
+ " }",
+ "",
+ " public abstract static class Builder implements Leaf.Builder {",
+ " protected ModuleWithUsedBinding moduleWithUsedBinding;",
+ " protected ModuleWithUnusedBinding moduleWithUnusedBinding;",
+ "",
+ " @Override",
+ " public Builder setUsed(ModuleWithUsedBinding module) {",
+ " this.moduleWithUsedBinding = Preconditions.checkNotNull(module);",
+ " return this;",
+ " }",
+ "",
+ " @Override",
+ " public Builder setUnused(ModuleWithUnusedBinding module) {",
+ " this.moduleWithUnusedBinding = Preconditions.checkNotNull(module);",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " Leaf.Builder leaf();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf.Builder leaf() {",
+ " return new LeafBuilder();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " private final class LeafBuilder extends DaggerLeaf.Builder {",
+ " @Override",
+ " public Leaf build() {",
+ " if (moduleWithUsedBinding == null) {",
+ " this.moduleWithUsedBinding = new ModuleWithUsedBinding();",
+ " }",
+ // ModuleWithUnusedBinding is not verified since it's not used
+ " return new LeafImpl(moduleWithUsedBinding);",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private final ModuleWithUsedBinding moduleWithUsedBinding;",
+ "",
+ " private LeafImpl(ModuleWithUsedBinding moduleWithUsedBindingParam) {",
+ " this.moduleWithUsedBinding = moduleWithUsedBindingParam;",
+ " configureInitialization(moduleWithUsedBindingParam);",
+ " }",
+ "",
+ " @Override",
+ " protected ModuleWithUsedBinding moduleWithUsedBinding() {",
+ " return moduleWithUsedBinding;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void subcomponentBuilders_repeatedModule() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RepeatedModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class RepeatedModule {",
+ " @Provides",
+ " int i() {",
+ " return 1;",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = RepeatedModule.class)",
+ "interface Leaf {",
+ " int i();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " Builder repeatedModule(RepeatedModule repeatedModule);",
+ " Leaf build();",
+ " }",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private RepeatedModule repeatedModule;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization(RepeatedModule repeatedModuleParam) {",
+ " this.repeatedModule = repeatedModuleParam;",
+ " }",
+ "",
+ " @Override",
+ " public int i() {",
+ " return repeatedModule().i();",
+ " }",
+ "",
+ " protected RepeatedModule repeatedModule() {",
+ " return repeatedModule;",
+ " }",
+ "",
+ " public abstract static class Builder implements Leaf.Builder {",
+ " protected RepeatedModule repeatedModule;",
+ "",
+ " @Override",
+ " public Builder repeatedModule(RepeatedModule repeatedModule) {",
+ " this.repeatedModule = Preconditions.checkNotNull(repeatedModule);",
+ " return this;",
+ " }",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RepeatedModule.class)",
+ "interface Root {",
+ " Leaf.Builder leaf();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private final RepeatedModule repeatedModule;",
+ "",
+ " private DaggerRoot(RepeatedModule repeatedModuleParam) {",
+ " this.repeatedModule = repeatedModuleParam;",
+ " }",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf.Builder leaf() {",
+ " return new LeafBuilder();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private RepeatedModule repeatedModule;",
+ "",
+ " private Builder() {}",
+ "",
+ " public Builder repeatedModule(RepeatedModule repeatedModule) {",
+ " this.repeatedModule = Preconditions.checkNotNull(repeatedModule);",
+ " return this;",
+ " }",
+ "",
+ " public Root build() {",
+ " if (repeatedModule == null) {",
+ " this.repeatedModule = new RepeatedModule();",
+ " }",
+ " return new DaggerRoot(repeatedModule);",
+ " }",
+ " }",
+ "",
+ " private final class LeafBuilder extends DaggerLeaf.Builder {",
+ " @Override",
+ " public LeafBuilder repeatedModule(RepeatedModule repeatedModule) {",
+ " throw new UnsupportedOperationException(",
+ " String.format(",
+ " \"%s cannot be set because it is inherited from the enclosing component\",",
+ " RepeatedModule.class.getCanonicalName()));",
+ " }",
+ "",
+ " @Override",
+ " public Leaf build() {",
+ " return new LeafImpl();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private LeafImpl() {",
+ " configureInitialization(null);",
+ " }",
+ "",
+ " @Override",
+ " protected RepeatedModule repeatedModule() {",
+ " return DaggerRoot.this.repeatedModule;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void bindsWithMissingDependency() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Binds;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Binds Object missingBindsDependency(MissingInLeaf missing);",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Object bindsWithMissingDependencyInLeaf();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract Object bindsWithMissingDependencyInLeaf();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.MissingInLeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface MissingInLeafModule {",
+ " @Provides",
+ " static MissingInLeaf boundInRoot() {",
+ " return new MissingInLeaf();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = MissingInLeafModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private LeafImpl() {}",
+ "",
+ " @Override",
+ " public Object bindsWithMissingDependencyInLeaf() {",
+ " return MissingInLeafModule_BoundInRootFactory.boundInRoot();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void bindsWithMissingDependency_pruned() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "MissingInLeaf");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Binds;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Binds Object missingBindsDependency(MissingInLeaf missing);",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.DependsOnBindsWithMissingDep",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class DependsOnBindsWithMissingDep {",
+ " @Inject DependsOnBindsWithMissingDep(Object bindsWithMissingDep) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " DependsOnBindsWithMissingDep DependsOnBindsWithMissingDep();",
+ "}"));
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public DependsOnBindsWithMissingDep DependsOnBindsWithMissingDep() {",
+ " return new DependsOnBindsWithMissingDep(getObject());",
+ " }",
+ "",
+ " protected abstract Object getObject();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.PrunesInjectConstructorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface PrunesInjectConstructorModule {",
+ " @Provides",
+ " static DependsOnBindsWithMissingDep pruneInjectConstructor() {",
+ " return new DependsOnBindsWithMissingDep(new Object());",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = PrunesInjectConstructorModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private LeafImpl() {}",
+ "",
+ " @Override",
+ " protected Object getObject() {",
+ " " + PRUNED_METHOD_BODY,
+ " }",
+ "",
+ " @Override",
+ " public DependsOnBindsWithMissingDep DependsOnBindsWithMissingDep() {",
+ " return PrunesInjectConstructorModule_PruneInjectConstructorFactory",
+ " .pruneInjectConstructor();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void modifiedProducerFromProvider() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "DependsOnModifiedProducerFromProvider");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.Provides;",
+ "import java.util.Set;",
+ "",
+ "@ProducerModule",
+ "interface LeafModule {",
+ " @Produces",
+ " static DependsOnModifiedProducerFromProvider dependsOnModified(Set<String> set) {",
+ " return new DependsOnModifiedProducerFromProvider();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.ProductionSubcomponent;",
+ "import java.util.Set;",
+ "",
+ "@ProductionSubcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Producer<DependsOnModifiedProducerFromProvider>",
+ " dependsOnModifiedProducerFromProvider();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.internal.CancellationListener;",
+ "import dagger.producers.internal.Producers;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import java.util.Set;",
+ "import java.util.concurrent.Executor;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf, CancellationListener {",
+ " private Producer<DependsOnModifiedProducerFromProvider>",
+ " dependsOnModifiedProducerFromProviderEntryPoint;",
+ " private Producer<DependsOnModifiedProducerFromProvider> dependsOnModifiedProducer;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.dependsOnModifiedProducer =",
+ " LeafModule_DependsOnModifiedFactory.create(",
+ " getProductionImplementationExecutorProvider(),",
+ " getProductionComponentMonitorProvider(),",
+ " getSetOfStringProducer());",
+ " this.dependsOnModifiedProducerFromProviderEntryPoint =",
+ " Producers.entryPointViewOf(dependsOnModifiedProducer, this);",
+ " }",
+ "",
+ " @Override",
+ " public Producer<DependsOnModifiedProducerFromProvider> ",
+ " dependsOnModifiedProducerFromProvider() {",
+ " return dependsOnModifiedProducerFromProviderEntryPoint;",
+ " }",
+ "",
+ " protected abstract Provider<Executor> ",
+ " getProductionImplementationExecutorProvider();",
+ "",
+ " protected abstract Provider<ProductionComponentMonitor>",
+ " getProductionComponentMonitorProvider();",
+ "",
+ " protected abstract Producer<Set<String>> getSetOfStringProducer();",
+ "",
+ " @Override",
+ " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
+ " Producers.cancel(dependsOnModifiedProducer, mayInterruptIfRunning);",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import dagger.multibindings.IntoSet;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.producers.Production;",
+ "import java.util.Set;",
+ "import java.util.concurrent.Executor;",
+ "",
+ "@Module",
+ "interface RootModule {",
+ " @Provides",
+ " @IntoSet",
+ " static String induceModificationInLeaf() {",
+ " return new String();",
+ " }",
+ "",
+ " @Provides",
+ " @Production",
+ " static Executor productionExecutor() {",
+ " return null;",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.DoubleCheck;",
+ "import dagger.internal.InstanceFactory;",
+ "import dagger.internal.SetFactory;",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.internal.CancellationListener;",
+ "import dagger.producers.internal.DelegateProducer;",
+ "import dagger.producers.internal.Producers;",
+ "import dagger.producers.monitoring.ProductionComponentMonitor;",
+ "import java.util.Set;",
+ "import java.util.concurrent.Executor;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private DaggerRoot() {}",
+ "",
+ " public static Builder builder() {",
+ " return new Builder();",
+ " }",
+ "",
+ " public static Root create() {",
+ " return new Builder().build();",
+ " }",
+ "",
+ " @Override",
+ " public Leaf leaf() {",
+ " return new LeafImpl();",
+ " }",
+ "",
+ " static final class Builder {",
+ " private Builder() {}",
+ "",
+ " public Root build() {",
+ " return new DaggerRoot();",
+ " }",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf implements CancellationListener {",
+ " private Provider<Executor> productionImplementationExecutorProvider =",
+ " new DelegateFactory<>();",
+ " private Provider<Leaf> leafProvider;",
+ " private Provider<ProductionComponentMonitor> monitorProvider =",
+ " new DelegateFactory<>();",
+ " private Provider<Set<String>> setOfStringProvider;",
+ " private Producer<Set<String>> setOfStringProducer = new DelegateProducer<>();",
+ "",
+ " private LeafImpl() {",
+ " configureInitialization();",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " DelegateFactory.setDelegate(",
+ " productionImplementationExecutorProvider,",
+ " DoubleCheck.provider(",
+ " (Provider) RootModule_ProductionExecutorFactory.create()));",
+ " this.leafProvider = InstanceFactory.create((Leaf) this);",
+ " DelegateFactory.setDelegate(",
+ " monitorProvider,",
+ " DoubleCheck.provider(",
+ " Leaf_MonitoringModule_MonitorFactory.create(",
+ " leafProvider,",
+ " getSetOfProductionComponentMonitorFactoryProvider())));",
+ " this.setOfStringProvider =",
+ " SetFactory.<String>builder(1, 0)",
+ " .addProvider(RootModule_InduceModificationInLeafFactory.create())",
+ " .build();",
+ " DelegateProducer.setDelegate(",
+ " setOfStringProducer,",
+ " Producers.producerFromProvider(getSetOfStringProvider()));",
+ " }",
+ "",
+ " @Override",
+ " protected Provider<Executor> getProductionImplementationExecutorProvider() {",
+ " return productionImplementationExecutorProvider;",
+ " }",
+ "",
+ " protected Provider<Set<ProductionComponentMonitor.Factory>> ",
+ " getSetOfProductionComponentMonitorFactoryProvider() {",
+ " return SetFactory.<ProductionComponentMonitor.Factory>empty();",
+ " }",
+ "",
+ " @Override",
+ " protected Provider<ProductionComponentMonitor> ",
+ " getProductionComponentMonitorProvider() {",
+ " return monitorProvider;",
+ " }",
+ "",
+ " protected Provider<Set<String>> getSetOfStringProvider() {",
+ " return setOfStringProvider;",
+ " }",
+ "",
+ " @Override",
+ " protected Producer<Set<String>> getSetOfStringProducer() {",
+ " return setOfStringProducer;",
+ " }",
+ "",
+ " @Override",
+ " public void onProducerFutureCancelled(boolean mayInterruptIfRunning) {",
+ " super.onProducerFutureCancelled(mayInterruptIfRunning);",
+ " Producers.cancel(getSetOfStringProducer(), mayInterruptIfRunning);",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .hasSourceEquivalentTo(generatedRoot);
+ }
+
+ @Test
+ public void modifiableBindingMethods_namesDedupedAcrossImplementations() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "foo.Thing",
+ "package foo;",
+ "", // force multi-line format
+ "public interface Thing extends CharSequence {}"),
+ JavaFileObjects.forSourceLines(
+ "bar.Thing",
+ "package bar;",
+ "", // force multi-line format
+ "public interface Thing extends Runnable {}"),
+ JavaFileObjects.forSourceLines(
+ "test.WillInduceSetOfRunnable",
+ "package test;",
+ "", // force multi-line format
+ "class WillInduceSetOfRunnable {}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Provides",
+ " static CharSequence depOnFooThing(foo.Thing thing) {",
+ " return thing.toString();",
+ " }",
+ "",
+ " @Provides",
+ " @IntoSet",
+ " static Runnable depOnBarThing(bar.Thing thing) {",
+ " return () -> {};",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " CharSequence inducesFoo();",
+ " WillInduceSetOfRunnable willInduceSetOfRunnable();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ "import foo.Thing;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public CharSequence inducesFoo() {",
+ " return LeafModule_DepOnFooThingFactory.depOnFooThing(getThing());",
+ " }",
+ "",
+ " @Override",
+ " public abstract WillInduceSetOfRunnable willInduceSetOfRunnable();",
+ "",
+ " protected abstract Thing getThing();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "interface AncestorModule {",
+ " @Provides",
+ " static WillInduceSetOfRunnable induce(Set<Runnable> set) {",
+ " return null;",
+ " }",
+ "",
+ " @Multibinds Set<Runnable> runnables();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " Leaf leaf();",
+ "}"));
+
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import bar.Thing;",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class LeafImpl extends DaggerLeaf {",
+ " protected LeafImpl() {}",
+ "",
+ " private Runnable getDepOnBarThing() {",
+ " return LeafModule_DepOnBarThingFactory.depOnBarThing(getThing2());",
+ " }",
+ "",
+ " protected abstract Thing getThing2();",
+ "",
+ " protected Set<Runnable> getSetOfRunnable() {",
+ " return ImmutableSet.<Runnable>of(getDepOnBarThing());",
+ " }",
+ "",
+ " @Override",
+ " public final WillInduceSetOfRunnable willInduceSetOfRunnable() {",
+ " return AncestorModule_InduceFactory.induce(getSetOfRunnable());",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ /**
+ * This test verifies that Dagger can find the appropriate child subcomponent
+ * super-implementation, even if it is not enclosed in the current component's
+ * super-implementation. This can happen if a subcomponent is installed with a module's {@code
+ * subcomponents} attribute, but the binding is not accessed in a super-implementation. To exhibit
+ * this, we use multibindings that reference the pruned subcomponent, but make the multibinding
+ * also unresolved in the base implementation. An ancestor component defines a binding that
+ * depends on the multibinding, which induces the previously unresolved multibinding
+ * contributions, which itself induces the previously unresolved subcomponent.
+ */
+ @Test
+ public void subcomponentInducedFromAncestor() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Inducer");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.InducedSubcomponent",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface InducedSubcomponent {",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " InducedSubcomponent build();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.MaybeLeaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = InducedSubcomponentModule.class)",
+ "interface MaybeLeaf {",
+ " Inducer inducer();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.MaybeLeaf",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.IntoSet;",
+ "",
+ "@Module(subcomponents = InducedSubcomponent.class)",
+ "interface InducedSubcomponentModule {",
+ " @Provides",
+ " @IntoSet",
+ " static Object inducedSet(InducedSubcomponent.Builder builder) {",
+ " return new Object();",
+ " }",
+ "}"));
+
+ JavaFileObject generatedMaybeLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerMaybeLeaf implements MaybeLeaf {",
+ " protected DaggerMaybeLeaf() {}",
+ "",
+ " @Override",
+ " public abstract Inducer inducer();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerMaybeLeaf")
+ .hasSourceEquivalentTo(generatedMaybeLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import dagger.multibindings.Multibinds;",
+ "import java.util.Set;",
+ "",
+ "@Module",
+ "interface AncestorModule {",
+ " @Provides",
+ " static Inducer inducer(Set<Object> set) {",
+ " return null;",
+ " }",
+ "",
+ " @Multibinds Set<Object> set();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = AncestorModule.class)",
+ "interface Ancestor {",
+ " MaybeLeaf noLongerLeaf();",
+ "}"));
+
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ "import com.google.common.collect.ImmutableSet;",
+ "import dagger.internal.GenerationOptions;",
+ "import java.util.Set;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected DaggerAncestor() {}",
+ "",
+ " protected abstract class MaybeLeafImpl extends DaggerMaybeLeaf {",
+ " protected MaybeLeafImpl() {}",
+ "",
+ " private Object getInducedSet() {",
+ " return InducedSubcomponentModule_InducedSetFactory.inducedSet(",
+ // TODO(b/117833324): remove this unnecessary cast
+ " (InducedSubcomponent.Builder) getInducedSubcomponentBuilder());",
+ " }",
+ "",
+ " protected abstract Object getInducedSubcomponentBuilder();",
+ "",
+ " protected Set<Object> getSetOfObject() {",
+ " return ImmutableSet.<Object>of(getInducedSet());",
+ " }",
+ "",
+ " @Override",
+ " public final Inducer inducer() {",
+ " return AncestorModule_InducerFactory.inducer(getSetOfObject());",
+ " }",
+ "",
+ " protected abstract class InducedSubcomponentImpl extends",
+ " DaggerInducedSubcomponent {",
+ // ^ Note that this is DaggerInducedSubcomponent, not
+ // DaggerMaybeLeaf.InducedSubcomponentImpl
+ " protected InducedSubcomponentImpl() {}",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .hasSourceEquivalentTo(generatedAncestor);
+ }
+
+ @Test
+ public void rootScopedAtInjectConstructor_effectivelyMissingInSubcomponent() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "ProvidesMethodRootScoped");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RootScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope",
+ "public @interface RootScope {}"),
+ JavaFileObjects.forSourceLines(
+ "test.AtInjectRootScoped",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "@RootScope",
+ "class AtInjectRootScoped {",
+ " @Inject AtInjectRootScoped() {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " AtInjectRootScoped shouldBeEffectivelyMissingInLeaf();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public abstract AtInjectRootScoped shouldBeEffectivelyMissingInLeaf();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@RootScope",
+ "@Component",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " @Override",
+ " public AtInjectRootScoped shouldBeEffectivelyMissingInLeaf() {",
+ " return DaggerRoot.this.atInjectRootScopedProvider.get();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .containsElementsIn(generatedRoot);
+ }
+
+ @Test
+ public void prunedModuleWithInstanceState() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Pruned");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Modified",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Modified {",
+ " @Inject Modified(Pruned pruned) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class LeafModule {",
+ " @Provides",
+ " Pruned pruned() {",
+ " return new Pruned();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Modified modified();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected DaggerLeaf() {}",
+ "",
+ " @Override",
+ " public Modified modified() {",
+ " return new Modified(LeafModule_PrunedFactory.pruned(leafModule()));",
+ " }",
+ "",
+ " protected abstract LeafModule leafModule();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "class RootModule {",
+ " @Provides",
+ " static Modified modified() {",
+ " return new Modified(null);",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ IMPORT_GENERATED_ANNOTATION,
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " @Override",
+ " public Modified modified() {",
+ " return RootModule_ModifiedFactory.modified();",
+ " }",
+ "",
+ " @Override",
+ " protected LeafModule leafModule() {",
+ " return null;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .containsElementsIn(generatedRoot);
+ }
+
+ @Test
+ public void modifiableCycles() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class A {",
+ " @Inject A(B b) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.B",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "class B {",
+ " @Inject B(Provider<A> a) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Provider<A> frameworkInstanceCycle();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import dagger.internal.DelegateFactory;",
+ "import dagger.internal.GenerationOptions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private Provider<A> aProvider;",
+ " private Provider<B> bProvider;",
+ "",
+ " protected DaggerLeaf() {}",
+ "",
+ " protected void configureInitialization() {",
+ " initialize();",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.aProvider = new DelegateFactory<>();",
+ " this.bProvider = B_Factory.create(frameworkInstanceCycle());",
+ " DelegateFactory.setDelegate(aProvider, A_Factory.create(getBProvider()));",
+ " }",
+ "",
+ " @Override",
+ " public Provider<A> frameworkInstanceCycle() {",
+ " return aProvider;",
+ " }",
+ "",
+ " protected Provider getBProvider() {",
+ " return bProvider;",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .hasSourceEquivalentTo(generatedLeaf);
+ }
+
+ /**
+ * This tests a regression case where the component builder in the base implementation used one
+ * set of disambiguated names from all of the {@link ComponentDescriptor#requirements()}, and the
+ * final implementation used a different set of disambiguated names from the resolved {@link
+ * BindingGraph#componentRequirements()}. This resulted in generated output that didn't compile,
+ * as the builder implementation attempted to use the new names in validation, which didn't line
+ * up with the old names.
+ */
+ @Test
+ public void componentBuilderFields_consistencyAcrossImplementations() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "a.Mod",
+ "package a;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Named;",
+ "",
+ "@Module",
+ "public class Mod {",
+ " @Provides",
+ " @Named(\"a\")",
+ " int i() { return 0; }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "b.Mod",
+ "package b;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Named;",
+ "",
+ "@Module",
+ "public class Mod {",
+ " @Provides",
+ " @Named(\"b\")",
+ " int i() { return 0; }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "c.Mod",
+ "package c;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "import javax.inject.Named;",
+ "",
+ "@Module",
+ "public class Mod {",
+ " @Provides",
+ " @Named(\"c\")",
+ " int i() { return 0; }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.HasUnusedModuleLeaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "import javax.inject.Named;",
+ "",
+ "@Subcomponent(modules = {a.Mod.class, b.Mod.class, c.Mod.class})",
+ "interface HasUnusedModuleLeaf {",
+ " @Named(\"a\") int a();",
+ // b omitted intentionally
+ " @Named(\"c\") int c();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " Builder setAMod(a.Mod mod);",
+ " Builder setBMod(b.Mod mod);",
+ " Builder setCMod(c.Mod mod);",
+ " HasUnusedModuleLeaf build();",
+ " }",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import a.Mod;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerHasUnusedModuleLeaf implements HasUnusedModuleLeaf {",
+ " public abstract static class Builder implements HasUnusedModuleLeaf.Builder {",
+ " protected Mod mod;",
+ " protected b.Mod mod2;",
+ " protected c.Mod mod3;",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerHasUnusedModuleLeaf")
+ .containsElementsIn(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component",
+ "interface Root {",
+ " HasUnusedModuleLeaf.Builder leaf();",
+ "}"));
+
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ "import a.Mod;",
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " private final class HasUnusedModuleLeafBuilder",
+ " extends DaggerHasUnusedModuleLeaf.Builder {",
+ " @Override",
+ " public HasUnusedModuleLeaf build() {",
+ " if (mod == null) {",
+ " this.mod = new Mod();",
+ " }",
+ // Before this regression was fixed, `mod3` was instead `mod2`, since the `b.Mod` was
+ // pruned from the graph and did not need validation.
+ " if (mod3 == null) {",
+ " this.mod3 = new c.Mod();",
+ " }",
+ " return new HasUnusedModuleLeafImpl(mod, mod3);",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .containsElementsIn(generatedRoot);
+ }
+
+ @Test
+ public void dependencyExpressionCasting() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.PublicType",
+ "package test;",
+ "", //
+ "public class PublicType {}"),
+ JavaFileObjects.forSourceLines(
+ "test.ModifiableNonPublicSubclass",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class ModifiableNonPublicSubclass extends PublicType {",
+ " @Inject ModifiableNonPublicSubclass() {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Parameterized",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Parameterized<T extends PublicType> {",
+ " @Inject Parameterized(T t) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " Parameterized<ModifiableNonPublicSubclass> parameterizedWithNonPublicSubtype();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " @Override",
+ " public Parameterized<ModifiableNonPublicSubclass> ",
+ " parameterizedWithNonPublicSubtype() {",
+ " return Parameterized_Factory.newInstance(",
+ " (ModifiableNonPublicSubclass) getModifiableNonPublicSubclass());",
+ " }",
+ "",
+ " protected Object getModifiableNonPublicSubclass() {",
+ " return new ModifiableNonPublicSubclass();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .containsElementsIn(generatedLeaf);
+ }
+
+ @Test
+ public void multipleComponentMethodsForSameBindingRequest() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " String string1();",
+ " String string2();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " @Override",
+ " public final String string2() {",
+ " return string1();",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .containsElementsIn(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface RootModule {",
+ " @Provides",
+ " static String string() {",
+ " return new String();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " protected final class LeafImpl extends DaggerLeaf {",
+ " private LeafImpl() {}",
+ "",
+ " @Override",
+ " public String string1() {",
+ " return RootModule_StringFactory.string();",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .containsElementsIn(generatedRoot);
+ }
+
+ @Test
+ public void boundInstanceUsedOnlyInInitialize() {
+ JavaFileObject subcomponent =
+ JavaFileObjects.forSourceLines(
+ "test.Sub",
+ "package test;",
+ "",
+ "import dagger.BindsInstance;",
+ "import dagger.Subcomponent;",
+ "import javax.inject.Provider;",
+ "",
+ "@Subcomponent",
+ "interface Sub {",
+ " Provider<String> stringProvider();",
+ "",
+ " @Subcomponent.Builder",
+ " interface Builder {",
+ " @BindsInstance",
+ " Builder string(String string);",
+ " Sub build();",
+ " }",
+ "}");
+
+ JavaFileObject generated =
+ JavaFileObjects.forSourceLines(
+ "test.Sub",
+ "package test;",
+ "",
+ "import dagger.internal.InstanceFactory;",
+ "import dagger.internal.Preconditions;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerSub implements Sub {",
+ " private Provider<String> stringProvider;",
+ "",
+ " protected DaggerSub() {}",
+ "",
+ " protected void configureInitialization(String stringParam) {",
+ " initialize(stringParam);",
+ " }",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize(final String stringParam) {",
+ " this.stringProvider = InstanceFactory.create(stringParam);",
+ " }",
+ "",
+ " @Override",
+ " public Provider<String> stringProvider() {",
+ " return stringProvider;",
+ " }",
+ "}");
+
+ Compilation compilation = compile(ImmutableList.of(subcomponent));
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerSub")
+ .containsElementsIn(generated);
+ }
+
+ @Test
+ public void packagePrivate_derivedFromFrameworkInstance_ComponentMethod() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.PackagePrivate",
+ "package test;",
+ "",
+ "import dagger.Reusable;",
+ "import javax.inject.Inject;",
+ "",
+ "@Reusable", // Use @Reusable to force a framework field
+ "class PackagePrivate {",
+ " @Inject PackagePrivate() {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent",
+ "interface Leaf {",
+ " PackagePrivate packagePrivate();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " private Provider<PackagePrivate> packagePrivateProvider;",
+ "",
+ " @Override",
+ " public PackagePrivate packagePrivate() {",
+ " return (PackagePrivate) getPackagePrivateProvider().get();",
+ " }",
+ "",
+ " protected Provider getPackagePrivateProvider() {",
+ " return packagePrivateProvider;",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .containsElementsIn(generatedLeaf);
+ }
+
+ @Test
+ public void castModifiableMethodAccessedInFinalImplementation() {
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "PackagePrivate");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.PublicBaseType",
+ "package test;",
+ "", //
+ "public class PublicBaseType {}"),
+ JavaFileObjects.forSourceLines(
+ "test.PackagePrivateSubtype",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ // Force this to be a modifiable binding resolved in the ancestor even though the
+ // binding is requested in the leaf.
+ "@AncestorScope",
+ "class PackagePrivateSubtype extends PublicBaseType {",
+ " @Inject PackagePrivateSubtype() {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorScope",
+ "package test;",
+ "",
+ "import javax.inject.Scope;",
+ "",
+ "@Scope @interface AncestorScope {}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "interface LeafModule {",
+ " @Binds PublicBaseType publicBaseType(PackagePrivateSubtype subtype);",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.InjectsOptionalOfModifiable",
+ "package test;",
+ "",
+ "import java.util.Optional;",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectsOptionalOfModifiable {",
+ " @Inject InjectsOptionalOfModifiable(",
+ " Optional<PublicBaseType> optionalOfModifiable) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@Subcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " InjectsOptionalOfModifiable injectsOptionalOfModifiable();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf {",
+ " protected abstract Optional<PublicBaseType> getOptionalOfPublicBaseType();",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .containsElementsIn(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.InjectsPackagePrivateSubtype",
+ "package test;",
+ "",
+ "import java.util.Optional;",
+ "import javax.inject.Inject;",
+ "",
+ "class InjectsPackagePrivateSubtype {",
+ " @Inject InjectsPackagePrivateSubtype(",
+ // Force a modifiable binding method for PackagePrivateSubtype in Ancestor. The
+ // final Leaf implementation will refer to this method, but will need to cast it
+ // since the PackagePrivateSubtype is accessible from the current package, but the
+ // method returns Object
+ " PackagePrivateSubtype packagePrivateSubtype) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.AncestorModule",
+ "package test;",
+ "",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "interface AncestorModule {",
+ " @Provides",
+ " static PackagePrivateSubtype packagePrivateSubtype() {",
+ " return new PackagePrivateSubtype();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Ancestor",
+ "package test;",
+ "",
+ "import dagger.Subcomponent;",
+ "",
+ "@AncestorScope",
+ "@Subcomponent",
+ "interface Ancestor {",
+ " InjectsPackagePrivateSubtype injectsPackagePrivateSubtype();",
+ " Leaf leaf();",
+ "}"));
+
+ JavaFileObject generatedAncestor =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerAncestor",
+ "package test;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerAncestor implements Ancestor {",
+ " protected Object getPackagePrivateSubtype() {",
+ " return getPackagePrivateSubtypeProvider().get();",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerAncestor")
+ .containsElementsIn(generatedAncestor);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Module;",
+ "",
+ "@Module",
+ "interface RootModule {",
+ " @BindsOptionalOf",
+ " PublicBaseType optionalPublicBaseType();",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = RootModule.class)",
+ "interface Root {",
+ " Ancestor ancestor();",
+ "}"));
+
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root {",
+ " protected final class AncestorImpl extends DaggerAncestor {",
+ " protected final class LeafImpl extends DaggerAncestor.LeafImpl {",
+ " @Override",
+ " protected Optional<PublicBaseType> getOptionalOfPublicBaseType() {",
+ " return Optional.of(",
+ " (PublicBaseType) AncestorImpl.this.getPackagePrivateSubtype());",
+ " }",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .containsElementsIn(generatedRoot);
+ }
+
+ @Test
+ public void injectInLeaf_ProductionInRoot() {
+ // most of this is also covered in ProducesMethodShadowsInjectConstructorTest, but this test
+ // asserts that the correct PrunedConcreteBindingExpression is used
+ ImmutableList.Builder<JavaFileObject> filesToCompile = ImmutableList.builder();
+ createSimplePackagePrivateClasses(filesToCompile, "Dependency", "Missing");
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.Injected",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "class Injected {",
+ " @Inject Injected(Dependency dependency, Missing missing) {}",
+ "",
+ " Injected(Dependency dependency) {}",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.LeafModule",
+ "package test;",
+ "",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "",
+ "@ProducerModule",
+ "interface LeafModule {",
+ " @Produces",
+ " static Object dependsOnInjectReplacedWithProduces(Injected injected) {",
+ " return new Object();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Leaf",
+ "package test;",
+ "",
+ "import dagger.producers.Producer;",
+ "import dagger.producers.ProductionSubcomponent;",
+ "",
+ "@ProductionSubcomponent(modules = LeafModule.class)",
+ "interface Leaf {",
+ " Producer<Object> objectProducer();",
+ "}"));
+
+ JavaFileObject generatedLeaf =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerLeaf",
+ "package test;",
+ "",
+ GENERATION_OPTIONS_ANNOTATION,
+ GENERATED_ANNOTATION,
+ "public abstract class DaggerLeaf implements Leaf, CancellationListener {",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.injectedProvider = Injected_Factory.create(",
+ " getDependencyProvider(), getMissingProvider());",
+ " this.injectedProducer = Producers.producerFromProvider(getInjectedProvider());",
+ " this.dependsOnInjectReplacedWithProducesProducer =",
+ " LeafModule_DependsOnInjectReplacedWithProducesFactory.create(",
+ " getProductionImplementationExecutorProvider(),",
+ " getProductionComponentMonitorProvider(),",
+ " getInjectedProducer());",
+ " this.objectProducerEntryPoint =",
+ " Producers.entryPointViewOf(",
+ " dependsOnInjectReplacedWithProducesProducer, this);",
+ " }",
+ "",
+ " protected abstract Provider getDependencyProvider();",
+ " protected abstract Provider getMissingProvider();",
+ "",
+ " protected Provider getInjectedProvider() {",
+ " return injectedProvider;",
+ " }",
+ "",
+ " protected Producer getInjectedProducer() {",
+ " return injectedProducer;",
+ " }",
+ "}");
+ Compilation compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerLeaf")
+ .containsElementsIn(generatedLeaf);
+
+ filesToCompile.add(
+ JavaFileObjects.forSourceLines(
+ "test.RootModule",
+ "package test;",
+ "",
+ "import com.google.common.util.concurrent.MoreExecutors;",
+ "import dagger.Provides;",
+ "import dagger.producers.ProducerModule;",
+ "import dagger.producers.Produces;",
+ "import dagger.producers.Production;",
+ "import java.util.concurrent.Executor;",
+ "",
+ "@ProducerModule",
+ "interface RootModule {",
+ " @Produces",
+ " static Injected replaceInjectWithProduces(Dependency dependency) {",
+ " return new Injected(dependency);",
+ " }",
+ "",
+ " @Produces",
+ " static Dependency dependency() {",
+ " return new Dependency();",
+ " }",
+ "",
+ " @Provides",
+ " @Production",
+ " static Executor executor() {",
+ " return MoreExecutors.directExecutor();",
+ " }",
+ "}"),
+ JavaFileObjects.forSourceLines(
+ "test.Root",
+ "package test;",
+ "",
+ "import dagger.producers.ProductionComponent;",
+ "",
+ "@ProductionComponent(modules = RootModule.class)",
+ "interface Root {",
+ " Leaf leaf();",
+ "}"));
+
+ JavaFileObject generatedRoot =
+ JavaFileObjects.forSourceLines(
+ "test.DaggerRoot",
+ "package test;",
+ "",
+ GENERATED_ANNOTATION,
+ "final class DaggerRoot implements Root, CancellationListener {",
+ " private Producer<Dependency> dependencyProducer;",
+ " private Producer<Injected> replaceInjectWithProducesProducer;",
+ "",
+ " @SuppressWarnings(\"unchecked\")",
+ " private void initialize() {",
+ " this.productionImplementationExecutorProvider =",
+ " DoubleCheck.provider((Provider) RootModule_ExecutorFactory.create());",
+ " this.rootProvider = InstanceFactory.create((Root) this);",
+ " this.monitorProvider =",
+ " DoubleCheck.provider(",
+ " Root_MonitoringModule_MonitorFactory.create(",
+ " rootProvider,",
+ " SetFactory.<ProductionComponentMonitor.Factory>empty()));",
+ " this.dependencyProducer =",
+ " RootModule_DependencyFactory.create(",
+ " productionImplementationExecutorProvider, monitorProvider);",
+ " this.replaceInjectWithProducesProducer =",
+ " RootModule_ReplaceInjectWithProducesFactory.create(",
+ " productionImplementationExecutorProvider,",
+ " monitorProvider,",
+ " dependencyProducer);",
+ " }",
+ "",
+ " protected final class LeafImpl extends DaggerLeaf",
+ " implements CancellationListener {",
+ " @Override",
+ " protected Provider getDependencyProvider() {",
+ " return MissingBindingFactory.create();",
+ " }",
+ "",
+ " @Override",
+ " protected Provider getMissingProvider() {",
+ " return MissingBindingFactory.create();",
+ " }",
+ "",
+ " @Override",
+ " protected Producer getInjectedProducer() {",
+ " return DaggerRoot.this.replaceInjectWithProducesProducer;",
+ " }",
+ " }",
+ "}");
+ compilation = compile(filesToCompile.build());
+ assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation)
+ .generatedSourceFile("test.DaggerRoot")
+ .containsElementsIn(generatedRoot);
+ }
+
+ // TODO(ronshapiro): remove copies from AheadOfTimeSubcomponents*Test classes
+ private void createSimplePackagePrivateClasses(
+ ImmutableList.Builder<JavaFileObject> filesBuilder, String... ancillaryClasses) {
+ for (String className : ancillaryClasses) {
+ filesBuilder.add(
+ JavaFileObjects.forSourceLines(
+ String.format("test.%s", className),
+ "package test;",
+ "",
+ String.format("class %s { }", className)));
+ }
+ }
+
+ private static Compilation compile(Iterable<JavaFileObject> files, CompilerMode... modes) {
+ return compilerWithOptions(
+ ObjectArrays.concat(
+ new CompilerMode[] {AHEAD_OF_TIME_SUBCOMPONENTS_MODE}, modes, CompilerMode.class))
+ .compile(files);
+ }
+}
diff --git a/javatests/dagger/internal/codegen/AnnotationProtoConverterTest.java b/javatests/dagger/internal/codegen/AnnotationProtoConverterTest.java
new file mode 100644
index 0000000..fda5859
--- /dev/null
+++ b/javatests/dagger/internal/codegen/AnnotationProtoConverterTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.auto.common.AnnotationMirrors;
+import com.google.testing.compile.CompilationRule;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.lang.model.element.AnnotationMirror;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests {@link TypeProtoConverter}. */
+@RunWith(JUnit4.class)
+public class AnnotationProtoConverterTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private DaggerElements elements;
+ private DaggerTypes types;
+ private AnnotationProtoConverter annotationProtoConverter;
+
+ @Before
+ public void setUp() {
+ this.elements = new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
+ this.types = new DaggerTypes(compilationRule.getTypes(), elements);
+ this.annotationProtoConverter =
+ new AnnotationProtoConverter(new TypeProtoConverter(types, elements));
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface TestAnnotation {
+ byte b();
+ boolean bool();
+ short s();
+ char c();
+ int i();
+ long l();
+ double d();
+ float f();
+
+ String string();
+ RetentionPolicy enumValue();
+ Class<?> classValue();
+ HasDefaults[] nestedAnnotations();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface HasDefaults {
+ int value() default 2;
+ }
+
+ @TestAnnotation(
+ b = 1,
+ bool = true,
+ s = 2,
+ c = 'c',
+ i = 4,
+ l = 5,
+ d = 6.0d,
+ f = 7.0f,
+ string = "hello, world",
+ enumValue = RetentionPolicy.CLASS,
+ classValue = AnnotationProtoConverter.class,
+ nestedAnnotations = {@HasDefaults, @HasDefaults(8)})
+ static class TestSubject {}
+
+ @Test
+ public void conversion() {
+ AnnotationMirror actual =
+ getOnlyElement(elements.getTypeElement(TestSubject.class).getAnnotationMirrors());
+ AnnotationMirror translated =
+ annotationProtoConverter.fromProto(AnnotationProtoConverter.toProto(actual));
+ assertThat(AnnotationMirrors.equivalence().equivalent(actual, translated)).isTrue();
+ }
+}
diff --git a/javatests/dagger/internal/codegen/AssistedErrorsTest.java b/javatests/dagger/internal/codegen/AssistedErrorsTest.java
deleted file mode 100644
index bf61412..0000000
--- a/javatests/dagger/internal/codegen/AssistedErrorsTest.java
+++ /dev/null
@@ -1,104 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-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 AssistedErrorsTest {
- @Parameters(name = "{0}")
- public static ImmutableCollection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public AssistedErrorsTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void testAssistedNotWithAssistedInjectionConstructor() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "",
- "final class Foo {",
- " Foo(",
- " @Assisted String str",
- " ) {}",
- "",
- " void someMethod(",
- " @Assisted int i",
- " ) {}",
- "}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
- .hadErrorContaining(
- "@Assisted parameters can only be used within an @AssistedInject-annotated constructor")
- .inFile(foo)
- .onLine(7);
- assertThat(compilation)
- .hadErrorContaining(
- "@Assisted parameters can only be used within an @AssistedInject-annotated constructor")
- .inFile(foo)
- .onLine(11);
- }
-
- @Test
- public void testNestedFactoryNotStatic() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import javax.inject.Qualifier;",
- "",
- "class Foo {",
- " @Qualifier @interface FooQualifier {}",
- "",
- " @AssistedInject",
- " Foo(",
- " @FooQualifier @Assisted int i",
- " ) {}",
- "}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Qualifiers cannot be used with @Assisted parameters.")
- .inFile(foo)
- .onLine(12);
- }
-}
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java b/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
deleted file mode 100644
index 2bcfedc..0000000
--- a/javatests/dagger/internal/codegen/AssistedFactoryErrorsTest.java
+++ /dev/null
@@ -1,839 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-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 AssistedFactoryErrorsTest {
- @Parameters(name = "{0}")
- public static ImmutableCollection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public AssistedFactoryErrorsTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void testFactoryNotAbstract() {
- JavaFileObject factory =
- JavaFileObjects.forSourceLines(
- "test.Factory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory class Factory {}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(factory);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "The @AssistedFactory-annotated type must be either an abstract class or interface.");
- }
-
- @Test
- public void testNestedFactoryNotStatic() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted int i) {}",
- "",
- " @AssistedFactory",
- " abstract class Factory {",
- " abstract Foo create(int i);",
- " }",
- "}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Nested @AssistedFactory-annotated types must be static.");
- }
-
- @Test
- public void testFactoryMissingAbstractMethod() {
- JavaFileObject factory =
- JavaFileObjects.forSourceLines(
- "test.Factory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory interface Factory {}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(factory);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "The @AssistedFactory-annotated type is missing an abstract, non-default method whose"
- + " return type matches the assisted injection type.");
- }
-
- @Test
- public void testFactoryReturnsNonDeclaredType() {
- JavaFileObject noInject =
- JavaFileObjects.forSourceLines(
- "test.NoInject", "package test;", "", "final class NoInject {}");
- JavaFileObject noAssistedParam =
- JavaFileObjects.forSourceLines(
- "test.NoAssistedParam",
- "package test;",
- "",
- "import dagger.assisted.AssistedInject;",
- "",
- "final class NoAssistedParam {",
- " @AssistedInject NoAssistedParam() {}",
- "}");
- JavaFileObject factory =
- JavaFileObjects.forSourceLines(
- "test.Factory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface Factory<T> {",
- " int createInt();", // Fails return type not @AssistedInject
- "",
- " NoInject createNoInject();", // Fails return type not @AssistedInject
- "",
- " NoAssistedParam createNoAssistedParam();", // Succeeds
- "",
- " T createT();", // Fails return type not @AssistedInject
- "}");
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(factory, noInject, noAssistedParam);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(4);
-
- assertThat(compilation)
- .hadErrorContaining(
- "The @AssistedFactory-annotated type should contain a single abstract, non-default "
- + "method but found multiple: ["
- + "createInt(), createNoInject(), createNoAssistedParam(), createT()]")
- .inFile(factory)
- .onLine(6);
-
- assertThat(compilation)
- .hadErrorContaining(
- "Invalid return type: int. "
- + "An assisted factory's abstract method must return a type with an "
- + "@AssistedInject-annotated constructor.")
- .inFile(factory)
- .onLine(7);
-
- assertThat(compilation)
- .hadErrorContaining(
- "Invalid return type: test.NoInject. "
- + "An assisted factory's abstract method must return a type with an "
- + "@AssistedInject-annotated constructor.")
- .inFile(factory)
- .onLine(9);
-
- assertThat(compilation)
- .hadErrorContaining(
- "Invalid return type: T. "
- + "An assisted factory's abstract method must return a type with an "
- + "@AssistedInject-annotated constructor.")
- .inFile(factory)
- .onLine(13);
- }
-
- @Test
- public void testFactoryMultipleAbstractMethods() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted int i) {}",
- "}");
-
- JavaFileObject fooFactoryInterface =
- JavaFileObjects.forSourceLines(
- "test.FooFactoryInterface",
- "package test;",
- "",
- "interface FooFactoryInterface {",
- " Foo createFoo1(int i);",
- "}");
-
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface FooFactory extends FooFactoryInterface {",
- " Foo createFoo2(int i);",
- "",
- " Foo createFoo3(int i);",
- "}");
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, fooFactory, fooFactoryInterface);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "The @AssistedFactory-annotated type should contain a single abstract, non-default "
- + "method but found multiple: [createFoo1(int), createFoo2(int), createFoo3(int)]");
- }
-
- @Test
- public void testFactoryMismatchingParameter() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted int i) {}",
- "}");
-
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface FooFactory {",
- " Foo create(String i);",
- "}");
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, fooFactory);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "The parameters in the factory method must match the @Assisted parameters in "
- + "test.Foo.\n"
- + " Actual: test.FooFactory#create(java.lang.String)\n"
- + " Expected: test.FooFactory#create(int)");
- }
-
- @Test
- public void testFactoryMismatchingGenericParameter() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo<T> {",
- " @AssistedInject Foo(@Assisted T t) {}",
- "}");
-
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface FooFactory<T> {",
- " Foo<T> create(String str);",
- "}");
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, fooFactory);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "The parameters in the factory method must match the @Assisted parameters in "
- + "test.Foo<T>.\n"
- + " Actual: test.FooFactory#create(java.lang.String)\n"
- + " Expected: test.FooFactory#create(T)");
- }
-
- @Test
- public void testFactoryDuplicateGenericParameter() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo<T> {",
- " @AssistedInject Foo(@Assisted String str, @Assisted T t) {}",
- "}");
-
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface FooFactory {",
- " Foo<String> create(String str1, String str2);",
- "}");
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, fooFactory);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@AssistedFactory method has duplicate @Assisted types: @Assisted java.lang.String");
- }
-
- @Test
- public void testAssistedInjectionRequest() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted String str) {}",
- "}");
-
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class Bar {",
- " @Inject",
- " Bar(Foo foo, Provider<Foo> fooProvider) {}",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.FooModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Provider;",
- "",
- "@Module",
- "class FooModule {",
- " @Provides",
- " static int provideInt(Foo foo, Provider<Foo> fooProvider) {",
- " return 0;",
- " }",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "",
- "@Component",
- "interface FooComponent {",
- " Foo foo();",
- "",
- " Provider<Foo> fooProvider();",
- "}");
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, module, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(6);
-
- String fooError =
- "Dagger does not support injecting @AssistedInject type, test.Foo. "
- + "Did you mean to inject its assisted factory type instead?";
- assertThat(compilation).hadErrorContaining(fooError).inFile(bar).onLine(8);
- assertThat(compilation).hadErrorContaining(fooError).inFile(module).onLine(10);
- assertThat(compilation).hadErrorContaining(fooError).inFile(component).onLine(8);
-
- String fooProviderError =
- "Dagger does not support injecting @AssistedInject type, javax.inject.Provider<test.Foo>. "
- + "Did you mean to inject its assisted factory type instead?";
- assertThat(compilation).hadErrorContaining(fooProviderError).inFile(bar).onLine(8);
- assertThat(compilation).hadErrorContaining(fooProviderError).inFile(module).onLine(10);
- assertThat(compilation).hadErrorContaining(fooProviderError).inFile(component).onLine(10);
- }
-
- @Test
- public void testProvidesAssistedBindings() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted int i) {}",
- "",
- " @AssistedFactory",
- " interface Factory {",
- " Foo create(int i);",
- " }",
- "}");
-
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.FooModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Provider;",
- "",
- "@Module",
- "class FooModule {",
- " @Provides",
- " static Foo provideFoo() {",
- " return null;",
- " }",
- "",
- " @Provides",
- " static Foo.Factory provideFooFactory() {",
- " return null;",
- " }",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo, module);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
- .hadErrorContaining("[test.Foo] Dagger does not support providing @AssistedInject types.")
- .inFile(module)
- .onLine(10);
- assertThat(compilation)
- .hadErrorContaining(
- "[test.Foo.Factory] Dagger does not support providing @AssistedFactory types.")
- .inFile(module)
- .onLine(15);
- }
-
- @Test
- public void testProvidesAssistedBindingsAsFactoryBindsInstance() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted int i) {}",
- "",
- " @AssistedFactory",
- " interface Factory {",
- " Foo create(int i);",
- " }",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.BindsInstance;",
- "",
- "@Component",
- "interface FooComponent {",
- " @Component.Factory",
- " interface Factory {",
- " FooComponent create(",
- " @BindsInstance Foo foo,",
- " @BindsInstance Foo.Factory fooFactory);",
- " }",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
- .hadErrorContaining("[test.Foo] Dagger does not support providing @AssistedInject types.")
- .inFile(component)
- .onLine(11);
- assertThat(compilation)
- .hadErrorContaining(
- "[test.Foo.Factory] Dagger does not support providing @AssistedFactory types.")
- .inFile(component)
- .onLine(12);
- }
-
- @Test
- public void testProvidesAssistedBindingsAsBuilderBindsInstance() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted int i) {}",
- "",
- " @AssistedFactory",
- " interface Factory {",
- " Foo create(int i);",
- " }",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.BindsInstance;",
- "",
- "@Component",
- "interface FooComponent {",
- " @Component.Builder",
- " interface Builder {",
- " @BindsInstance Builder foo(Foo foo);",
- " @BindsInstance Builder fooFactory(Foo.Factory fooFactory);",
- " FooComponent build();",
- " }",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
- .hadErrorContaining("[test.Foo] Dagger does not support providing @AssistedInject types.")
- .inFile(component)
- .onLine(10);
- assertThat(compilation)
- .hadErrorContaining(
- "[test.Foo.Factory] Dagger does not support providing @AssistedFactory types.")
- .inFile(component)
- .onLine(11);
- }
-
- @Test
- public void testInjectsProviderOfAssistedFactory() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "",
- "class Foo {",
- " @AssistedInject Foo(@Assisted int i) {}",
- "",
- " @AssistedFactory",
- " interface Factory {",
- " Foo create(int i);",
- " }",
- "}");
-
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "",
- "class Bar {",
- " @Inject",
- " Bar(Foo.Factory fooFactory, Provider<Foo.Factory> fooFactoryProvider) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo, bar);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Dagger does not support injecting Provider<T>, Lazy<T>, Producer<T>, or Produced<T> "
- + "when T is an @AssistedFactory-annotated type such as test.Foo.Factory")
- .inFile(bar)
- .onLine(8);
- }
-
- @Test
- public void testScopedAssistedInjection() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted int i) {}",
- "",
- " @AssistedFactory",
- " interface Factory {",
- " Foo create(int i);",
- " }",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("A type with an @AssistedInject-annotated constructor cannot be scoped")
- .inFile(foo)
- .onLine(8);
- }
-
- @Test
- public void testMultipleInjectAnnotations() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject",
- " @AssistedInject",
- " Foo(@Assisted int i) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "Constructors cannot be annotated with both @Inject and @AssistedInject");
- }
-
- @Test
- public void testAssistedInjectNotOnConstructor() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject",
- " void someMethod() {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
-
- // Note: this isn't actually a Dagger error, it's a javac error since @AssistedInject only
- // targets constructors. However, it's good to have this test in case that ever changes.
- assertThat(compilation)
- .hadErrorContaining("annotation type not applicable to this kind of declaration")
- .inFile(foo)
- .onLine(6);
- }
-
- @Test
- public void testAssistedInjectWithNoAssistedParametersIsNotInjectable() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject",
- " Foo(Bar bar) {}",
- "}");
-
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import dagger.assisted.AssistedInject;",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @AssistedInject",
- " Bar() {}",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface FooComponent {",
- " Foo foo();",
- "}");
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, component);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
- .hadErrorContaining(
- "Dagger does not support injecting @AssistedInject type, test.Bar. "
- + "Did you mean to inject its assisted factory type instead?")
- .inFile(foo)
- .onLine(7);
- assertThat(compilation)
- .hadErrorContaining(
- "\033[1;31m[Dagger/MissingBinding]\033[0m "
- + "Foo cannot be provided without an @Inject constructor or an @Provides-annotated "
- + "method.");
- }
-
- @Test
- public void testInaccessibleFoo() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.subpackage.InaccessibleFoo",
- "package test.subpackage;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class InaccessibleFoo {",
- " @AssistedInject InaccessibleFoo(@Assisted int i) {}",
- "}");
-
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.subpackage.InaccessibleFooFactory",
- "package test.subpackage;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "public interface InaccessibleFooFactory {",
- " InaccessibleFoo create(int i);",
- "}");
-
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.FooFactoryComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import test.subpackage.InaccessibleFooFactory;",
- "",
- "@Component",
- "interface FooFactoryComponent {",
- " InaccessibleFooFactory inaccessibleFooFactory();",
- "}");
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, fooFactory, component);
-
- if (compilerMode == CompilerMode.FAST_INIT_MODE) {
- // TODO(bcorso): Remove once we fix inaccessible assisted factory imlementation for fastInit.
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "test.subpackage.InaccessibleFoo is not public in test.subpackage; cannot be "
- + "accessed from outside package");
- } else {
- assertThat(compilation).succeeded();
- }
- }
-
- @Test
- public void testAssistedFactoryMethodWithTypeParametersFails() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.AssistedInject;",
- "import dagger.assisted.AssistedFactory;",
- "",
- "class Foo<T> {",
- " @AssistedInject",
- " Foo() {}",
- "",
- " @AssistedFactory",
- " interface FooFactory {",
- " <T> Foo<T> create();",
- " }",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@AssistedFactory does not currently support type parameters in the creator method.")
- .inFile(foo)
- .onLine(12);
- }
-}
diff --git a/javatests/dagger/internal/codegen/AssistedFactoryTest.java b/javatests/dagger/internal/codegen/AssistedFactoryTest.java
deleted file mode 100644
index d752321..0000000
--- a/javatests/dagger/internal/codegen/AssistedFactoryTest.java
+++ /dev/null
@@ -1,247 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
-import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-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 AssistedFactoryTest {
- @Parameters(name = "{0}")
- public static ImmutableCollection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public AssistedFactoryTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void testAssistedFactory() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted String str, Bar bar) {}",
- "}");
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface FooFactory {",
- " Foo create(String factoryStr);",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar() {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " FooFactory fooFactory();",
- "}");
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
- assertThat(compilation).succeeded();
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines("package test;", "", GENERATED_CODE_ANNOTATIONS)
- .addLinesIn(
- FAST_INIT_MODE,
- "final class DaggerTestComponent implements TestComponent {",
- "",
- " private Foo foo(String str) {",
- " return new Foo(str, new Bar());",
- " }",
- "",
- " @Override",
- " public FooFactory fooFactory() {",
- " return new FooFactory() {",
- " @Override",
- " public Foo create(String str) {",
- " return DaggerTestComponent.this.foo(str);",
- " }",
- " };",
- " }",
- "}")
- .addLinesIn(
- DEFAULT_MODE,
- "final class DaggerTestComponent implements TestComponent {",
- "",
- " private Foo_Factory fooProvider;",
- "",
- " private Provider<FooFactory> fooFactoryProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.fooProvider = Foo_Factory.create(Bar_Factory.create());",
- " this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
- " }",
- "",
- " @Override",
- " public FooFactory fooFactory() {",
- " return fooFactoryProvider.get();",
- " }",
- "}")
- .build();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- @Test
- public void testAssistedFactoryCycle() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted String str, Bar bar) {}",
- "}");
- JavaFileObject fooFactory =
- JavaFileObjects.forSourceLines(
- "test.FooFactory",
- "package test;",
- "",
- "import dagger.assisted.AssistedFactory;",
- "",
- "@AssistedFactory",
- "interface FooFactory {",
- " Foo create(String factoryStr);",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "test.Bar",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar(FooFactory fooFactory) {}",
- "}");
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface TestComponent {",
- " FooFactory fooFactory();",
- "}");
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
- assertThat(compilation).succeeded();
- JavaFileObject generatedComponent =
- compilerMode
- .javaFileBuilder("test.DaggerTestComponent")
- .addLines("package test;", "", GENERATED_CODE_ANNOTATIONS)
- .addLinesIn(
- FAST_INIT_MODE,
- "final class DaggerTestComponent implements TestComponent {",
- "",
- " private Bar bar() {",
- " return new Bar(fooFactory());",
- " }",
- "",
- " private Foo foo(String str) {",
- " return new Foo(str, bar());",
- " }",
- "",
- " @Override",
- " public FooFactory fooFactory() {",
- " return new FooFactory() {",
- " @Override",
- " public Foo create(String str) {",
- " return DaggerTestComponent.this.foo(str);",
- " }",
- " };",
- " }",
- "}")
- .addLinesIn(
- DEFAULT_MODE,
- "final class DaggerTestComponent implements TestComponent {",
- "",
- " private Provider<FooFactory> fooFactoryProvider;",
- "",
- " private Provider<Bar> barProvider;",
- "",
- " private Foo_Factory fooProvider;",
- "",
- " @SuppressWarnings(\"unchecked\")",
- " private void initialize() {",
- " this.fooFactoryProvider = new DelegateFactory<>();",
- " this.barProvider = Bar_Factory.create(fooFactoryProvider);",
- " this.fooProvider = Foo_Factory.create(barProvider);",
- " DelegateFactory.setDelegate(",
- " fooFactoryProvider, FooFactory_Impl.create(fooProvider));",
- " }",
- "",
- " @Override",
- " public FooFactory fooFactory() {",
- " return fooFactoryProvider.get();",
- " }",
- "}")
- .build();
- assertThat(compilation)
- .generatedSourceFile("test.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-}
diff --git a/javatests/dagger/internal/codegen/AssistedInjectErrorsTest.java b/javatests/dagger/internal/codegen/AssistedInjectErrorsTest.java
deleted file mode 100644
index 47e2171..0000000
--- a/javatests/dagger/internal/codegen/AssistedInjectErrorsTest.java
+++ /dev/null
@@ -1,234 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-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 AssistedInjectErrorsTest {
- @Parameters(name = "{0}")
- public static ImmutableCollection<Object[]> parameters() {
- return CompilerMode.TEST_PARAMETERS;
- }
-
- private final CompilerMode compilerMode;
-
- public AssistedInjectErrorsTest(CompilerMode compilerMode) {
- this.compilerMode = compilerMode;
- }
-
- @Test
- public void testAssistedInjectWithDuplicateTypesFails() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted String str1, @Assisted String str2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@AssistedInject constructor has duplicate @Assisted type: @Assisted java.lang.String")
- .inFile(foo)
- .onLine(8);
- }
-
- @Test
- public void testAssistedInjectWithDuplicateTypesEmptyQualifierFails() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted(\"\") String str1, @Assisted String str2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@AssistedInject constructor has duplicate @Assisted type: @Assisted java.lang.String")
- .inFile(foo)
- .onLine(8);
- }
-
- @Test
- public void testAssistedInjectWithDuplicateQualifiedTypesFails() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo<T> {",
- " @AssistedInject",
- " Foo(@Assisted(\"MyQualfier\") String s1, @Assisted(\"MyQualfier\") String s2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@AssistedInject constructor has duplicate @Assisted type: "
- + "@Assisted(\"MyQualfier\") java.lang.String")
- .inFile(foo)
- .onLine(8);
- }
-
- @Test
- public void testAssistedInjectWithDuplicateGenericTypesFails() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import java.util.List;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted List<String> list1, @Assisted List<String> list2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- "@AssistedInject constructor has duplicate @Assisted type: "
- + "@Assisted java.util.List<java.lang.String>")
- .inFile(foo)
- .onLine(9);
- }
-
- @Test
- public void testAssistedInjectWithDuplicateParameterizedTypesFails() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "",
- "class Foo<T> {",
- " @AssistedInject",
- " Foo(@Assisted T t1, @Assisted T t2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("@AssistedInject constructor has duplicate @Assisted type: @Assisted T")
- .inFile(foo)
- .onLine(8);
- }
-
- @Test
- public void testAssistedInjectWithUniqueParameterizedTypesPasses() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import java.util.List;",
- "",
- "class Foo<T1, T2> {",
- " @AssistedInject",
- " Foo(@Assisted T1 t1, @Assisted T2 t2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void testAssistedInjectWithUniqueGenericTypesPasses() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import java.util.List;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(@Assisted List<String> list1, @Assisted List<Integer> list2) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void testAssistedInjectWithUniqueQualifiedTypesPasses() {
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "test.Foo",
- "package test;",
- "",
- "import dagger.assisted.Assisted;",
- "import dagger.assisted.AssistedInject;",
- "import java.util.List;",
- "",
- "class Foo {",
- " @AssistedInject",
- " Foo(",
- " @Assisted(\"1\") Integer i1,",
- " @Assisted(\"1\") String s1,",
- " @Assisted(\"2\") String s2,",
- " @Assisted String s3) {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(foo);
- assertThat(compilation).succeeded();
- }
-}
diff --git a/javatests/dagger/internal/codegen/BUILD b/javatests/dagger/internal/codegen/BUILD
index 979ae71..ad214ff 100644
--- a/javatests/dagger/internal/codegen/BUILD
+++ b/javatests/dagger/internal/codegen/BUILD
@@ -15,84 +15,42 @@
# Description:
# Tests for the Dagger compiler/codegen
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
-kt_jvm_library(
- name = "kotlin_sources",
- srcs = [
- "KotlinInjectedQualifier.kt",
- "KotlinObjectWithMemberInjection.kt",
- ],
- deps = [
- "//java/dagger:core",
- ],
-)
-
-# TODO(bcorso): Move this into a subpackage.
-java_library(
- name = "compilers",
- srcs = [
- "CompilerMode.java",
- "Compilers.java",
- "JavaFileBuilder.java",
- ],
- deps = [
- "//java/dagger/internal/codegen:package_info",
- "//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "@com_google_auto_value_auto_value//jar",
- "@google_bazel_common//third_party/java/compile_testing",
- ],
-)
-
GenJavaTests(
name = "compiler_tests",
- srcs = glob(
- ["*.java"],
- exclude = [
- "CompilerMode.java",
- "Compilers.java",
- "JavaFileBuilder.java",
- ],
- ),
+ srcs = glob(["*.java"]),
functional = False,
javacopts = DOCLINT_HTML_AND_SYNTAX,
- plugins = ["//java/dagger/internal/codegen/bootstrap"],
deps = [
- ":compilers",
- ":kotlin_sources",
"//java/dagger:core",
- "//java/dagger/internal/codegen:package_info",
+ "//java/dagger/internal/codegen:base",
+ "//java/dagger/internal/codegen:binding",
+ "//java/dagger/internal/codegen:binding_graph_validation",
"//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:validation",
+ "//java/dagger/internal/codegen:writing",
"//java/dagger/internal/codegen/javapoet",
- "//java/dagger/internal/codegen/kotlin",
"//java/dagger/internal/codegen/langmodel",
- "//java/dagger/internal/codegen/validation",
- "//java/dagger/internal/codegen/writing",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
+ "//java/dagger/internal/codegen/serialization",
+ "//java/dagger/model",
"//java/dagger/model/testing",
"//java/dagger/producers",
"//java/dagger/spi",
- "@com_google_auto_value_auto_value//jar",
+ "@com_google_auto_value_auto_value//jar", # For AutoAnnotationProcessor
+ "@google_bazel_common//third_party/java/auto:common",
"@google_bazel_common//third_party/java/auto:value",
"@google_bazel_common//third_party/java/compile_testing",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/javapoet",
"@google_bazel_common//third_party/java/jsr250_annotations",
"@google_bazel_common//third_party/java/jsr330_inject",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/mockito",
"@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
+ "@google_bazel_common//third_party/java/truth:truth8",
],
)
diff --git a/javatests/dagger/internal/codegen/BindsDependsOnSubcomponentValidationTest.java b/javatests/dagger/internal/codegen/BindsDependsOnSubcomponentValidationTest.java
deleted file mode 100644
index aa01b3a..0000000
--- a/javatests/dagger/internal/codegen/BindsDependsOnSubcomponentValidationTest.java
+++ /dev/null
@@ -1,340 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests to make sure that delegate bindings where the impl depends on a binding in a subcomponent
- * properly fail. These are regression tests for b/147020838.
- */
-@RunWith(JUnit4.class)
-public class BindsDependsOnSubcomponentValidationTest {
- @Test
- public void testBinds() {
- JavaFileObject parentComponent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface ParentComponent {",
- " ChildComponent getChild();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface ParentModule {",
- " @Binds Foo bindFoo(FooImpl impl);",
- "}");
- JavaFileObject childComponent =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface ChildComponent {",
- " Foo getFoo();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface ChildModule {",
- " @Provides static Long providLong() {",
- " return 0L;",
- " }",
- "}");
- JavaFileObject iface =
- JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "interface Foo {", "}");
- JavaFileObject impl =
- JavaFileObjects.forSourceLines(
- "test.FooImpl",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FooImpl implements Foo {",
- " @Inject FooImpl(Long l) {}",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(parentComponent, parentModule, childComponent, childModule, iface, impl);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Long cannot be provided without an @Inject constructor")
- .inFile(parentComponent)
- .onLineContaining("interface ParentComponent");
- }
-
- @Test
- public void testSetBindings() {
- JavaFileObject parentComponent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface ParentComponent {",
- " ChildComponent getChild();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.multibindings.IntoSet;",
- "",
- "@Module",
- "interface ParentModule {",
- " @Binds @IntoSet Foo bindFoo(FooImpl impl);",
- "}");
- JavaFileObject childComponent =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Set;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface ChildComponent {",
- " Set<Foo> getFooSet();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface ChildModule {",
- " @Provides static Long providLong() {",
- " return 0L;",
- " }",
- "}");
- JavaFileObject iface =
- JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "interface Foo {", "}");
- JavaFileObject impl =
- JavaFileObjects.forSourceLines(
- "test.FooImpl",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FooImpl implements Foo {",
- " @Inject FooImpl(Long l) {}",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(parentComponent, parentModule, childComponent, childModule, iface, impl);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Long cannot be provided without an @Inject constructor")
- .inFile(parentComponent)
- .onLineContaining("interface ParentComponent");
- }
-
- @Test
- public void testSetValueBindings() {
- JavaFileObject parentComponent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface ParentComponent {",
- " ChildComponent getChild();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.ElementsIntoSet;",
- "import java.util.Collections;",
- "import java.util.Set;",
- "",
- "@Module",
- "interface ParentModule {",
- " @Provides @ElementsIntoSet",
- " static Set<Foo> provideFoo(FooImpl impl) {",
- " return Collections.singleton(impl);",
- " }",
- "}");
- JavaFileObject childComponent =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Set;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface ChildComponent {",
- " Set<Foo> getFooSet();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface ChildModule {",
- " @Provides static Long providLong() {",
- " return 0L;",
- " }",
- "}");
- JavaFileObject iface =
- JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "interface Foo {", "}");
- JavaFileObject impl =
- JavaFileObjects.forSourceLines(
- "test.FooImpl",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FooImpl implements Foo {",
- " @Inject FooImpl(Long l) {}",
- "}");
- Compilation compilation =
- daggerCompiler()
- .compile(parentComponent, parentModule, childComponent, childModule, iface, impl);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Long cannot be provided without an @Inject constructor")
- .inFile(parentComponent)
- .onLineContaining("interface ParentComponent");
- }
-
- @Test
- public void testMapBindings() {
- JavaFileObject parentComponent =
- JavaFileObjects.forSourceLines(
- "test.ParentComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(modules = ParentModule.class)",
- "interface ParentComponent {",
- " ChildComponent getChild();",
- "}");
- JavaFileObject parentModule =
- JavaFileObjects.forSourceLines(
- "test.ParentModule",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.multibindings.StringKey;",
- "",
- "@Module",
- "interface ParentModule {",
- " @Binds @IntoMap @StringKey(\"foo\") Foo bindFoo(FooImpl impl);",
- "}");
- JavaFileObject childComponent =
- JavaFileObjects.forSourceLines(
- "test.ChildComponent",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "import java.util.Map;",
- "",
- "@Subcomponent(modules = ChildModule.class)",
- "interface ChildComponent {",
- " Map<String, Foo> getFooSet();",
- "}");
- JavaFileObject childModule =
- JavaFileObjects.forSourceLines(
- "test.ChildModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface ChildModule {",
- " @Provides static Long providLong() {",
- " return 0L;",
- " }",
- "}");
- JavaFileObject iface =
- JavaFileObjects.forSourceLines("test.Foo", "package test;", "", "interface Foo {", "}");
- JavaFileObject impl =
- JavaFileObjects.forSourceLines(
- "test.FooImpl",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class FooImpl implements Foo {",
- " @Inject FooImpl(Long l) {}",
- "}");
- Compilation compilation =
- // TODO(erichang): make this flag the default and remove this
- compilerWithOptions("-Adagger.strictMultibindingValidation=enabled")
- .compile(parentComponent, parentModule, childComponent, childModule, iface, impl);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Long cannot be provided without an @Inject constructor")
- .inFile(parentComponent)
- .onLineContaining("interface ParentComponent");
- }
-}
diff --git a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
index ab26010..6ba9e3e 100644
--- a/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
+++ b/javatests/dagger/internal/codegen/BindsMethodValidationTest.java
@@ -25,6 +25,7 @@
import dagger.multibindings.IntKey;
import dagger.multibindings.LongKey;
import dagger.producers.ProducerModule;
+import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.util.Collection;
@@ -78,8 +79,9 @@
@Test
public void throwsException() {
- assertThatMethod("@Binds abstract Object throwsException(String s1) throws RuntimeException;")
- .hasError("may not throw");
+ assertThatMethod("@Binds abstract Object throwsException(String s1) throws IOException;")
+ .importing(IOException.class)
+ .hasError("only throw unchecked");
}
@Test
diff --git a/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java b/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java
index bfc3617..28b75be 100644
--- a/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java
+++ b/javatests/dagger/internal/codegen/BindsMissingDelegateValidationTest.java
@@ -97,7 +97,7 @@
.hadErrorContainingMatch(
"\\Qtest.C.NotBound cannot be provided\\E|"
+ message(
- "\\QObject is bound multiple times:",
+ "\\Qjava.lang.Object is bound multiple times:",
" @Binds Object test.C.TestModule.bindObject(test.C.NotBound)",
" @Provides Object test.C.TestModule.provideObject()\\E"))
.inFile(component)
diff --git a/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java b/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java
index ca3e5e4..fa44a6e 100644
--- a/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java
+++ b/javatests/dagger/internal/codegen/BindsOptionalOfMethodValidationTest.java
@@ -37,7 +37,7 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-/** Tests {@link dagger.internal.codegen.validation.BindsOptionalOfMethodValidator}. */
+/** Tests {@link BindsOptionalOfMethodValidator}. */
@RunWith(Parameterized.class)
public class BindsOptionalOfMethodValidationTest {
@Parameters(name = "{0}")
diff --git a/javatests/dagger/internal/codegen/CompilerMode.java b/javatests/dagger/internal/codegen/CompilerMode.java
index 86ce53d..23aa312 100644
--- a/javatests/dagger/internal/codegen/CompilerMode.java
+++ b/javatests/dagger/internal/codegen/CompilerMode.java
@@ -23,6 +23,9 @@
enum CompilerMode {
DEFAULT_MODE,
FAST_INIT_MODE("-Adagger.fastInit=enabled"),
+ AHEAD_OF_TIME_SUBCOMPONENTS_MODE(
+ "-Adagger.experimentalAheadOfTimeSubcomponents=enabled",
+ "-Adagger.emitModifiableMetadataAnnotations=disabled"),
JAVA7("-source", "7", "-target", "7"),
;
diff --git a/javatests/dagger/internal/codegen/Compilers.java b/javatests/dagger/internal/codegen/Compilers.java
index 26796bf..3e08f63 100644
--- a/javatests/dagger/internal/codegen/Compilers.java
+++ b/javatests/dagger/internal/codegen/Compilers.java
@@ -19,60 +19,42 @@
import static com.google.common.base.StandardSystemProperty.JAVA_CLASS_PATH;
import static com.google.common.base.StandardSystemProperty.PATH_SEPARATOR;
import static com.google.testing.compile.Compiler.javac;
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.joining;
import com.google.auto.value.processor.AutoAnnotationProcessor;
import com.google.common.base.Splitter;
+import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compiler;
-import java.io.File;
-import java.util.Arrays;
import javax.annotation.processing.Processor;
/** {@link Compiler} instances for testing Dagger. */
-public final class Compilers {
+final class Compilers {
private static final String GUAVA = "guava";
- static final ImmutableList<File> CLASS_PATH_WITHOUT_GUAVA_OPTION =
- Splitter.on(PATH_SEPARATOR.value()).splitToList(JAVA_CLASS_PATH.value()).stream()
- .filter(jar -> !jar.contains(GUAVA))
- // Remove Bazel's runner deploy jar which leaks Guava classes into the classpath and
- // the compile testing tests.
- .filter(jar -> !jar.contains("Runner_deploy.jar"))
- .map(File::new)
- .collect(collectingAndThen(toList(), ImmutableList::copyOf));
-
- static final ImmutableList<String> DEFAULT_JAVACOPTS =
- ImmutableList.of("-Adagger.experimentalDaggerErrorMessages=enabled");
+ static final ImmutableList<String> CLASS_PATH_WITHOUT_GUAVA_OPTION =
+ ImmutableList.of(
+ "-classpath",
+ Splitter.on(PATH_SEPARATOR.value()).splitToList(JAVA_CLASS_PATH.value()).stream()
+ .filter(jar -> !jar.contains(GUAVA))
+ .collect(joining(PATH_SEPARATOR.value())));
/**
* Returns a compiler that runs the Dagger and {@code @AutoAnnotation} processors, along with
* extras.
*/
- public static Compiler daggerCompiler(Processor... extraProcessors) {
+ static Compiler daggerCompiler(Processor... extraProcessors) {
ImmutableList.Builder<Processor> processors = ImmutableList.builder();
processors.add(new ComponentProcessor(), new AutoAnnotationProcessor());
processors.add(extraProcessors);
- return javac().withProcessors(processors.build()).withOptions(DEFAULT_JAVACOPTS);
+ return javac().withProcessors(processors.build());
}
- public static Compiler compilerWithOptions(CompilerMode... compilerModes) {
- ImmutableList.Builder<String> options = ImmutableList.builder();
+ static Compiler compilerWithOptions(CompilerMode... compilerModes) {
+ FluentIterable<String> options = FluentIterable.of();
for (CompilerMode compilerMode : compilerModes) {
- options = options.addAll(compilerMode.javacopts());
+ options = options.append(compilerMode.javacopts());
}
- return compilerWithOptions(options.build());
+ return daggerCompiler().withOptions(options);
}
-
- public static Compiler compilerWithOptions(String... options) {
- return compilerWithOptions(Arrays.asList(options));
- }
-
- public static Compiler compilerWithOptions(Iterable<String> options) {
- return daggerCompiler()
- .withOptions(ImmutableList.builder().addAll(DEFAULT_JAVACOPTS).addAll(options).build());
- }
-
- private Compilers() {}
}
diff --git a/javatests/dagger/internal/codegen/ComponentBuilderTest.java b/javatests/dagger/internal/codegen/ComponentBuilderTest.java
index acf5437..f280bdd 100644
--- a/javatests/dagger/internal/codegen/ComponentBuilderTest.java
+++ b/javatests/dagger/internal/codegen/ComponentBuilderTest.java
@@ -17,14 +17,13 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.COMPONENT_BUILDER;
+import static dagger.internal.codegen.ErrorMessages.creatorMessagesFor;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ErrorMessages;
import java.util.Collection;
import javax.tools.JavaFileObject;
import org.junit.Test;
@@ -88,7 +87,7 @@
"",
"import dagger.internal.Preconditions;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private static final class Builder implements TestComponent.Builder {",
" private TestModule testModule;",
@@ -109,7 +108,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
@@ -136,7 +135,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(MSGS.setterMethodsMustTakeOneArg())
@@ -169,7 +168,7 @@
" interface Builder extends Parent {}",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
@@ -199,7 +198,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(MSGS.setterMethodsMustReturnVoidOrBuilder())
@@ -228,7 +227,7 @@
" interface Builder extends Parent {}",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
@@ -257,7 +256,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(MSGS.methodsMayNotHaveTypeParameters())
@@ -286,7 +285,7 @@
" interface Builder extends Parent {}",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
@@ -319,7 +318,7 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(MSGS.bindsInstanceNotAllowedOnBothSetterMethodAndParameter())
@@ -353,7 +352,7 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTest.java b/javatests/dagger/internal/codegen/ComponentCreatorTest.java
index 0a7e40e..6f4ea8d 100644
--- a/javatests/dagger/internal/codegen/ComponentCreatorTest.java
+++ b/javatests/dagger/internal/codegen/ComponentCreatorTest.java
@@ -16,27 +16,28 @@
package dagger.internal.codegen;
-import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.common.collect.Sets.immutableEnumSet;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.ComponentCreatorTest.CompilerType.JAVAC;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.COMPONENT_BUILDER;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.COMPONENT_FACTORY;
+import static dagger.internal.codegen.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.ComponentCreatorKind.FACTORY;
+import static dagger.internal.codegen.ComponentKind.COMPONENT;
+import static dagger.internal.codegen.ErrorMessages.componentMessagesFor;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_FACTORY;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
-import static dagger.internal.codegen.binding.ComponentKind.COMPONENT;
-import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
import java.util.Collection;
+import java.util.List;
+import java.util.Set;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,34 +47,22 @@
/** Tests for properties of component creators shared by both builders and factories. */
@RunWith(Parameterized.class)
public class ComponentCreatorTest extends ComponentCreatorTestHelper {
- enum CompilerType {
- JAVAC
- }
-
- private final CompilerType compilerType;
- private final CompilerMode compilerMode;
-
@Parameters(name = "compilerMode={0}, creatorKind={1}")
public static Collection<Object[]> parameters() {
- return ImmutableList.of(
- new Object[]{DEFAULT_MODE, COMPONENT_BUILDER, JAVAC},
- new Object[]{DEFAULT_MODE, COMPONENT_FACTORY, JAVAC},
- new Object[]{FAST_INIT_MODE, COMPONENT_BUILDER, JAVAC},
- new Object[]{FAST_INIT_MODE, COMPONENT_FACTORY, JAVAC});
+ Set<List<Object>> params =
+ Sets.<Object>cartesianProduct(
+ immutableEnumSet(DEFAULT_MODE, FAST_INIT_MODE),
+ immutableEnumSet(COMPONENT_BUILDER, COMPONENT_FACTORY));
+ return ImmutableList.copyOf(Iterables.transform(params, Collection::toArray));
}
public ComponentCreatorTest(
- CompilerMode compilerMode,
- ComponentCreatorAnnotation componentCreatorAnnotation,
- CompilerType compilerType) {
+ CompilerMode compilerMode, ComponentCreatorAnnotation componentCreatorAnnotation) {
super(compilerMode, componentCreatorAnnotation);
- this.compilerMode = compilerMode;
- this.compilerType = compilerType;
}
@Test
public void testEmptyCreator() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject injectableTypeFile =
JavaFileObjects.forSourceLines(
"test.SomeInjectableType",
@@ -106,7 +95,7 @@
"test.DaggerSimpleComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private static final class Builder implements SimpleComponent.Builder {",
" @Override",
@@ -124,7 +113,6 @@
@Test
public void testCanInstantiateModulesUserCannotSet() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
@@ -161,7 +149,7 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final TestModule testModule;",
"",
@@ -322,7 +310,6 @@
@Test
public void testCreatorWithBindsInstanceNoStaticCreateGenerated() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject componentFile =
javaFileBuilder("test.SimpleComponent")
.addLines(
@@ -360,7 +347,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private final Object object;",
"",
@@ -423,7 +410,6 @@
@Test
public void testCreatorWithPrimitiveBindsInstance() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject componentFile =
javaFileBuilder("test.SimpleComponent")
.addLines(
@@ -462,7 +448,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private final Integer i;",
"",
@@ -793,7 +779,6 @@
@Test
public void testMultipleSettersPerTypeFails() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject moduleFile =
JavaFileObjects.forSourceLines(
"test.TestModule",
@@ -852,7 +837,6 @@
@Test
public void testMultipleSettersPerTypeIncludingResolvedGenericsFails() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject moduleFile =
JavaFileObjects.forSourceLines(
"test.TestModule",
@@ -916,7 +900,6 @@
@Test
public void testExtraSettersFails() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject componentFile =
javaFileBuilder("test.SimpleComponent")
.addLines(
@@ -1049,7 +1032,6 @@
@Test
public void covariantFactoryMethodReturnType() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject foo =
JavaFileObjects.forSourceLines(
"test.Foo",
@@ -1090,7 +1072,6 @@
@Test
public void covariantFactoryMethodReturnType_hasNewMethod() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject foo =
JavaFileObjects.forSourceLines(
"test.Foo",
@@ -1152,7 +1133,6 @@
@Test
public void covariantFactoryMethodReturnType_hasNewMethod_factoryMethodInherited() {
- assume().that(compilerType).isEqualTo(JAVAC);
JavaFileObject foo =
JavaFileObjects.forSourceLines(
"test.Foo",
@@ -1270,13 +1250,4 @@
.inFile(componentFile)
.onLineContaining(process("interface Builder"));
}
-
- /** Compiles the given files with the set compiler mode's javacopts. */
- @Override
- Compilation compile(JavaFileObject... files) {
- ImmutableList.Builder<String> options =
- ImmutableList.<String>builder().addAll(compilerMode.javacopts());
-
- return compilerWithOptions(options.build()).compile(files);
- }
}
diff --git a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
index 8ad4322..2ee120e 100644
--- a/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
+++ b/javatests/dagger/internal/codegen/ComponentCreatorTestHelper.java
@@ -16,16 +16,13 @@
package dagger.internal.codegen;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
-import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.ComponentCreatorKind.FACTORY;
+import static dagger.internal.codegen.ErrorMessages.creatorMessagesFor;
import static java.util.stream.Collectors.joining;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
-import dagger.internal.codegen.binding.ComponentCreatorKind;
-import dagger.internal.codegen.binding.ErrorMessages;
import java.util.Arrays;
import java.util.stream.Stream;
import javax.tools.JavaFileObject;
@@ -87,6 +84,6 @@
/** Compiles the given files with the set compiler mode's javacopts. */
Compilation compile(JavaFileObject... files) {
- return compilerWithOptions(compilerMode.javacopts()).compile(files);
+ return daggerCompiler().withOptions(compilerMode.javacopts()).compile(files);
}
}
diff --git a/javatests/dagger/internal/codegen/ComponentDependenciesTest.java b/javatests/dagger/internal/codegen/ComponentDependenciesTest.java
deleted file mode 100644
index bbfa51c..0000000
--- a/javatests/dagger/internal/codegen/ComponentDependenciesTest.java
+++ /dev/null
@@ -1,136 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.daggerCompiler;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.JavaFileObjects;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class ComponentDependenciesTest {
- @Test
- public void dependenciesWithTwoOfSameMethodOnDifferentInterfaces_fail() {
- JavaFileObject interfaceOne = JavaFileObjects.forSourceLines("test.One",
- "package test;",
- "",
- "interface One {",
- " String getOne();",
- "}");
- JavaFileObject interfaceTwo = JavaFileObjects.forSourceLines("test.Two",
- "package test;",
- "",
- "interface Two {",
- " String getTwo();",
- "}");
- JavaFileObject mergedInterface = JavaFileObjects.forSourceLines("test.Merged",
- "package test;",
- "",
- "interface Merged extends One, Two {}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = Merged.class)",
- "interface TestComponent {",
- " String getString();",
- "}");
- Compilation compilation = daggerCompiler().compile(
- interfaceOne, interfaceTwo, mergedInterface, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("DuplicateBindings");
- }
-
- @Test
- public void dependenciesWithTwoOfSameMethodOnDifferentInterfaces_producers_fail() {
- JavaFileObject interfaceOne = JavaFileObjects.forSourceLines("test.One",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "",
- "interface One {",
- " ListenableFuture<String> getOne();",
- "}");
- JavaFileObject interfaceTwo = JavaFileObjects.forSourceLines("test.Two",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "",
- "interface Two {",
- " ListenableFuture<String> getTwo();",
- "}");
- JavaFileObject mergedInterface = JavaFileObjects.forSourceLines("test.Merged",
- "package test;",
- "",
- "interface Merged extends One, Two {}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import com.google.common.util.concurrent.ListenableFuture;",
- "import dagger.producers.ProductionComponent;",
- "",
- "@ProductionComponent(dependencies = Merged.class)",
- "interface TestComponent {",
- " ListenableFuture<String> getString();",
- "}");
- Compilation compilation = daggerCompiler().compile(
- interfaceOne, interfaceTwo, mergedInterface, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("DuplicateBindings");
- }
-
- @Test
- public void dependenciesWithTwoOfSameMethodButDifferentNullability_fail() {
- JavaFileObject interfaceOne = JavaFileObjects.forSourceLines("test.One",
- "package test;",
- "",
- "interface One {",
- " String getString();",
- "}");
- JavaFileObject interfaceTwo = JavaFileObjects.forSourceLines("test.Two",
- "package test;",
- "import javax.annotation.Nullable;",
- "",
- "interface Two {",
- " @Nullable String getString();",
- "}");
- JavaFileObject mergedInterface = JavaFileObjects.forSourceLines("test.Merged",
- "package test;",
- "",
- "interface Merged extends One, Two {}");
- JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component(dependencies = Merged.class)",
- "interface TestComponent {",
- " String getString();",
- "}");
- Compilation compilation = daggerCompiler().compile(
- interfaceOne, interfaceTwo, mergedInterface, componentFile);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("DuplicateBindings");
- }
-
-}
diff --git a/javatests/dagger/internal/codegen/ComponentFactoryTest.java b/javatests/dagger/internal/codegen/ComponentFactoryTest.java
index 0f155b9..403498b 100644
--- a/javatests/dagger/internal/codegen/ComponentFactoryTest.java
+++ b/javatests/dagger/internal/codegen/ComponentFactoryTest.java
@@ -17,14 +17,13 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.COMPONENT_FACTORY;
-import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.COMPONENT_FACTORY;
+import static dagger.internal.codegen.ErrorMessages.creatorMessagesFor;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ErrorMessages;
import java.util.Collection;
import javax.tools.JavaFileObject;
import org.junit.Test;
@@ -87,7 +86,7 @@
"",
"import dagger.internal.Preconditions;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private static final class Factory implements TestComponent.Factory {",
" @Override",
@@ -98,7 +97,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(moduleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
@@ -124,7 +123,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(String.format(MSGS.twoFactoryMethods(), "create()"))
@@ -153,7 +152,7 @@
" interface Factory extends Parent {}",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(String.format(MSGS.twoFactoryMethods(), "create()"))
diff --git a/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java b/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java
index 6fb1820..19eabac 100644
--- a/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java
+++ b/javatests/dagger/internal/codegen/ComponentHierarchyValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.message;
@@ -64,7 +63,8 @@
assertThat(compilation).hadErrorContaining("test.Parent also has @Singleton");
Compilation withoutScopeValidation =
- compilerWithOptions("-Adagger.disableInterComponentScopeValidation=none")
+ daggerCompiler()
+ .withOptions("-Adagger.disableInterComponentScopeValidation=none")
.compile(component, subcomponent);
assertThat(withoutScopeValidation).succeeded();
}
diff --git a/javatests/dagger/internal/codegen/ComponentProcessorTest.java b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
index eee6a0c..2b79b6f 100644
--- a/javatests/dagger/internal/codegen/ComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/ComponentProcessorTest.java
@@ -20,10 +20,11 @@
import static com.google.testing.compile.Compiler.javac;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.NPE_FROM_COMPONENT_METHOD;
+import static dagger.internal.codegen.GeneratedLines.NPE_FROM_PROVIDES_METHOD;
import com.google.auto.common.MoreElements;
import com.google.common.base.Predicate;
@@ -106,15 +107,16 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(parent, child, another, componentFile);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("List<Integer> is bound multiple times");
+ .hadErrorContaining("java.util.List<java.lang.Integer> is bound multiple times");
assertThat(compilation)
- .hadErrorContaining("@Provides List<Integer> ChildNumberModule.provideListB(Integer)");
+ .hadErrorContaining("@Provides List<Integer> test.ChildNumberModule.provideListB(Integer)");
assertThat(compilation)
- .hadErrorContaining("@Provides List<Integer> AnotherModule.provideListOfInteger()");
+ .hadErrorContaining("@Provides List<Integer> test.AnotherModule.provideListOfInteger()");
}
@Test public void privateNestedClassWithWarningThatIsAnErrorInComponent() {
@@ -140,7 +142,8 @@
" OuterClass outerClass();",
"}");
Compilation compilation =
- compilerWithOptions(
+ daggerCompiler()
+ .withOptions(
compilerMode.javacopts().append("-Adagger.privateMemberValidation=WARNING"))
.compile(outerClass, componentFile);
assertThat(compilation).failed();
@@ -182,7 +185,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {")
.addLinesIn(
FAST_INIT_MODE,
@@ -258,7 +261,8 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectableTypeFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -298,7 +302,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {")
.addLinesIn(
FAST_INIT_MODE,
@@ -383,7 +387,8 @@
" }")
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectableTypeFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -417,7 +422,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerOuterType_SimpleComponent",
" implements OuterType.SimpleComponent {",
" private DaggerOuterType_SimpleComponent() {}",
@@ -441,7 +446,7 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(nestedTypesFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(nestedTypesFile);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerOuterType_SimpleComponent")
@@ -501,7 +506,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final TestModule testModule;",
"",
@@ -509,13 +514,13 @@
" this.testModule = testModuleParam;",
" }",
"",
- " private B b() {",
+ " private B getB() {",
" return TestModule_BFactory.b(testModule, new C());",
" }",
"",
" @Override",
" public A a() {",
- " return new A(b());",
+ " return new A(getB());",
" }",
"",
" static final class Builder {",
@@ -537,7 +542,8 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aFile, bFile, cFile, moduleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -604,21 +610,22 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
- " private B b() {",
+ " private B getB() {",
" return TestModule_BFactory.b(new C());",
" }",
"",
" @Override",
" public A a() {",
- " return new A(b());",
+ " return new A(getB());",
" }",
"}")
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aFile, bFile, cFile, moduleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -701,7 +708,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" static final class Builder {",
"",
@@ -747,7 +754,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
always,
testModule,
@@ -781,7 +789,7 @@
"@Component(modules = RootModule.class)",
"interface TestComponent {}");
assertThat(
- compilerWithOptions(compilerMode.javacopts()).compile(rootModule, component))
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(rootModule, component))
.failed();
assertThat(
daggerCompiler(
@@ -820,7 +828,7 @@
" ChildComponent childComponent();",
"}");
assertThat(
- compilerWithOptions(compilerMode.javacopts()).compile(subcomponent, component))
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(subcomponent, component))
.failed();
assertThat(
daggerCompiler(
@@ -885,7 +893,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
"",
" private DaggerParent() {}",
@@ -919,7 +927,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(component, module, subcomponent);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -953,7 +962,8 @@
" BClass bClass();",
"}");
assertThat(
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aModule, aClass, bClass, component))
.succeeded();
}
@@ -997,7 +1007,7 @@
"",
"import com.google.errorprone.annotations.CanIgnoreReturnValue;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" @Override",
" public void inject(SomeInjectedType instance) {",
@@ -1019,7 +1029,8 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectableTypeFile, injectedTypeFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1053,7 +1064,7 @@
"test.DaggerSimpleComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private Provider<SimpleComponent> simpleComponentProvider;",
"",
@@ -1073,7 +1084,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectableTypeFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1117,7 +1129,7 @@
"",
"import com.google.errorprone.annotations.CanIgnoreReturnValue;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" @Override",
" public SomeInjectedType createAndInject() {",
@@ -1135,7 +1147,8 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectableTypeFile, injectedTypeFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1185,9 +1198,11 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerBComponent implements BComponent {")
- .addLinesIn(DEFAULT_MODE, " private Provider<A> aProvider;")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " private Provider<A> aProvider;")
.addLinesIn(
FAST_INIT_MODE,
" private final AComponent aComponent;",
@@ -1197,7 +1212,7 @@
" this.aComponent = aComponentParam;",
" }",
"",
- " private Provider<A> aProvider() {",
+ " private Provider<A> getAProvider() {",
" Object local = aProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -1211,9 +1226,16 @@
" private void initialize(final AComponent aComponentParam) {",
" this.aProvider = new test_AComponent_a(aComponentParam);",
" }")
- .addLines("", " @Override", " public B b() {")
- .addLinesIn(DEFAULT_MODE, " return new B(aProvider);")
- .addLinesIn(FAST_INIT_MODE, " return new B(aProvider());")
+ .addLines(
+ "",
+ " @Override",
+ " public B b() {")
+ .addLinesIn(
+ DEFAULT_MODE,
+ " return new B(aProvider);")
+ .addLinesIn(
+ FAST_INIT_MODE,
+ " return new B(getAProvider());")
.addLines(
" }",
"",
@@ -1241,7 +1263,8 @@
" ",
" @Override()",
" public A get() {",
- " return Preconditions.checkNotNullFromComponent(aComponent.a());",
+ " return Preconditions.checkNotNull(",
+ " aComponent.a(), " + NPE_FROM_COMPONENT_METHOD + ");",
" }",
" }",
"}")
@@ -1254,8 +1277,9 @@
" switch (id) {",
" case 0:",
" return (T)",
- " Preconditions.checkNotNullFromComponent(",
- " DaggerBComponent.this.aComponent.a());",
+ " Preconditions.checkNotNull(",
+ " DaggerBComponent.this.aComponent.a(),",
+ " " + NPE_FROM_COMPONENT_METHOD + ");",
" default:",
" throw new AssertionError(id);",
" }",
@@ -1263,7 +1287,8 @@
" }")
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aFile, bFile, aComponentFile, bComponentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1318,7 +1343,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final TestModule testModule;",
" private final other.test.TestModule testModule2;",
@@ -1366,7 +1391,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aFile, otherAFile, moduleFile, otherModuleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1443,7 +1469,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerBComponent implements BComponent {",
" private final AComponent aComponent;",
"",
@@ -1454,17 +1480,20 @@
" @Override",
" public InjectedType injectedType() {",
" return new InjectedType(",
- " Preconditions.checkNotNullFromComponent(",
- " aComponent.someStringInjection()),",
+ " Preconditions.checkNotNull(",
+ " aComponent.someStringInjection(),",
+ " \"Cannot return null from a non-@Nullable component method\"),",
" aComponent.someIntInjection(),",
" aComponent,",
- " Preconditions.checkNotNullFromComponent(",
- " aComponent.someClassInjection()));",
+ " Preconditions.checkNotNull(",
+ " aComponent.someClassInjection(),",
+ " \"Cannot return null from a non-@Nullable component method\"));",
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectedTypeFile, aComponentFile, bComponentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1527,15 +1556,15 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
- " private B b() {",
+ " private B getB() {",
" return new B(new C());",
" }",
"",
" @Override",
" public A a() {",
- " return new A(b());",
+ " return new A(getB());",
" }",
"",
" @Override",
@@ -1551,7 +1580,8 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aFile, bFile, cFile, xFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1607,7 +1637,7 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private DaggerSimpleComponent() {}",
"",
@@ -1633,7 +1663,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
injectableTypeFile,
componentSupertypeAFile,
@@ -1676,7 +1707,7 @@
"test.DaggerSimpleComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" @Override",
" public SomeInjectableType someInjectableType() {",
@@ -1684,7 +1715,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectableTypeFile, componentSupertype, depComponentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1731,7 +1763,8 @@
" C c();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(aFile, bFile, cFile, componentFile);
assertThat(compilation).failed();
assertThat(compilation)
@@ -1754,7 +1787,7 @@
" String[] array();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(component);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("String[] cannot be provided without an @Provides-annotated method");
@@ -1980,7 +2013,7 @@
" @Inject @AScope AClass() {}",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(aScope, aClass);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(aScope, aClass);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("@Scope annotations are not allowed on @Inject constructors")
@@ -2049,7 +2082,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
" private DaggerParent() {",
" }",
@@ -2078,7 +2111,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(foo, module, component, prunedSubcomponent);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -2141,7 +2175,7 @@
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
- .hadErrorContaining("String is bound multiple times")
+ .hadErrorContaining("java.lang.String is bound multiple times")
.inFile(component)
.onLineContaining("interface TestComponent");
}
@@ -2149,7 +2183,8 @@
@Test
public void nullIncorrectlyReturnedFromNonNullableInlinedProvider() {
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
JavaFileObjects.forSourceLines(
"test.TestModule",
@@ -2190,7 +2225,7 @@
"test.TestModule_NonNullableStringFactory",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_NonNullableStringFactory",
" implements Factory<String> {",
" @Override",
@@ -2199,8 +2234,8 @@
" }",
"",
" public static String nonNullableString() {",
- " return Preconditions.checkNotNullFromProvides(",
- " TestModule.nonNullableString());",
+ " return Preconditions.checkNotNull(",
+ " TestModule.nonNullableString(), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}"));
@@ -2210,7 +2245,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public String nonNullableString() {",
@@ -2239,7 +2274,8 @@
@Test
public void nullCheckingIgnoredWhenProviderReturnsPrimitive() {
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
JavaFileObjects.forSourceLines(
"test.TestModule",
@@ -2280,7 +2316,7 @@
"test.TestModule_PrimitiveIntegerFactory",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_PrimitiveIntegerFactory",
" implements Factory<Integer> {",
"",
@@ -2300,7 +2336,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Integer nonNullableInteger() {",
@@ -2376,9 +2412,9 @@
JavaFileObjects.forSourceLines(
"test.DaggerParent",
"package test;",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
- " private String string() {",
+ " private String getString() {",
" return TestModule_StringFactory.string(numberProvider.get());",
" }",
"}");
@@ -2446,7 +2482,7 @@
JavaFileObjects.forSourceLines(
"test.DaggerParent",
"package test;",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
" private final class ChildImpl implements Child {",
" @Override",
@@ -2513,7 +2549,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Injected injected() {",
@@ -2586,7 +2622,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public String unqualified() {",
@@ -2640,7 +2676,7 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class DaggerPublicComponent implements PublicComponent {",
" private DaggerPublicComponent() {}",
"",
diff --git a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
index 049ff85..85e2d7b 100644
--- a/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
+++ b/javatests/dagger/internal/codegen/ComponentRequirementFieldTest.java
@@ -17,8 +17,9 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.NPE_FROM_COMPONENT_METHOD;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
@@ -66,7 +67,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(component);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
@@ -75,7 +76,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final Integer i;",
" private final List<String> list;",
@@ -161,7 +162,8 @@
" long l();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, otherPackageModule, component);
assertThat(compilation).succeeded();
JavaFileObject generatedComponent =
@@ -172,7 +174,7 @@
"import other.OtherPackageModule;",
"import other.OtherPackageModule_LFactory;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final ParentModule parentModule;",
" private final OtherPackageModule otherPackageModule;",
@@ -234,7 +236,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(dependency, component, subcomponent);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -244,7 +247,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final Dep dep;",
"",
@@ -264,13 +267,14 @@
"",
" @Override",
" public String methodOnDep() {",
- " return Preconditions.checkNotNullFromComponent(",
- " dep.string());",
+ " return Preconditions.checkNotNull(",
+ " dep.string(), " + NPE_FROM_COMPONENT_METHOD + " );",
" }",
"",
" @Override",
" public Object otherMethodOnDep() {",
- " return Preconditions.checkNotNullFromComponent(dep.object());",
+ " return Preconditions.checkNotNull(",
+ " dep.object(), " + NPE_FROM_COMPONENT_METHOD + " );",
" }",
"",
" private final class TestSubcomponentImpl implements TestSubcomponent {",
@@ -357,7 +361,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final ParentModule parentModule;",
"",
@@ -366,15 +370,15 @@
" }",
"",
" private final class TestSubcomponentImpl implements TestSubcomponent {",
- " private Set<Object> setOfObject() {",
+ " private Set<Object> getSetOfObject() {",
" return ImmutableSet.<Object>of(",
" ParentModule_ContributionFactory.contribution(),",
" ChildModule_ContributionFactory.contribution());",
" }",
"",
- " private Object object() {",
+ " private Object getObject() {",
" return ParentModule_ReliesOnMultibindingFactory.reliesOnMultibinding(",
- " DaggerTestComponent.this.parentModule, setOfObject());",
+ " DaggerTestComponent.this.parentModule, getSetOfObject());",
" }",
" }",
"}");
@@ -385,7 +389,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final ParentModule parentModule;",
"",
@@ -421,7 +425,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(parentModule, childModule, component, subcomponent);
assertThat(compilation).succeeded();
assertThat(compilation)
diff --git a/javatests/dagger/internal/codegen/ComponentShardTest.java b/javatests/dagger/internal/codegen/ComponentShardTest.java
deleted file mode 100644
index fc59c92..0000000
--- a/javatests/dagger/internal/codegen/ComponentShardTest.java
+++ /dev/null
@@ -1,281 +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.internal.codegen;
-
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
-import static java.util.stream.Collectors.joining;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import java.util.Arrays;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class ComponentShardTest {
- private static final int BINDINGS_PER_SHARD = 10;
-
- @Test
- public void testNewShardCreated() {
- // Create 2N + 1 bindings: N in DaggerTestComponent, N in Shard1, and 1 in Shard2
- int numBindings = 2 * BINDINGS_PER_SHARD + 1;
- ImmutableList.Builder<JavaFileObject> javaFileObjects = ImmutableList.builder();
- ImmutableList.Builder<String> entryPoints = ImmutableList.builder();
- for (int i = 0; i < numBindings; i++) {
- String bindingName = "Binding" + i;
- entryPoints.add(String.format("%1$s get%1$s();", bindingName));
- entryPoints.add(String.format("Provider<%1$s> get%1$sProvider();", bindingName));
-
- // Add dependencies between main component and shard1: 9 -> 10 -> Provider<9>
- // Add dependencies between shard1 and shard2: 19 -> 20 -> Provider<19>
- switch (i) {
- case 9:
- javaFileObjects.add(createBinding(bindingName, "Binding10 dep"));
- break;
- case 10:
- javaFileObjects.add(createBinding(bindingName, "Provider<Binding9> dep"));
- break;
- case 19:
- javaFileObjects.add(createBinding(bindingName, "Binding20 dep"));
- break;
- case 20:
- javaFileObjects.add(createBinding(bindingName, "Provider<Binding19> dep"));
- break;
- default:
- javaFileObjects.add(createBinding(bindingName));
- break;
- }
- }
-
- javaFileObjects.add(createComponent(entryPoints.build()));
-
- // This generated component shows a couple things:
- // 1. Binding locations:
- // * Binding #9 belongs to DaggerTestComponent
- // * Binding #10 belongs to Shard1
- // * Binding #20 belongs to Shard2
- // 2. DaggerTestComponent entry point methods:
- // * Binding #9 implementation is inlined DaggerTestComponent.
- // * Binding #10 implementation is delegated to Shard1.
- // * Binding #20 implementation is delegated to Shard2.
- // 3. Dependencies between component and shard:
- // * Binding #9 in DaggerTestComponent depends on #10 in Shard1.
- // * Binding #10 in Shard1 depends on Provider<#9> in DaggerTestComponent.
- // 4. Dependencies between shard and shard:
- // * Binding #19 in Shard1 depends on #20 in Shard2.
- // * Binding #20 in Shard2 depends on Provider<#19> in Shard1.
- JavaFileObject generatedComponent =
- JavaFileObjects.forSourceLines(
- "dagger.internal.codegen.DaggerTestComponent",
- "package dagger.internal.codegen;",
- GENERATED_CODE_ANNOTATIONS,
- "final class DaggerTestComponent implements TestComponent {",
- " private final Shard1 shard1 = new Shard1();",
- "",
- " private volatile Provider<Binding9> binding9Provider;",
- "",
- " private volatile Object binding9 = new MemoizedSentinel();",
- "",
- " @Override",
- " public Binding9 getBinding9() {",
- " Object local = binding9;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding9;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding9(DaggerTestComponent.this.shard1.binding10());",
- " binding9 = DoubleCheck.reentrantCheck(binding9, local);",
- " }",
- " }",
- " }",
- " return (Binding9) local;",
- " }",
- "",
- " @Override",
- " public Provider<Binding9> getBinding9Provider() {",
- " Object local = binding9Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(9);",
- " binding9Provider = (Provider<Binding9>) local;",
- " }",
- " return (Provider<Binding9>) local;",
- " }",
- "",
- " @Override",
- " public Binding10 getBinding10() {",
- " return DaggerTestComponent.this.shard1.binding10();",
- " }",
- "",
- " @Override",
- " public Provider<Binding10> getBinding10Provider() {",
- " return DaggerTestComponent.this.shard1.binding10Provider();",
- " }",
- "",
- " @Override",
- " public Binding20 getBinding20() {",
- " return DaggerTestComponent.this.shard2.binding20();",
- " }",
- "",
- " @Override",
- " public Provider<Binding20> getBinding20Provider() {",
- " return DaggerTestComponent.this.shard2.binding20Provider();",
- " }",
- "",
- " private final class Shard1 {",
- " private volatile Object binding10 = new MemoizedSentinel();",
- "",
- " private volatile Provider<Binding10> binding10Provider;",
- "",
- " private volatile Provider<Binding19> binding19Provider;",
- "",
- " private volatile Object binding19 = new MemoizedSentinel();",
- "",
- " private Binding10 binding10() {",
- " Object local = binding10;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding10;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding10(",
- " DaggerTestComponent.this.getBinding9Provider());",
- " binding10 = DoubleCheck.reentrantCheck(binding10, local);",
- " }",
- " }",
- " }",
- " return (Binding10) local;",
- " }",
- "",
- " private Provider<Binding10> binding10Provider() {",
- " Object local = binding10Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(10);",
- " binding10Provider = (Provider<Binding10>) local;",
- " }",
- " return (Provider<Binding10>) local;",
- " }",
- "",
- " private Provider<Binding19> binding19Provider() {",
- " Object local = binding19Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(19);",
- " binding19Provider = (Provider<Binding19>) local;",
- " }",
- " return (Provider<Binding19>) local;",
- " }",
- "",
- " private Binding19 binding19() {",
- " Object local = binding19;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding19;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding19(DaggerTestComponent.this.shard2.binding20());",
- " binding19 = DoubleCheck.reentrantCheck(binding19, local);",
- " }",
- " }",
- " }",
- " return (Binding19) local;",
- " }",
- " }",
- "",
- " private final class Shard2 {",
- " private volatile Object binding20 = new MemoizedSentinel();",
- "",
- " private volatile Provider<Binding20> binding20Provider;",
- "",
- " private Binding20 binding20() {",
- " Object local = binding20;",
- " if (local instanceof MemoizedSentinel) {",
- " synchronized (local) {",
- " local = binding20;",
- " if (local instanceof MemoizedSentinel) {",
- " local = new Binding20(",
- " DaggerTestComponent.this.shard1.binding19Provider());",
- " binding20 = DoubleCheck.reentrantCheck(binding20, local);",
- " }",
- " }",
- " }",
- " return (Binding20) local;",
- " }",
- "",
- " private Provider<Binding20> binding20Provider() {",
- " Object local = binding20Provider;",
- " if (local == null) {",
- " local = new SwitchingProvider<>(20);",
- " binding20Provider = (Provider<Binding20>) local;",
- " }",
- " return (Provider<Binding20>) local;",
- " }",
- " }",
- "}");
-
- Compilation compilation = compilerWithAndroidMode().compile(javaFileObjects.build());
- assertThat(compilation).succeededWithoutWarnings();
- assertThat(compilation)
- .generatedSourceFile("dagger.internal.codegen.DaggerTestComponent")
- .containsElementsIn(generatedComponent);
- }
-
- private static JavaFileObject createBinding(String bindingName, String... deps) {
- return JavaFileObjects.forSourceLines(
- "dagger.internal.codegen." + bindingName,
- "package dagger.internal.codegen;",
- "",
- "import javax.inject.Inject;",
- "import javax.inject.Provider;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "final class " + bindingName + " {",
- " @Inject",
- " " + bindingName + "(" + Arrays.stream(deps).collect(joining(", ")) + ") {}",
- "}");
- }
-
- private static JavaFileObject createComponent(ImmutableList<String> entryPoints) {
- return JavaFileObjects.forSourceLines(
- "dagger.internal.codegen.TestComponent",
- "package dagger.internal.codegen;",
- "",
- "import dagger.Component;",
- "import javax.inject.Provider;",
- "import javax.inject.Singleton;",
- "",
- "@Singleton",
- "@Component",
- "interface TestComponent {",
- " " + entryPoints.stream().collect(joining("\n ")),
- "}");
- }
-
- private static Compiler compilerWithAndroidMode() {
- return javac()
- .withProcessors(new ComponentProcessor())
- .withOptions(
- ImmutableSet.builder()
- .add("-Adagger.keysPerComponentShard=" + BINDINGS_PER_SHARD)
- .addAll(CompilerMode.FAST_INIT_MODE.javacopts())
- .build());
- }
-}
diff --git a/javatests/dagger/internal/codegen/ComponentValidationTest.java b/javatests/dagger/internal/codegen/ComponentValidationTest.java
index 6c642a4..169a318 100644
--- a/javatests/dagger/internal/codegen/ComponentValidationTest.java
+++ b/javatests/dagger/internal/codegen/ComponentValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.message;
@@ -220,17 +219,6 @@
message(
"test.ComponentShort contains a cycle in its component dependencies:",
" test.ComponentShort"));
-
- // Test that this also fails when transitive validation is disabled.
- compilation =
- compilerWithOptions("-Adagger.validateTransitiveComponentDependencies=DISABLED")
- .compile(shortLifetime);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.ComponentShort contains a cycle in its component dependencies:",
- " test.ComponentShort"));
}
@Test
@@ -293,13 +281,6 @@
" test.ComponentMedium",
" test.ComponentShort"))
.inFile(shortLifetime);
-
- // Test that compilation succeeds when transitive validation is disabled because the cycle
- // cannot be detected.
- compilation =
- compilerWithOptions("-Adagger.validateTransitiveComponentDependencies=DISABLED")
- .compile(longLifetime, mediumLifetime, shortLifetime);
- assertThat(compilation).succeeded();
}
@Test
diff --git a/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java b/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java
index 470b1ed..1fcf7bc 100644
--- a/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java
+++ b/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java
@@ -36,7 +36,7 @@
import javax.tools.JavaFileObject;
/** A {@link Truth} subject for testing Dagger module methods. */
-final class DaggerModuleMethodSubject extends Subject {
+final class DaggerModuleMethodSubject extends Subject<DaggerModuleMethodSubject, String> {
/** A {@link Truth} subject factory for testing Dagger module methods. */
static final class Factory implements Subject.Factory<DaggerModuleMethodSubject, String> {
diff --git a/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java b/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java
index bc729fc..2f4aecf 100644
--- a/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java
+++ b/javatests/dagger/internal/codegen/DelegateBindingExpressionTest.java
@@ -19,8 +19,8 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.CompilationSubject;
@@ -144,14 +144,14 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object regularScoped = new MemoizedSentinel();",
" private volatile ReusableScoped reusableScoped;",
"",
- " private RegularScoped regularScoped() {",
+ " private RegularScoped getRegularScoped() {",
" Object local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -165,7 +165,7 @@
" return (RegularScoped) local;",
" }",
"",
- " private ReusableScoped reusableScoped() {",
+ " private ReusableScoped getReusableScoped() {",
" Object local = reusableScoped;",
" if (local == null) {",
" local = new ReusableScoped();",
@@ -223,14 +223,14 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object regularScoped = new MemoizedSentinel();",
" private volatile ReusableScoped reusableScoped;",
"",
- " private RegularScoped regularScoped() {",
+ " private RegularScoped getRegularScoped() {",
" Object local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -244,7 +244,7 @@
" return (RegularScoped) local;",
" }",
"",
- " private ReusableScoped reusableScoped() {",
+ " private ReusableScoped getReusableScoped() {",
" Object local = reusableScoped;",
" if (local == null) {",
" local = new ReusableScoped();",
@@ -299,14 +299,14 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object regularScoped = new MemoizedSentinel();",
" private volatile ReusableScoped reusableScoped;",
"",
- " private RegularScoped regularScoped() {",
+ " private RegularScoped getRegularScoped() {",
" Object local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -320,7 +320,7 @@
" return (RegularScoped) local;",
" }",
"",
- " private ReusableScoped reusableScoped() {",
+ " private ReusableScoped getReusableScoped() {",
" Object local = reusableScoped;",
" if (local == null) {",
" local = new ReusableScoped();",
@@ -390,7 +390,8 @@
" other.Supertype supertype();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(accessibleSupertype, inaccessibleSubtype, module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -401,7 +402,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
@@ -421,7 +422,7 @@
FAST_INIT_MODE,
" private volatile Object subtype = new MemoizedSentinel();",
"",
- " private Object subtype() {",
+ " private Object getSubtype() {",
" Object local = subtype;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -437,7 +438,7 @@
"",
" @Override",
" public Supertype supertype() {",
- " return (Supertype) subtype();",
+ " return (Supertype) getSubtype();",
" }")
.build());
}
@@ -498,7 +499,8 @@
" other.UsesSupertype usesSupertype();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(supertype, subtype, usesSupertype, module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -509,7 +511,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
@@ -526,7 +528,7 @@
FAST_INIT_MODE,
" private volatile Object subtype = new MemoizedSentinel();",
"",
- " private Object subtype() {",
+ " private Object getSubtype() {",
" Object local = subtype;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -542,7 +544,7 @@
"",
" @Override",
" public UsesSupertype usesSupertype() {",
- " return UsesSupertype_Factory.newInstance(subtype());",
+ " return UsesSupertype_Factory.newInstance(getSubtype());",
" }")
.build());
}
@@ -588,7 +590,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -599,7 +602,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
@@ -617,7 +620,7 @@
FAST_INIT_MODE,
" private volatile Provider<String> provideStringProvider;",
"",
- " private Provider<String> stringProvider() {",
+ " private Provider<String> getStringProvider() {",
" Object local = provideStringProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -628,12 +631,12 @@
"",
" @Override",
" public Provider<CharSequence> charSequence() {",
- " return (Provider) stringProvider();",
+ " return (Provider) getStringProvider();",
" }",
"",
" @Override",
" public Provider<String> namedString() {",
- " return stringProvider();",
+ " return getStringProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
@@ -689,7 +692,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -700,7 +704,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
@@ -717,7 +721,7 @@
FAST_INIT_MODE,
" private volatile Provider<String> provideStringProvider;",
"",
- " private Provider<String> stringProvider() {",
+ " private Provider<String> getStringProvider() {",
" Object local = provideStringProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -728,12 +732,12 @@
"",
" @Override",
" public Provider<CharSequence> charSequence() {",
- " return (Provider) stringProvider();",
+ " return (Provider) getStringProvider();",
" }",
"",
" @Override",
" public Provider<Object> object() {",
- " return (Provider) stringProvider();",
+ " return (Provider) getStringProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
@@ -794,7 +798,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(supertype, injectableSubtype, module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -805,7 +810,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerRequestsSubtypeAsProvider",
" implements RequestsSubtypeAsProvider {")
.addLinesIn(
@@ -819,7 +824,7 @@
FAST_INIT_MODE,
" private volatile Provider subtypeProvider;",
"",
- " private Provider subtypeProvider() {",
+ " private Provider getSubtypeProvider() {",
" Object local = subtypeProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -830,7 +835,7 @@
"",
" @Override",
" public Provider<Supertype> supertypeProvider() {",
- " return subtypeProvider();",
+ " return getSubtypeProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
@@ -883,10 +888,11 @@
"@Singleton",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
- " Provider<Object> object();",
+ " Provider<Object> getObject();",
"}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts())
+ Compilation compilation = daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -897,7 +903,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
@@ -913,7 +919,7 @@
" }",
"",
" @Override",
- " public Provider<Object> object() {",
+ " public Provider<Object> getObject() {",
" return bindStringProvider;",
" }",
"}")
@@ -923,7 +929,7 @@
" private volatile Object object = new MemoizedSentinel();",
" private volatile Provider<Object> bindStringProvider;",
"",
- " private String string() {",
+ " private String getString() {",
" Object local = string;",
" if (local == null) {",
" local = TestModule_ProvideStringFactory.provideString();",
@@ -932,13 +938,13 @@
" return (String) local;",
" }",
"",
- " private Object object2() {",
+ " private Object getObject2() {",
" Object local = object;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = object;",
" if (local instanceof MemoizedSentinel) {",
- " local = string();",
+ " local = getString();",
" object = DoubleCheck.reentrantCheck(object, local);",
" }",
" }",
@@ -947,7 +953,7 @@
" }",
"",
" @Override",
- " public Provider<Object> object() {",
+ " public Provider<Object> getObject() {",
" Object local = bindStringProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -961,7 +967,7 @@
" @Override",
" public T get() {",
" switch (id) {",
- " case 0: return (T) DaggerTestComponent.this.object2();",
+ " case 0: return (T) DaggerTestComponent.this.getObject2();",
" default: throw new AssertionError(id);",
" }",
" }",
@@ -971,7 +977,8 @@
private CompilationSubject assertThatCompilationWithModule(JavaFileObject module) {
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
module,
COMPONENT,
diff --git a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
index 22547b5..4a4e0a5 100644
--- a/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
+++ b/javatests/dagger/internal/codegen/DependencyCycleValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.endsWithMessage;
import static dagger.internal.codegen.TestUtils.message;
@@ -76,14 +75,14 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Outer.C is injected at",
- " Outer.A(cParam)",
- " Outer.A is injected at",
- " Outer.B(aParam)",
- " Outer.B is injected at",
- " Outer.C(bParam)",
- " Outer.C is requested at",
- " Outer.CComponent.getC()"))
+ " test.Outer.C is injected at",
+ " test.Outer.A(cParam)",
+ " test.Outer.A is injected at",
+ " test.Outer.B(aParam)",
+ " test.Outer.B is injected at",
+ " test.Outer.C(bParam)",
+ " test.Outer.C is provided at",
+ " test.Outer.CComponent.getC()"))
.inFile(SIMPLE_CYCLIC_DEPENDENCY)
.onLineContaining("interface CComponent");
@@ -93,28 +92,21 @@
@Test
public void cyclicDependencyWithModuleBindingValidation() {
// Cycle errors should not show a dependency trace to an entry point when doing full binding
- // graph validation. So ensure that the message doesn't end with "test.Outer.C is requested at
+ // graph validation. So ensure that the message doesn't end with "test.Outer.C is provided at
// test.Outer.CComponent.getC()", as the previous test's message does.
Pattern moduleBindingValidationError =
endsWithMessage(
"Found a dependency cycle:",
- " Outer.C is injected at",
- " Outer.A(cParam)",
- " Outer.A is injected at",
- " Outer.B(aParam)",
- " Outer.B is injected at",
- " Outer.C(bParam)",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "Outer: test.Outer",
- "========================",
- "End of classname legend:",
- "========================");
+ " test.Outer.C is injected at",
+ " test.Outer.A(cParam)",
+ " test.Outer.A is injected at",
+ " test.Outer.B(aParam)",
+ " test.Outer.B is injected at",
+ " test.Outer.C(bParam)");
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(SIMPLE_CYCLIC_DEPENDENCY);
assertThat(compilation).failed();
@@ -171,16 +163,16 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Outer.C is injected at",
- " Outer.A(cParam)",
- " Outer.A is injected at",
- " Outer.B(aParam)",
- " Outer.B is injected at",
- " Outer.C(bParam)",
- " Outer.C is injected at",
- " Outer.D(cParam)",
- " Outer.D is requested at",
- " Outer.DComponent.getD()"))
+ " test.Outer.C is injected at",
+ " test.Outer.A(cParam)",
+ " test.Outer.A is injected at",
+ " test.Outer.B(aParam)",
+ " test.Outer.B is injected at",
+ " test.Outer.C(bParam)",
+ " test.Outer.C is injected at",
+ " test.Outer.D(cParam)",
+ " test.Outer.D is provided at",
+ " test.Outer.DComponent.getD()"))
.inFile(component)
.onLineContaining("interface DComponent");
}
@@ -234,16 +226,16 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Outer.C is injected at",
- " Outer.CModule.c(c)",
- " Map<String,Outer.C> is injected at",
- " Outer.A(cMap)",
- " Outer.A is injected at",
- " Outer.B(aParam)",
- " Outer.B is injected at",
- " Outer.C(bParam)",
- " Outer.C is requested at",
- " Outer.CComponent.getC()"))
+ " test.Outer.C is injected at",
+ " test.Outer.CModule.c(c)",
+ " java.util.Map<java.lang.String,test.Outer.C> is injected at",
+ " test.Outer.A(cMap)",
+ " test.Outer.A is injected at",
+ " test.Outer.B(aParam)",
+ " test.Outer.B is injected at",
+ " test.Outer.C(bParam)",
+ " test.Outer.C is provided at",
+ " test.Outer.CComponent.getC()"))
.inFile(component)
.onLineContaining("interface CComponent");
}
@@ -295,16 +287,16 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Outer.C is injected at",
- " Outer.CModule.c(c)",
- " Set<Outer.C> is injected at",
- " Outer.A(cSet)",
- " Outer.A is injected at",
- " Outer.B(aParam)",
- " Outer.B is injected at",
- " Outer.C(bParam)",
- " Outer.C is requested at",
- " Outer.CComponent.getC()"))
+ " test.Outer.C is injected at",
+ " test.Outer.CModule.c(c)",
+ " java.util.Set<test.Outer.C> is injected at",
+ " test.Outer.A(cSet)",
+ " test.Outer.A is injected at",
+ " test.Outer.B(aParam)",
+ " test.Outer.B is injected at",
+ " test.Outer.C(bParam)",
+ " test.Outer.C is provided at",
+ " test.Outer.CComponent.getC()"))
.inFile(component)
.onLineContaining("interface CComponent");
}
@@ -351,16 +343,16 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Outer.C is injected at",
- " Outer.A(cParam)",
- " Outer.A is injected at",
- " Outer.B(aParam)",
- " Outer.B is injected at",
- " Outer.C(bParam)",
- " Provider<Outer.C> is injected at",
- " Outer.D(cParam)",
- " Outer.D is requested at",
- " Outer.DComponent.getD()"))
+ " test.Outer.C is injected at",
+ " test.Outer.A(cParam)",
+ " test.Outer.A is injected at",
+ " test.Outer.B(aParam)",
+ " test.Outer.B is injected at",
+ " test.Outer.C(bParam)",
+ " javax.inject.Provider<test.Outer.C> is injected at",
+ " test.Outer.D(cParam)",
+ " test.Outer.D is provided at",
+ " test.Outer.DComponent.getD()"))
.inFile(component)
.onLineContaining("interface DComponent");
}
@@ -435,12 +427,12 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " String is injected at",
- " CycleModule.object(string)",
- " Object is injected at",
- " CycleModule.string(object)",
- " String is requested at",
- " Grandchild.entry()"))
+ " java.lang.String is injected at",
+ " test.CycleModule.object(string)",
+ " java.lang.Object is injected at",
+ " test.CycleModule.string(object)",
+ " java.lang.String is provided at",
+ " test.Grandchild.entry()"))
.inFile(parent)
.onLineContaining("interface Parent");
}
@@ -517,12 +509,12 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " String is injected at",
- " CycleModule.object(string)",
- " Object is injected at",
- " CycleModule.string(object)",
- " String is requested at",
- " Child.entry() [Parent → Child]"))
+ " java.lang.String is injected at",
+ " test.CycleModule.object(string)",
+ " java.lang.Object is injected at",
+ " test.CycleModule.string(object)",
+ " java.lang.String is provided at",
+ " test.Child.entry() [test.Parent → test.Child]"))
.inFile(parent)
.onLineContaining("interface Parent");
}
@@ -568,12 +560,12 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Object is injected at",
- " TestModule.bindQualified(unqualified)",
- " @SomeQualifier Object is injected at",
- " TestModule.bindUnqualified(qualified)",
- " Object is requested at",
- " TestComponent.unqualified()"))
+ " java.lang.Object is injected at",
+ " test.TestModule.bindQualified(unqualified)",
+ " @test.SomeQualifier java.lang.Object is injected at",
+ " test.TestModule.bindUnqualified(qualified)",
+ " java.lang.Object is provided at",
+ " test.TestComponent.unqualified()"))
.inFile(component)
.onLineContaining("interface TestComponent");
}
@@ -610,10 +602,10 @@
.hadErrorContaining(
message(
"Found a dependency cycle:",
- " Object is injected at",
- " TestModule.bindToSelf(sameKey)",
- " Object is requested at",
- " TestComponent.selfReferential()"))
+ " java.lang.Object is injected at",
+ " test.TestModule.bindToSelf(sameKey)",
+ " java.lang.Object is provided at",
+ " test.TestComponent.selfReferential()"))
.inFile(component)
.onLineContaining("interface TestComponent");
}
@@ -667,7 +659,7 @@
" test.B is injected at",
" test.A.b",
" test.A is injected at",
- " CycleComponent.inject(test.A)"))
+ " test.CycleComponent.inject(test.A)"))
.inFile(component)
.onLineContaining("interface CycleComponent");
}
diff --git a/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java b/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java
index 9b0dde0..a2da92f 100644
--- a/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java
+++ b/javatests/dagger/internal/codegen/DiagnosticFormattingTest.java
@@ -18,7 +18,6 @@
import static com.google.common.truth.Truth.assertThat;
-import dagger.internal.codegen.base.DiagnosticFormatting;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
diff --git a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
index fbda59d..14a6fb9 100644
--- a/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
+++ b/javatests/dagger/internal/codegen/DuplicateBindingsValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.message;
import static org.junit.Assume.assumeFalse;
@@ -83,16 +82,14 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Outer.A is bound multiple times:",
- " @Provides Outer.A Outer.AModule.provideA(String)",
- " Outer.A Outer.Parent.getA()"))
+ "test.Outer.A is bound multiple times:",
+ " @Provides test.Outer.A test.Outer.AModule.provideA(String)",
+ " test.Outer.A test.Outer.Parent.getA()"))
.inFile(component)
.onLineContaining("interface Child");
}
@@ -137,16 +134,14 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Outer.A is bound multiple times:",
- " @Provides Outer.A Outer.Module1.provideA1()",
- " @Provides Outer.A Outer.Module2.provideA2(String)"))
+ "test.Outer.A is bound multiple times:",
+ " @Provides test.Outer.A test.Outer.Module1.provideA1()",
+ " @Provides test.Outer.A test.Outer.Module2.provideA2(String)"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -154,9 +149,9 @@
assertThat(compilation)
.hadErrorContaining(
message(
- "Outer.A is bound multiple times:",
- " @Provides Outer.A Outer.Module1.provideA1()",
- " @Provides Outer.A Outer.Module2.provideA2(String)"))
+ "test.Outer.A is bound multiple times:",
+ " @Provides test.Outer.A test.Outer.Module1.provideA1()",
+ " @Provides test.Outer.A test.Outer.Module2.provideA2(String)"))
.inFile(component)
.onLineContaining("class Module3");
}
@@ -205,16 +200,14 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Outer.A is bound multiple times:",
- " @Provides Outer.A Outer.Module1.provideA1()",
- " @Binds Outer.A Outer.Module2.bindA2(Outer.B)"))
+ "test.Outer.A is bound multiple times:",
+ " @Provides test.Outer.A test.Outer.Module1.provideA1()",
+ " @Binds test.Outer.A test.Outer.Module2.bindA2(test.Outer.B)"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -222,9 +215,9 @@
assertThat(compilation)
.hadErrorContaining(
message(
- "Outer.A is bound multiple times:",
- " @Provides Outer.A Outer.Module1.provideA1()",
- " @Binds Outer.A Outer.Module2.bindA2(Outer.B)"))
+ "test.Outer.A is bound multiple times:",
+ " @Provides test.Outer.A test.Outer.Module1.provideA1()",
+ " @Binds test.Outer.A test.Outer.Module2.bindA2(test.Outer.B)"))
.inFile(component)
.onLineContaining("class Module3");
}
@@ -275,22 +268,20 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Set<String> has incompatible bindings or declarations:",
+ "java.util.Set<java.lang.String> has incompatible bindings or declarations:",
" Set bindings and declarations:",
- " @Binds @IntoSet String "
- + "Outer.TestModule1.bindStringSetElement(@Outer.SomeQualifier "
+ " @Binds @dagger.multibindings.IntoSet String "
+ + "test.Outer.TestModule1.bindStringSetElement(@test.Outer.SomeQualifier "
+ "String)",
- " @Provides @IntoSet String "
- + "Outer.TestModule1.stringSetElement()",
+ " @Provides @dagger.multibindings.IntoSet String "
+ + "test.Outer.TestModule1.stringSetElement()",
" Unique bindings and declarations:",
- " @Provides Set<String> Outer.TestModule2.stringSet()"))
+ " @Provides Set<String> test.Outer.TestModule2.stringSet()"))
.inFile(component)
.onLineContaining(
fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
@@ -346,23 +337,23 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Map<String,String> has incompatible bindings "
+ "java.util.Map<java.lang.String,java.lang.String> has incompatible bindings "
+ "or declarations:",
" Map bindings and declarations:",
- " @Binds @IntoMap @StringKey(\"bar\") String"
- + " Outer.TestModule1.bindStringMapEntry(@Outer.SomeQualifier "
+ " @Binds @dagger.multibindings.IntoMap "
+ + "@dagger.multibindings.StringKey(\"bar\") String"
+ + " test.Outer.TestModule1.bindStringMapEntry(@test.Outer.SomeQualifier "
+ "String)",
- " @Provides @IntoMap @StringKey(\"foo\") String"
- + " Outer.TestModule1.stringMapEntry()",
+ " @Provides @dagger.multibindings.IntoMap "
+ + "@dagger.multibindings.StringKey(\"foo\") String"
+ + " test.Outer.TestModule1.stringMapEntry()",
" Unique bindings and declarations:",
- " @Provides Map<String,String> Outer.TestModule2.stringMap()"))
+ " @Provides Map<String,String> test.Outer.TestModule2.stringMap()"))
.inFile(component)
.onLineContaining(
fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
@@ -403,19 +394,17 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Set<String> has incompatible bindings or declarations:",
+ "java.util.Set<java.lang.String> has incompatible bindings or declarations:",
" Set bindings and declarations:",
- " @Multibinds Set<String> "
- + "Outer.TestModule1.stringSet()",
+ " @dagger.multibindings.Multibinds Set<String> "
+ + "test.Outer.TestModule1.stringSet()",
" Unique bindings and declarations:",
- " @Provides Set<String> Outer.TestModule2.stringSet()"))
+ " @Provides Set<String> test.Outer.TestModule2.stringSet()"))
.inFile(component)
.onLineContaining(
fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
@@ -458,20 +447,18 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Map<String,String> has incompatible bindings "
+ "java.util.Map<java.lang.String,java.lang.String> has incompatible bindings "
+ "or declarations:",
" Map bindings and declarations:",
- " @Multibinds Map<String,String> "
- + "Outer.TestModule1.stringMap()",
+ " @dagger.multibindings.Multibinds Map<String,String> "
+ + "test.Outer.TestModule1.stringMap()",
" Unique bindings and declarations:",
- " @Provides Map<String,String> Outer.TestModule2.stringMap()"))
+ " @Provides Map<String,String> test.Outer.TestModule2.stringMap()"))
.inFile(component)
.onLineContaining(
fullBindingGraphValidation ? "class TestModule3" : "interface TestComponent");
@@ -587,24 +574,22 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
- .compile(component);
+ daggerCompiler().withOptions(fullBindingGraphValidationOption()).compile(component);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Outer.A is bound multiple times:",
- " @Provides Outer.A Outer.Module01.provideA()",
- " @Provides Outer.A Outer.Module02.provideA()",
- " @Provides Outer.A Outer.Module03.provideA()",
- " @Provides Outer.A Outer.Module04.provideA()",
- " @Provides Outer.A Outer.Module05.provideA()",
- " @Provides Outer.A Outer.Module06.provideA()",
- " @Provides Outer.A Outer.Module07.provideA()",
- " @Provides Outer.A Outer.Module08.provideA()",
- " @Provides Outer.A Outer.Module09.provideA()",
- " @Provides Outer.A Outer.Module10.provideA()",
+ "test.Outer.A is bound multiple times:",
+ " @Provides test.Outer.A test.Outer.Module01.provideA()",
+ " @Provides test.Outer.A test.Outer.Module02.provideA()",
+ " @Provides test.Outer.A test.Outer.Module03.provideA()",
+ " @Provides test.Outer.A test.Outer.Module04.provideA()",
+ " @Provides test.Outer.A test.Outer.Module05.provideA()",
+ " @Provides test.Outer.A test.Outer.Module06.provideA()",
+ " @Provides test.Outer.A test.Outer.Module07.provideA()",
+ " @Provides test.Outer.A test.Outer.Module08.provideA()",
+ " @Provides test.Outer.A test.Outer.Module09.provideA()",
+ " @Provides test.Outer.A test.Outer.Module10.provideA()",
" and 2 others"))
.inFile(component)
.onLineContaining(fullBindingGraphValidation ? "class Modules" : "interface TestComponent");
@@ -661,14 +646,14 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
+ daggerCompiler()
+ .withOptions(fullBindingGraphValidationOption())
.compile(aComponent, bComponent);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Object is bound multiple times:",
+ "java.lang.Object is bound multiple times:",
" @Provides Object test.A.AModule.abConflict()",
" @Provides Object test.B.BModule.abConflict()"))
.inFile(aComponent)
@@ -742,14 +727,14 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
+ daggerCompiler()
+ .withOptions(fullBindingGraphValidationOption())
.compile(aComponent, bComponent, cComponent);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Object is bound multiple times:",
+ "java.lang.Object is bound multiple times:",
" @Provides Object test.A.AModule.acConflict()",
" @Provides Object test.C.CModule.acConflict()"))
.inFile(aComponent)
@@ -818,14 +803,14 @@
"}");
Compilation compilation =
- compilerWithOptions(
- fullBindingGraphValidationOption())
+ daggerCompiler()
+ .withOptions(fullBindingGraphValidationOption())
.compile(aComponent, bComponent, cComponent);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Object is bound multiple times:",
+ "java.lang.Object is bound multiple times:",
" @Provides Object test.B.BModule.bcConflict()",
" @Provides Object test.C.CModule.bcConflict()"))
.inFile(fullBindingGraphValidation ? bComponent : aComponent)
@@ -948,10 +933,10 @@
assertThat(compilation)
.hadWarningContaining(
message(
- "Foo is bound multiple times:",
- " @Inject Foo(Set<String>) [Injected1]",
- " @Provides Foo Provided1.Provided1Module.provideFoo(Set<String>) "
- + "[Injected1 → Injected2 → Provided1]"))
+ "test.Foo is bound multiple times:",
+ " @Inject test.Foo(Set<String>) [test.Injected1]",
+ " @Provides test.Foo test.Provided1.Provided1Module.provideFoo(Set<String>) "
+ + "[test.Injected1 → test.Injected2 → test.Provided1]"))
.inFile(injected1)
.onLineContaining("interface Injected1 {");
}
@@ -1006,18 +991,17 @@
"}");
Compilation compilation =
- compilerWithOptions(
- "-Adagger.nullableValidation=WARNING",
- fullBindingGraphValidationOption())
+ daggerCompiler()
+ .withOptions("-Adagger.nullableValidation=WARNING", fullBindingGraphValidationOption())
.compile(parentConflictsWithChild, child);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
message(
- "Object is bound multiple times:",
- " @Provides Object Child.ChildModule.nonNullableParentChildConflict()",
- " @Provides @Nullable Object"
- + " ParentConflictsWithChild.ParentModule.nullableParentChildConflict()"))
+ "java.lang.Object is bound multiple times:",
+ " @Provides Object test.Child.ChildModule.nonNullableParentChildConflict()",
+ " @Provides @javax.annotation.Nullable Object"
+ + " test.ParentConflictsWithChild.ParentModule.nullableParentChildConflict()"))
.inFile(parentConflictsWithChild)
.onLineContaining(
fullBindingGraphValidation
@@ -1091,7 +1075,7 @@
Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("String is bound multiple times")
+ .hadErrorContaining("java.lang.String is bound multiple times")
.inFile(parent)
.onLineContaining("interface Parent");
assertThat(compilation).hadErrorCount(1);
diff --git a/javatests/dagger/internal/codegen/ElementDescriptorsTest.java b/javatests/dagger/internal/codegen/ElementDescriptorsTest.java
deleted file mode 100644
index e97e360..0000000
--- a/javatests/dagger/internal/codegen/ElementDescriptorsTest.java
+++ /dev/null
@@ -1,239 +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.internal.codegen;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.testing.compile.CompilationRule;
-import dagger.internal.codegen.langmodel.DaggerElements;
-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/internal/codegen/TestDataClass;)V",
- "method2()Ldagger/internal/codegen/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/internal/codegen/TestDataClass;)V",
- "method2()[Ldagger/internal/codegen/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/internal/codegen/TestDataClass$MemberInnerData;)V",
- "method2(Ldagger/internal/codegen/TestDataClass$StaticInnerData;)V",
- "method3(Ldagger/internal/codegen/TestDataClass$EnumData;)V",
- "method4()Ldagger/internal/codegen/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(DaggerElements::getFieldDescriptor)
- .collect(Collectors.toSet());
- }
-
- private Set<String> getMethodDescriptors(String className) {
- TypeElement testElement = compilation.getElements().getTypeElement(className);
- return ElementFilter.methodsIn(testElement.getEnclosedElements()).stream()
- .map(DaggerElements::getMethodDescriptor)
- .collect(Collectors.toSet());
- }
-}
-
-@SuppressWarnings("ClassCanBeStatic")
-class TestDataClass {
- class MemberInnerData {}
-
- static class StaticInnerData {}
-
- enum EnumData {
- VALUE1,
- VALUE2
- }
-}
diff --git a/javatests/dagger/internal/codegen/ElidedFactoriesTest.java b/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
index 6857039..58ddb82 100644
--- a/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
+++ b/javatests/dagger/internal/codegen/ElidedFactoriesTest.java
@@ -17,8 +17,8 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
@@ -84,7 +84,7 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private DaggerSimpleComponent() {}",
"",
@@ -112,7 +112,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(injectedType, dependsOnInjected, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -184,7 +185,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private volatile Object scopedType = new MemoizedSentinel();",
" private volatile Provider<DependsOnScoped> dependsOnScopedProvider;",
@@ -199,7 +200,7 @@
" return new Builder().build();",
" }",
"",
- " private ScopedType scopedType() {",
+ " private ScopedType getScopedType() {",
" Object local = scopedType;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -213,11 +214,11 @@
" return (ScopedType) local;",
" }",
"",
- " private DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(scopedType());",
+ " private DependsOnScoped getDependsOnScoped() {",
+ " return new DependsOnScoped(getScopedType());",
" }",
"",
- " private Provider<DependsOnScoped> dependsOnScopedProvider() {",
+ " private Provider<DependsOnScoped> getDependsOnScopedProvider() {",
" Object local = dependsOnScopedProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -228,7 +229,7 @@
"",
" @Override",
" public NeedsProvider needsProvider() {",
- " return new NeedsProvider(dependsOnScopedProvider());",
+ " return new NeedsProvider(getDependsOnScopedProvider());",
" }",
"",
" static final class Builder {",
@@ -249,7 +250,7 @@
" @Override",
" public T get() {",
" switch (id) {",
- " case 0: return (T) DaggerSimpleComponent.this.dependsOnScoped();",
+ " case 0: return (T) DaggerSimpleComponent.this.getDependsOnScoped();",
" default: throw new AssertionError(id);",
" }",
" }",
@@ -266,7 +267,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private Provider<ScopedType> scopedTypeProvider;",
" private Provider<DependsOnScoped> dependsOnScopedProvider;",
@@ -306,7 +307,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(scopedType, dependsOnScoped, componentFile, needsProvider);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -377,7 +379,7 @@
"import dagger.internal.MemoizedSentinel;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private volatile Object scopedType = new MemoizedSentinel();",
"",
@@ -391,7 +393,7 @@
" return new Builder().build();",
" }",
"",
- " private ScopedType scopedType() {",
+ " private ScopedType getScopedType() {",
" Object local = scopedType;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -423,7 +425,7 @@
"",
" @Override",
" public DependsOnScoped dependsOnScoped() {",
- " return new DependsOnScoped(DaggerSimpleComponent.this.scopedType());",
+ " return new DependsOnScoped(DaggerSimpleComponent.this.getScopedType());",
" }",
" }",
"}");
@@ -438,7 +440,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerSimpleComponent implements SimpleComponent {",
" private Provider<ScopedType> scopedTypeProvider;",
"",
@@ -484,7 +486,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(scopedType, dependsOnScoped, componentFile, subcomponentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
diff --git a/javatests/dagger/internal/codegen/FrameworkFieldTest.java b/javatests/dagger/internal/codegen/FrameworkFieldTest.java
index be495d7..cbc8c03 100644
--- a/javatests/dagger/internal/codegen/FrameworkFieldTest.java
+++ b/javatests/dagger/internal/codegen/FrameworkFieldTest.java
@@ -24,7 +24,6 @@
import com.google.testing.compile.CompilationRule;
import com.squareup.javapoet.ClassName;
-import dagger.internal.codegen.binding.FrameworkField;
import javax.inject.Inject;
import org.junit.Before;
import org.junit.Rule;
diff --git a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
index e27534d..3e6e3ad 100644
--- a/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
+++ b/javatests/dagger/internal/codegen/FrameworkTypeMapperTest.java
@@ -23,8 +23,6 @@
import static dagger.model.RequestKind.PRODUCER;
import static dagger.model.RequestKind.PROVIDER;
-import dagger.internal.codegen.binding.FrameworkType;
-import dagger.internal.codegen.binding.FrameworkTypeMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
diff --git a/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java b/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java
index b56bc04..944e307 100644
--- a/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java
+++ b/javatests/dagger/internal/codegen/FullBindingGraphValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.endsWithMessage;
@@ -49,35 +48,9 @@
// Make sure the error doesn't show other bindings or a dependency trace afterwards.
private static final Pattern MODULE_WITH_ERRORS_MESSAGE =
endsWithMessage(
- "\033[1;31m[Dagger/DuplicateBindings]\033[0m Object is bound multiple times:",
- " @Binds Object ModuleWithErrors.object1(String)",
- " @Binds Object ModuleWithErrors.object2(Long)",
- " in component: [ModuleWithErrors]",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "ModuleWithErrors: test.ModuleWithErrors",
- "========================",
- "End of classname legend:",
- "========================");
-
- private static final Pattern INCLUDES_MODULE_WITH_ERRORS_MESSAGE =
- endsWithMessage(
- "\033[1;31m[Dagger/DuplicateBindings]\033[0m Object is bound multiple times:",
- " @Binds Object ModuleWithErrors.object1(String)",
- " @Binds Object ModuleWithErrors.object2(Long)",
- " in component: [IncludesModuleWithErrors]",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "IncludesModuleWithErrors: test.IncludesModuleWithErrors",
- "ModuleWithErrors: test.ModuleWithErrors",
- "========================",
- "End of classname legend:",
- "========================");
-
+ "[Dagger/DuplicateBindings] java.lang.Object is bound multiple times:",
+ " @Binds Object test.ModuleWithErrors.object1(String)",
+ " @Binds Object test.ModuleWithErrors.object2(Long)");
@Test
public void moduleWithErrors_validationTypeNone() {
@@ -88,7 +61,8 @@
@Test
public void moduleWithErrors_validationTypeError() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(MODULE_WITH_ERRORS);
assertThat(compilation).failed();
@@ -104,7 +78,8 @@
@Test
public void moduleWithErrors_validationTypeWarning() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=WARNING")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
.compile(MODULE_WITH_ERRORS);
assertThat(compilation).succeeded();
@@ -138,7 +113,8 @@
@Test
public void includesModuleWithErrors_validationTypeError() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(MODULE_WITH_ERRORS, INCLUDES_MODULE_WITH_ERRORS);
assertThat(compilation).failed();
@@ -149,7 +125,7 @@
.onLineContaining("interface ModuleWithErrors");
assertThat(compilation)
- .hadErrorContainingMatch("ModuleWithErrors has errors")
+ .hadErrorContainingMatch("test.ModuleWithErrors has errors")
.inFile(INCLUDES_MODULE_WITH_ERRORS)
.onLineContaining("ModuleWithErrors.class");
@@ -159,7 +135,8 @@
@Test
public void includesModuleWithErrors_validationTypeWarning() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=WARNING")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
.compile(MODULE_WITH_ERRORS, INCLUDES_MODULE_WITH_ERRORS);
assertThat(compilation).succeeded();
@@ -171,7 +148,7 @@
// TODO(b/130284666)
assertThat(compilation)
- .hadWarningContainingMatch(INCLUDES_MODULE_WITH_ERRORS_MESSAGE)
+ .hadWarningContainingMatch(MODULE_WITH_ERRORS_MESSAGE)
.inFile(INCLUDES_MODULE_WITH_ERRORS)
.onLineContaining("interface IncludesModuleWithErrors");
@@ -207,19 +184,9 @@
// Make sure the error doesn't show other bindings or a dependency trace afterwards.
private static final Pattern COMBINED_WITH_A_MODULE_HAS_ERRORS_MESSAGE =
endsWithMessage(
- "\033[1;31m[Dagger/DuplicateBindings]\033[0m Object is bound multiple times:",
- " @Binds Object AModule.object(String)",
- " @Binds Object CombinedWithAModuleHasErrors.object(Long)",
- " in component: [CombinedWithAModuleHasErrors]",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "AModule: test.AModule",
- "CombinedWithAModuleHasErrors: test.CombinedWithAModuleHasErrors",
- "========================",
- "End of classname legend:",
- "========================");
+ "[Dagger/DuplicateBindings] java.lang.Object is bound multiple times:",
+ " @Binds Object test.AModule.object(String)",
+ " @Binds Object test.CombinedWithAModuleHasErrors.object(Long)");
@Test
public void moduleIncludingModuleWithCombinedErrors_validationTypeNone() {
@@ -231,7 +198,8 @@
@Test
public void moduleIncludingModuleWithCombinedErrors_validationTypeError() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(A_MODULE, COMBINED_WITH_A_MODULE_HAS_ERRORS);
assertThat(compilation).failed();
@@ -247,7 +215,8 @@
@Test
public void moduleIncludingModuleWithCombinedErrors_validationTypeWarning() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=WARNING")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
.compile(A_MODULE, COMBINED_WITH_A_MODULE_HAS_ERRORS);
assertThat(compilation).succeeded();
@@ -280,38 +249,10 @@
// Make sure the error doesn't show other bindings or a dependency trace afterwards.
private static final Pattern SUBCOMPONENT_WITH_ERRORS_MESSAGE =
endsWithMessage(
- "\033[1;31m[Dagger/DuplicateBindings]\033[0m Object is bound multiple times:",
- " @Binds Object AModule.object(String)",
- " @BindsInstance SubcomponentWithErrors.Builder"
- + " SubcomponentWithErrors.Builder.object(Object)",
- " in component: [SubcomponentWithErrors]",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "AModule: test.AModule",
- "SubcomponentWithErrors: test.SubcomponentWithErrors",
- "========================",
- "End of classname legend:",
- "========================");
-
- private static final Pattern MODULE_WITH_SUBCOMPONENT_WITH_ERRORS_MESSAGE =
- endsWithMessage(
- "\033[1;31m[Dagger/DuplicateBindings]\033[0m Object is bound multiple times:",
- " @Binds Object AModule.object(String)",
- " @BindsInstance SubcomponentWithErrors.Builder"
- + " SubcomponentWithErrors.Builder.object(Object)",
- " in component: [ModuleWithSubcomponentWithErrors → SubcomponentWithErrors]",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "AModule: test.AModule",
- "ModuleWithSubcomponentWithErrors: test.ModuleWithSubcomponentWithErrors",
- "SubcomponentWithErrors: test.SubcomponentWithErrors",
- "========================",
- "End of classname legend:",
- "========================");
+ "[Dagger/DuplicateBindings] java.lang.Object is bound multiple times:",
+ " @Binds Object test.AModule.object(String)",
+ " @BindsInstance test.SubcomponentWithErrors.Builder"
+ + " test.SubcomponentWithErrors.Builder.object(Object)");
@Test
public void subcomponentWithErrors_validationTypeNone() {
@@ -323,7 +264,8 @@
@Test
public void subcomponentWithErrors_validationTypeError() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(SUBCOMPONENT_WITH_ERRORS, A_MODULE);
assertThat(compilation).failed();
@@ -339,7 +281,8 @@
@Test
public void subcomponentWithErrors_validationTypeWarning() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=WARNING")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
.compile(SUBCOMPONENT_WITH_ERRORS, A_MODULE);
assertThat(compilation).succeeded();
@@ -375,13 +318,14 @@
@Test
public void moduleWithSubcomponentWithErrors_validationTypeError() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS, SUBCOMPONENT_WITH_ERRORS, A_MODULE);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContainingMatch(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS_MESSAGE)
+ .hadErrorContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
.inFile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS)
.onLineContaining("interface ModuleWithSubcomponentWithErrors");
@@ -397,13 +341,14 @@
@Test
public void moduleWithSubcomponentWithErrors_validationTypeWarning() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=WARNING")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
.compile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS, SUBCOMPONENT_WITH_ERRORS, A_MODULE);
assertThat(compilation).succeeded();
assertThat(compilation)
- .hadWarningContainingMatch(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS_MESSAGE)
+ .hadWarningContainingMatch(SUBCOMPONENT_WITH_ERRORS_MESSAGE)
.inFile(MODULE_WITH_SUBCOMPONENT_WITH_ERRORS)
.onLineContaining("interface ModuleWithSubcomponentWithErrors");
@@ -448,20 +393,9 @@
// Make sure the error doesn't show other bindings or a dependency trace afterwards.
private static final Pattern COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS_MESSAGE =
endsWithMessage(
- "\033[1;31m[Dagger/DuplicateBindings]\033[0m Object is bound multiple times:",
- " @Binds Object AModule.object(String)",
- " @Binds Object CombinedWithASubcomponentHasErrors.object(Number)",
- " in component: [CombinedWithASubcomponentHasErrors → ASubcomponent]",
- "",
- "======================",
- "Full classname legend:",
- "======================",
- "AModule: test.AModule",
- "ASubcomponent: test.ASubcomponent",
- "CombinedWithASubcomponentHasErrors: test.CombinedWithASubcomponentHasErrors",
- "========================",
- "End of classname legend:",
- "========================");
+ "[Dagger/DuplicateBindings] java.lang.Object is bound multiple times:",
+ " @Binds Object test.AModule.object(String)",
+ " @Binds Object test.CombinedWithASubcomponentHasErrors.object(Number)");
@Test
public void moduleWithSubcomponentWithCombinedErrors_validationTypeNone() {
@@ -474,7 +408,8 @@
@Test
public void moduleWithSubcomponentWithCombinedErrors_validationTypeError() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS, A_SUBCOMPONENT, A_MODULE);
assertThat(compilation).failed();
@@ -490,7 +425,8 @@
@Test
public void moduleWithSubcomponentWithCombinedErrors_validationTypeWarning() {
Compilation compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=WARNING")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=WARNING")
.compile(COMBINED_WITH_A_SUBCOMPONENT_HAS_ERRORS, A_SUBCOMPONENT, A_MODULE);
assertThat(compilation).succeeded();
@@ -506,7 +442,8 @@
@Test
public void bothAliasesDifferentValues() {
Compilation compilation =
- compilerWithOptions(
+ daggerCompiler()
+ .withOptions(
"-Adagger.moduleBindingValidation=NONE",
"-Adagger.fullBindingGraphValidation=ERROR")
.compile(MODULE_WITH_ERRORS);
@@ -525,7 +462,8 @@
@Test
public void bothAliasesSameValue() {
Compilation compilation =
- compilerWithOptions(
+ daggerCompiler()
+ .withOptions(
"-Adagger.moduleBindingValidation=NONE", "-Adagger.fullBindingGraphValidation=NONE")
.compile(MODULE_WITH_ERRORS);
diff --git a/javatests/dagger/internal/codegen/GeneratedLines.java b/javatests/dagger/internal/codegen/GeneratedLines.java
index f9a1b70..2aa17ac 100644
--- a/javatests/dagger/internal/codegen/GeneratedLines.java
+++ b/javatests/dagger/internal/codegen/GeneratedLines.java
@@ -16,7 +16,9 @@
package dagger.internal.codegen;
-import com.google.common.base.Joiner;
+import static dagger.internal.codegen.javapoet.CodeBlocks.stringLiteral;
+
+import com.squareup.javapoet.CodeBlock;
/**
* Common lines outputted during code generation.
@@ -27,12 +29,6 @@
+ "value = \"dagger.internal.codegen.ComponentProcessor\", "
+ "comments = \"https://dagger.dev\")";
- private static final String SUPPRESS_WARNINGS_ANNOTATION =
- "@SuppressWarnings({\"unchecked\", \"rawtypes\"})";
-
- public static final String GENERATED_CODE_ANNOTATIONS =
- Joiner.on('\n').join(GENERATED_ANNOTATION, SUPPRESS_WARNINGS_ANNOTATION);
-
public static final String IMPORT_GENERATED_ANNOTATION =
isBeforeJava9()
? "import javax.annotation.Generated;"
@@ -48,4 +44,10 @@
return true;
}
}
+
+ public static final CodeBlock NPE_FROM_PROVIDES_METHOD =
+ stringLiteral("Cannot return null from a non-@Nullable @Provides method");
+
+ public static final CodeBlock NPE_FROM_COMPONENT_METHOD =
+ stringLiteral("Cannot return null from a non-@Nullable component method");
}
diff --git a/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
index 579e87a..e6e9706 100644
--- a/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/InjectConstructorFactoryGeneratorTest.java
@@ -20,9 +20,8 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.common.collect.ImmutableList;
@@ -138,7 +137,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
" private final Provider<T> tProvider;",
"",
@@ -148,7 +147,7 @@
"",
" @Override",
" public GenericClass<T> get() {",
- " return newInstance(tProvider.get());",
+ " return new GenericClass<T>(tProvider.get());",
" }",
"",
" public static <T> GenericClass_Factory<T> create(Provider<T> tProvider) {",
@@ -187,9 +186,8 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
- "public final class GenericClass_Factory<A, B> implements",
- " Factory<GenericClass<A, B>> {",
+ GENERATED_ANNOTATION,
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
" private final Provider<A> aProvider;",
" private final Provider<B> bProvider;",
"",
@@ -201,7 +199,7 @@
"",
" @Override",
" public GenericClass<A, B> get() {",
- " GenericClass<A, B> instance = newInstance();",
+ " GenericClass<A, B> instance = new GenericClass<A, B>();",
" GenericClass_MembersInjector.injectA(instance, aProvider.get());",
" GenericClass_MembersInjector.injectRegister(instance, bProvider.get());",
" return instance;",
@@ -239,26 +237,24 @@
"import dagger.internal.Factory;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class GenericClass_Factory<T> implements Factory<GenericClass<T>> {",
+ " @SuppressWarnings(\"rawtypes\")",
+ " private static final GenericClass_Factory INSTANCE = new GenericClass_Factory();",
+ "",
" @Override",
" public GenericClass<T> get() {",
- " return newInstance();",
+ " return new GenericClass<T>();",
" }",
"",
" @SuppressWarnings(\"unchecked\")",
" public static <T> GenericClass_Factory<T> create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static <T> GenericClass<T> newInstance() {",
" return new GenericClass<T>();",
" }",
- "",
- " private static final class InstanceHolder {",
- " @SuppressWarnings(\"rawtypes\")",
- " private static final GenericClass_Factory INSTANCE = new GenericClass_Factory();",
- " }",
"}");
assertAbout(javaSource()).that(file)
.processedWith(new ComponentProcessor())
@@ -284,9 +280,8 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
- "public final class GenericClass_Factory<A, B>",
- " implements Factory<GenericClass<A, B>> {",
+ GENERATED_ANNOTATION,
+ "public final class GenericClass_Factory<A, B> implements Factory<GenericClass<A, B>> {",
" private final Provider<A> aProvider;",
" private final Provider<B> bProvider;",
"",
@@ -297,7 +292,7 @@
"",
" @Override",
" public GenericClass<A, B> get() {",
- " return newInstance(aProvider.get(), bProvider.get());",
+ " return new GenericClass<A, B>(aProvider.get(), bProvider.get());",
" }",
"",
" public static <A, B> GenericClass_Factory<A, B> create(",
@@ -337,7 +332,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class GenericClass_Factory<A extends Number & Comparable<A>,",
" B extends List<? extends String>,",
" C extends List<? super String>>",
@@ -356,7 +351,8 @@
"",
" @Override",
" public GenericClass<A, B, C> get() {",
- " return newInstance(aProvider.get(), bProvider.get(), cProvider.get());",
+ " return new GenericClass<A, B, C>(",
+ " aProvider.get(), bProvider.get(), cProvider.get());",
" }",
"",
" public static <A extends Number & Comparable<A>,",
@@ -405,110 +401,64 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class GenericClass_Factory<A, B>",
" implements Factory<GenericClass<A, B>> {",
- " private final Provider<A> aProvider;",
- " private final Provider<A> a2Provider;",
- " private final Provider<A> paProvider;",
+ " private final Provider<A> aAndA2AndPaAndLaProvider;",
" private final Provider<A> qaProvider;",
- " private final Provider<A> laProvider;",
- " private final Provider<String> sProvider;",
- " private final Provider<String> s2Provider;",
- " private final Provider<String> psProvider;",
+ " private final Provider<String> sAndS2AndPsAndLsProvider;",
" private final Provider<String> qsProvider;",
- " private final Provider<String> lsProvider;",
- " private final Provider<B> bProvider;",
- " private final Provider<B> b2Provider;",
- " private final Provider<B> pbProvider;",
+ " private final Provider<B> bAndB2AndPbAndLbProvider;",
" private final Provider<B> qbProvider;",
- " private final Provider<B> lbProvider;",
"",
- " public GenericClass_Factory(",
- " Provider<A> aProvider,",
- " Provider<A> a2Provider,",
- " Provider<A> paProvider,",
+ " public GenericClass_Factory(Provider<A> aAndA2AndPaAndLaProvider,",
" Provider<A> qaProvider,",
- " Provider<A> laProvider,",
- " Provider<String> sProvider,",
- " Provider<String> s2Provider,",
- " Provider<String> psProvider,",
+ " Provider<String> sAndS2AndPsAndLsProvider,",
" Provider<String> qsProvider,",
- " Provider<String> lsProvider,",
- " Provider<B> bProvider,",
- " Provider<B> b2Provider,",
- " Provider<B> pbProvider,",
- " Provider<B> qbProvider,",
- " Provider<B> lbProvider) {",
- " this.aProvider = aProvider;",
- " this.a2Provider = a2Provider;",
- " this.paProvider = paProvider;",
+ " Provider<B> bAndB2AndPbAndLbProvider,",
+ " Provider<B> qbProvider) {",
+ " this.aAndA2AndPaAndLaProvider = aAndA2AndPaAndLaProvider;",
" this.qaProvider = qaProvider;",
- " this.laProvider = laProvider;",
- " this.sProvider = sProvider;",
- " this.s2Provider = s2Provider;",
- " this.psProvider = psProvider;",
+ " this.sAndS2AndPsAndLsProvider = sAndS2AndPsAndLsProvider;",
" this.qsProvider = qsProvider;",
- " this.lsProvider = lsProvider;",
- " this.bProvider = bProvider;",
- " this.b2Provider = b2Provider;",
- " this.pbProvider = pbProvider;",
+ " this.bAndB2AndPbAndLbProvider = bAndB2AndPbAndLbProvider;",
" this.qbProvider = qbProvider;",
- " this.lbProvider = lbProvider;",
" }",
"",
" @Override",
" public GenericClass<A, B> get() {",
- " return newInstance(",
- " aProvider.get(),",
- " a2Provider.get(),",
- " paProvider,",
- " qaProvider.get(),",
- " DoubleCheck.lazy(laProvider),",
- " sProvider.get(),",
- " s2Provider.get(),",
- " psProvider,",
- " qsProvider.get(),",
- " DoubleCheck.lazy(lsProvider),",
- " bProvider.get(),",
- " b2Provider.get(),",
- " pbProvider,",
- " qbProvider.get(),",
- " DoubleCheck.lazy(lbProvider));",
+ " return new GenericClass<A, B>(",
+ " aAndA2AndPaAndLaProvider.get(),",
+ " aAndA2AndPaAndLaProvider.get(),",
+ " aAndA2AndPaAndLaProvider,",
+ " qaProvider.get(),",
+ " DoubleCheck.lazy(aAndA2AndPaAndLaProvider),",
+ " sAndS2AndPsAndLsProvider.get(),",
+ " sAndS2AndPsAndLsProvider.get(),",
+ " sAndS2AndPsAndLsProvider,",
+ " qsProvider.get(),",
+ " DoubleCheck.lazy(sAndS2AndPsAndLsProvider),",
+ " bAndB2AndPbAndLbProvider.get(),",
+ " bAndB2AndPbAndLbProvider.get(),",
+ " bAndB2AndPbAndLbProvider,",
+ " qbProvider.get(),",
+ " DoubleCheck.lazy(bAndB2AndPbAndLbProvider));",
" }",
"",
" public static <A, B> GenericClass_Factory<A, B> create(",
- " Provider<A> aProvider,",
- " Provider<A> a2Provider,",
- " Provider<A> paProvider,",
+ " Provider<A> aAndA2AndPaAndLaProvider,",
" Provider<A> qaProvider,",
- " Provider<A> laProvider,",
- " Provider<String> sProvider,",
- " Provider<String> s2Provider,",
- " Provider<String> psProvider,",
+ " Provider<String> sAndS2AndPsAndLsProvider,",
" Provider<String> qsProvider,",
- " Provider<String> lsProvider,",
- " Provider<B> bProvider,",
- " Provider<B> b2Provider,",
- " Provider<B> pbProvider,",
- " Provider<B> qbProvider,",
- " Provider<B> lbProvider) {",
+ " Provider<B> bAndB2AndPbAndLbProvider,",
+ " Provider<B> qbProvider) {",
" return new GenericClass_Factory<A, B>(",
- " aProvider,",
- " a2Provider,",
- " paProvider,",
+ " aAndA2AndPaAndLaProvider,",
" qaProvider,",
- " laProvider,",
- " sProvider,",
- " s2Provider,",
- " psProvider,",
+ " sAndS2AndPsAndLsProvider,",
" qsProvider,",
- " lsProvider,",
- " bProvider,",
- " b2Provider,",
- " pbProvider,",
- " qbProvider,",
- " lbProvider);",
+ " bAndB2AndPbAndLbProvider,",
+ " qbProvider);",
" }",
"",
" public static <A, B> GenericClass<A, B> newInstance(",
@@ -551,11 +501,11 @@
Compilation compilation = daggerCompiler().compile(file);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("Types may only contain one injected constructor")
+ .hadErrorContaining("Types may only contain one @Inject constructor")
.inFile(file)
.onLine(6);
assertThat(compilation)
- .hadErrorContaining("Types may only contain one injected constructor")
+ .hadErrorContaining("Types may only contain one @Inject constructor")
.inFile(file)
.onLine(8);
}
@@ -652,7 +602,7 @@
" @Inject CheckedExceptionClass() throws Exception {}",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded();
assertThat(compilation)
.hadWarningContaining("Dagger does not support checked exceptions on @Inject constructors")
@@ -691,7 +641,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded();
assertThat(compilation)
.hadWarningContaining("Dagger does not support injection into private classes")
@@ -734,7 +684,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded();
assertThat(compilation)
.hadWarningContaining("Dagger does not support injection into private classes")
@@ -786,7 +736,7 @@
" @Inject private String s;",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
}
@@ -817,7 +767,7 @@
" @Inject static String s;",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
}
@@ -888,7 +838,7 @@
" @Inject private void method(){}",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.privateMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
}
@@ -919,7 +869,7 @@
" @Inject static void method(){}",
"}");
Compilation compilation =
- compilerWithOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
+ daggerCompiler().withOptions("-Adagger.staticMemberValidation=WARNING").compile(file);
assertThat(compilation).succeeded(); // TODO: Verify warning message when supported
}
@@ -1053,7 +1003,6 @@
.hadErrorContaining("Producer may only be injected in @Produces methods");
}
-
@Test public void injectConstructor() {
JavaFileObject file = JavaFileObjects.forSourceLines("test.InjectConstructor",
"package test;",
@@ -1072,7 +1021,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
"",
@@ -1083,7 +1032,7 @@
" }",
"",
" @Override public InjectConstructor get() {",
- " return newInstance(sProvider.get());",
+ " return new InjectConstructor(sProvider.get());",
" }",
"",
" public static InjectConstructor_Factory create(Provider<String> sProvider) {",
@@ -1119,39 +1068,28 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class AllInjections_Factory implements Factory<AllInjections> {",
" private final Provider<String> sProvider;",
- " private final Provider<String> sProvider2;",
- " private final Provider<String> sProvider3;",
"",
- " public AllInjections_Factory(",
- " Provider<String> sProvider,",
- " Provider<String> sProvider2,",
- " Provider<String> sProvider3) {",
+ " public AllInjections_Factory(Provider<String> sProvider) {",
" this.sProvider = sProvider;",
- " this.sProvider2 = sProvider2;",
- " this.sProvider3 = sProvider3;",
" }",
"",
- " @Override",
- " public AllInjections get() {",
- " AllInjections instance = newInstance(sProvider.get());",
- " AllInjections_MembersInjector.injectS(instance, sProvider2.get());",
- " AllInjections_MembersInjector.injectS2(instance, sProvider3.get());",
+ " @Override public AllInjections get() {",
+ " AllInjections instance = new AllInjections(sProvider.get());",
+ " AllInjections_MembersInjector.injectS(instance, sProvider.get());",
+ " AllInjections_MembersInjector.injectS2(instance, sProvider.get());",
" return instance;",
" }",
"",
- " public static AllInjections_Factory create(",
- " Provider<String> sProvider,",
- " Provider<String> sProvider2,",
- " Provider<String> sProvider3) {",
- " return new AllInjections_Factory(sProvider, sProvider2, sProvider3);",
+ " public static AllInjections_Factory create(Provider<String> sProvider) {",
+ " return new AllInjections_Factory(sProvider);",
" }",
"",
" public static AllInjections newInstance(String s) {",
- " return new AllInjections(s);",
- " }",
+ " return new AllInjections(s);",
+ " }",
"}");
assertAbout(javaSource()).that(file).processedWith(new ComponentProcessor())
.compilesWithoutError()
@@ -1180,7 +1118,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
"",
@@ -1191,7 +1129,7 @@
" }",
"",
" @Override public InjectConstructor get() {",
- " return newInstance(objectsProvider.get());",
+ " return new InjectConstructor(objectsProvider.get());",
" }",
"",
" public static InjectConstructor_Factory create(",
@@ -1232,7 +1170,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
"",
@@ -1243,7 +1181,7 @@
" }",
"",
" @Override public InjectConstructor get() {",
- " return newInstance(factoryProvider.get());",
+ " return new InjectConstructor(factoryProvider.get());",
" }",
"",
" public static InjectConstructor_Factory create(",
@@ -1289,7 +1227,7 @@
"import javax.inject.Provider;",
"import other.pkg.Outer;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
"",
@@ -1300,7 +1238,7 @@
" }",
"",
" @Override public InjectConstructor get() {",
- " return newInstance(factoryProvider.get());",
+ " return new InjectConstructor(factoryProvider.get());",
" }",
"",
" public static InjectConstructor_Factory create(",
@@ -1347,7 +1285,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectConstructor_Factory ",
" implements Factory<InjectConstructor> {",
"",
@@ -1362,7 +1300,8 @@
" }",
"",
" @Override public InjectConstructor get() {",
- " return newInstance(otherPackageProvider.get(), samePackageProvider.get());",
+ " return new InjectConstructor(",
+ " otherPackageProvider.get(), samePackageProvider.get());",
" }",
"",
" public static InjectConstructor_Factory create(",
@@ -1401,23 +1340,21 @@
"import dagger.internal.Factory;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class SimpleType_Factory implements Factory<SimpleType> {",
+ " private static final SimpleType_Factory INSTANCE = new SimpleType_Factory();",
+ "",
" @Override public SimpleType get() {",
- " return newInstance();",
+ " return new SimpleType();",
" }",
"",
" public static SimpleType_Factory create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static SimpleType newInstance() {",
" return new SimpleType();",
" }",
- "",
- " private static final class InstanceHolder {",
- " private static final SimpleType_Factory INSTANCE = new SimpleType_Factory();",
- " }",
"}");
assertAbout(javaSource())
.that(simpleType)
@@ -1449,23 +1386,21 @@
"import dagger.internal.Factory;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class OuterType_A_Factory implements Factory<OuterType.A> {",
+ " private static final OuterType_A_Factory INSTANCE = new OuterType_A_Factory();",
+ "",
" @Override public OuterType.A get() {",
- " return newInstance();",
+ " return new OuterType.A();",
" }",
"",
" public static OuterType_A_Factory create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static OuterType.A newInstance() {",
" return new OuterType.A();",
" }",
- "",
- " private static final class InstanceHolder {",
- " private static final OuterType_A_Factory INSTANCE = new OuterType_A_Factory();",
- " }",
"}");
assertAbout(javaSources()).that(ImmutableList.of(nestedTypesFile))
.processedWith(new ComponentProcessor())
diff --git a/javatests/dagger/internal/codegen/KeyFactoryTest.java b/javatests/dagger/internal/codegen/KeyFactoryTest.java
index fdf62cb..d526ec9 100644
--- a/javatests/dagger/internal/codegen/KeyFactoryTest.java
+++ b/javatests/dagger/internal/codegen/KeyFactoryTest.java
@@ -24,11 +24,8 @@
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.testing.compile.CompilationRule;
-import dagger.BindsInstance;
-import dagger.Component;
import dagger.Module;
import dagger.Provides;
-import dagger.internal.codegen.binding.KeyFactory;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
import dagger.model.Key;
@@ -41,7 +38,6 @@
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Qualifier;
-import javax.inject.Singleton;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@@ -61,12 +57,16 @@
public class KeyFactoryTest {
@Rule public CompilationRule compilationRule = new CompilationRule();
- @Inject DaggerElements elements;
- @Inject DaggerTypes types;
- @Inject KeyFactory keyFactory;
+ private DaggerElements elements;
+ private DaggerTypes types;
+ private KeyFactory keyFactory;
@Before public void setUp() {
- DaggerKeyFactoryTest_TestComponent.factory().create(compilationRule).inject(this);
+ this.elements = new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
+ this.types = new DaggerTypes(compilationRule.getTypes(), elements);
+ TypeProtoConverter typeProtoConverter = new TypeProtoConverter(types, elements);
+ this.keyFactory = new KeyFactory(
+ types, elements, typeProtoConverter, new AnnotationProtoConverter(typeProtoConverter));
}
@Test public void forInjectConstructorWithResolvedType() {
@@ -250,7 +250,7 @@
ExecutableElement integerMethod = Iterables.getOnlyElement(
ElementFilter.methodsIn(boxedPrimitiveHolder.getEnclosedElements()));
- // TODO(user): Truth subject for TypeMirror and TypeElement
+ // TODO(cgruber): Truth subject for TypeMirror and TypeElement
TypeMirror intType = intMethod.getReturnType();
assertThat(intType.getKind().isPrimitive()).isTrue();
TypeMirror integerType = integerMethod.getReturnType();
@@ -329,28 +329,4 @@
throw new UnsupportedOperationException();
}
}
-
- @Singleton
- @Component(modules = {TestModule.class})
- interface TestComponent {
- void inject(KeyFactoryTest test);
-
- @Component.Factory
- interface Factory {
- TestComponent create(@BindsInstance CompilationRule compilationRule);
- }
- }
-
- @Module
- static class TestModule {
- @Provides
- static DaggerElements elements(CompilationRule compilationRule) {
- return new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
- }
-
- @Provides
- static DaggerTypes types(CompilationRule compilationRule, DaggerElements elements) {
- return new DaggerTypes(compilationRule.getTypes(), elements);
- }
- }
}
diff --git a/javatests/dagger/internal/codegen/KotlinInjectedQualifier.kt b/javatests/dagger/internal/codegen/KotlinInjectedQualifier.kt
deleted file mode 100644
index 05e2758..0000000
--- a/javatests/dagger/internal/codegen/KotlinInjectedQualifier.kt
+++ /dev/null
@@ -1,26 +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.internal.codegen
-
-import javax.inject.Inject
-import javax.inject.Named
-
-class KotlinInjectedQualifier {
- @Inject
- @Named("TheString")
- lateinit var qualifiedString: String
-}
diff --git a/javatests/dagger/internal/codegen/KotlinObjectWithMemberInjection.kt b/javatests/dagger/internal/codegen/KotlinObjectWithMemberInjection.kt
deleted file mode 100644
index 619c1dd..0000000
--- a/javatests/dagger/internal/codegen/KotlinObjectWithMemberInjection.kt
+++ /dev/null
@@ -1,57 +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.internal.codegen
-
-import javax.inject.Inject
-
-object KotlinObjectWithMemberInjection {
- @Inject
- lateinit var property: String
-}
-
-object KotlinObjectWithSetterMemberInjection {
- @set:Inject
- lateinit var setterProperty: String
-}
-
-class KotlinClassWithMemberInjectedCompanion {
- companion object {
- @Inject
- lateinit var property: String
- }
-}
-
-class KotlinClassWithSetterMemberInjectedCompanion {
- companion object {
- @set:Inject
- lateinit var setterProperty: String
- }
-}
-
-class KotlinClassWithMemberInjectedNamedCompanion {
- companion object TheCompanion {
- @Inject
- lateinit var property: String
- }
-}
-
-class KotlinClassWithSetterMemberInjectedNamedCompanion {
- companion object TheCompanion {
- @set:Inject
- lateinit var setterProperty: String
- }
-}
diff --git a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
index ed9dd65..ad48712 100644
--- a/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/MapBindingComponentProcessorTest.java
@@ -17,9 +17,8 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
@@ -129,7 +128,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final MapModuleOne mapModuleOne;",
" private final MapModuleTwo mapModuleTwo;",
@@ -138,7 +137,7 @@
" private volatile Provider<Map<PathEnum, Provider<Handler>>>",
" mapOfPathEnumAndProviderOfHandlerProvider;",
"",
- " private Provider<Handler> provideAdminHandlerProvider() {",
+ " private Provider<Handler> getProvideAdminHandlerProvider() {",
" Object local = provideAdminHandlerProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -147,7 +146,7 @@
" return (Provider<Handler>) local;",
" }",
"",
- " private Provider<Handler> provideLoginHandlerProvider() {",
+ " private Provider<Handler> getProvideLoginHandlerProvider() {",
" Object local = provideLoginHandlerProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -157,10 +156,10 @@
" }",
"",
" private Map<PathEnum, Provider<Handler>>",
- " mapOfPathEnumAndProviderOfHandler() {",
+ " getMapOfPathEnumAndProviderOfHandler() {",
" return ImmutableMap.<PathEnum, Provider<Handler>>of(",
- " PathEnum.ADMIN, provideAdminHandlerProvider(),",
- " PathEnum.LOGIN, provideLoginHandlerProvider());",
+ " PathEnum.ADMIN, getProvideAdminHandlerProvider(),",
+ " PathEnum.LOGIN, getProvideLoginHandlerProvider());",
" }",
"",
" @Override",
@@ -187,7 +186,7 @@
" switch (id) {",
" case 0:",
" return (T) DaggerTestComponent.this",
- " .mapOfPathEnumAndProviderOfHandler();",
+ " .getMapOfPathEnumAndProviderOfHandler();",
" case 1:",
" return (T) MapModuleOne_ProvideAdminHandlerFactory",
" .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
@@ -206,7 +205,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
@@ -235,7 +234,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
mapModuleOneFile,
mapModuleTwoFile,
@@ -357,7 +357,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private Provider<Map<Class<?>, Integer>> mapOfClassOfAndIntegerProvider;",
"",
@@ -367,7 +367,7 @@
" private Provider<Map<MapKeys.ComplexKey, Integer>>",
" mapOfComplexKeyAndIntegerProvider;",
"",
- " private Map mapOfPackagePrivateEnumAndInteger() {",
+ " private Map getMapOfPackagePrivateEnumAndInteger() {",
" return ImmutableMap.of(",
" MapModule_EnumKeyMapKey.create(), MapModule.enumKey());",
" }",
@@ -411,7 +411,7 @@
"",
" @Override",
" public Object inaccessibleEnum() {",
- " return mapOfPackagePrivateEnumAndInteger();",
+ " return getMapOfPackagePrivateEnumAndInteger();",
" }",
"",
" @Override",
@@ -443,7 +443,7 @@
"mapkeys.MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey",
"package mapkeys;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class MapModule_ComplexKeyWithInaccessibleAnnotationValueMapKey {",
" public static MapKeys.ComplexKey create() {",
" return MapKeys_ComplexKeyCreator.createComplexKey(",
@@ -459,7 +459,7 @@
"mapkeys.MapModule_ClassKeyMapKey",
"package mapkeys;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class MapModule_ClassKeyMapKey {",
" public static Class<?> create() {",
" return MapKeys.Inaccessible.class;",
@@ -536,7 +536,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final MapModuleOne mapModuleOne;",
" private final MapModuleTwo mapModuleTwo;",
@@ -545,7 +545,7 @@
" private volatile Provider<Map<String, Provider<Handler>>>",
" mapOfStringAndProviderOfHandlerProvider;",
"",
- " private Provider<Handler> provideAdminHandlerProvider() {",
+ " private Provider<Handler> getProvideAdminHandlerProvider() {",
" Object local = provideAdminHandlerProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -554,7 +554,7 @@
" return (Provider<Handler>) local;",
" }",
"",
- " private Provider<Handler> provideLoginHandlerProvider() {",
+ " private Provider<Handler> getProvideLoginHandlerProvider() {",
" Object local = provideLoginHandlerProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -564,10 +564,10 @@
" }",
"",
" private Map<String, Provider<Handler>>",
- " mapOfStringAndProviderOfHandler() {",
+ " getMapOfStringAndProviderOfHandler() {",
" return ImmutableMap.<String, Provider<Handler>>of(",
- " \"Admin\", provideAdminHandlerProvider(),",
- " \"Login\", provideLoginHandlerProvider());",
+ " \"Admin\", getProvideAdminHandlerProvider(),",
+ " \"Login\", getProvideLoginHandlerProvider());",
" }",
"",
" @Override",
@@ -594,7 +594,7 @@
" switch (id) {",
" case 0:",
" return (T) DaggerTestComponent.this",
- " .mapOfStringAndProviderOfHandler();",
+ " .getMapOfStringAndProviderOfHandler();",
" case 1:",
" return (T) MapModuleOne_ProvideAdminHandlerFactory",
" .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
@@ -613,7 +613,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
@@ -642,7 +642,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
mapModuleOneFile,
mapModuleTwoFile,
@@ -736,7 +737,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final MapModuleOne mapModuleOne;",
" private final MapModuleTwo mapModuleTwo;",
@@ -752,7 +753,7 @@
" this.mapModuleTwo = mapModuleTwoParam;",
" }",
"",
- " private Provider<Handler> provideAdminHandlerProvider() {",
+ " private Provider<Handler> getProvideAdminHandlerProvider() {",
" Object local = provideAdminHandlerProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -761,7 +762,7 @@
" return (Provider<Handler>) local;",
" }",
"",
- " private Provider<Handler> provideLoginHandlerProvider() {",
+ " private Provider<Handler> getProvideLoginHandlerProvider() {",
" Object local = provideLoginHandlerProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -771,12 +772,12 @@
" }",
"",
" private Map<WrappedClassKey, Provider<Handler>>",
- " mapOfWrappedClassKeyAndProviderOfHandler() {",
+ " getMapOfWrappedClassKeyAndProviderOfHandler() {",
" return ImmutableMap.<WrappedClassKey, Provider<Handler>>of(",
" WrappedClassKeyCreator.createWrappedClassKey(Integer.class),",
- " provideAdminHandlerProvider(),",
+ " getProvideAdminHandlerProvider(),",
" WrappedClassKeyCreator.createWrappedClassKey(Long.class),",
- " provideLoginHandlerProvider());",
+ " getProvideLoginHandlerProvider());",
" }",
"",
" @Override",
@@ -803,7 +804,7 @@
" switch (id) {",
" case 0:",
" return (T) DaggerTestComponent.this",
- " .mapOfWrappedClassKeyAndProviderOfHandler();",
+ " .getMapOfWrappedClassKeyAndProviderOfHandler();",
" case 1:",
" return (T) MapModuleOne_ProvideAdminHandlerFactory",
" .provideAdminHandler(DaggerTestComponent.this.mapModuleOne);",
@@ -822,7 +823,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
@@ -853,7 +854,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
mapModuleOneFile,
mapModuleTwoFile,
@@ -949,14 +951,14 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final MapModuleOne mapModuleOne;",
" private final MapModuleTwo mapModuleTwo;",
" private volatile Provider<Map<PathEnum, Handler>>",
" mapOfPathEnumAndHandlerProvider;",
"",
- " private Map<PathEnum, Handler> mapOfPathEnumAndHandler() {",
+ " private Map<PathEnum, Handler> getMapOfPathEnumAndHandler() {",
" return ImmutableMap.<PathEnum, Handler>of(",
" PathEnum.ADMIN,",
" MapModuleOne_ProvideAdminHandlerFactory.provideAdminHandler(",
@@ -987,7 +989,7 @@
" @Override",
" public T get() {",
" switch (id) {",
- " case 0: return (T) DaggerTestComponent.this.mapOfPathEnumAndHandler();",
+ " case 0: return (T) DaggerTestComponent.this.getMapOfPathEnumAndHandler();",
" default: throw new AssertionError(id);",
" }",
" }",
@@ -1000,7 +1002,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private Provider<Handler> provideAdminHandlerProvider;",
" private Provider<Handler> provideLoginHandlerProvider;",
@@ -1028,7 +1030,8 @@
"}");
}
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
mapModuleOneFile,
mapModuleTwoFile,
@@ -1077,7 +1080,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final MapModule mapModule;",
"",
@@ -1087,7 +1090,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(mapModuleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java b/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
index 3f33bd5..11f6bc1 100644
--- a/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
+++ b/javatests/dagger/internal/codegen/MapBindingExpressionTest.java
@@ -20,8 +20,8 @@
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.CLASS_PATH_WITHOUT_GUAVA_OPTION;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
@@ -92,7 +92,7 @@
"",
"import dagger.internal.MapBuilder;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
@@ -101,7 +101,7 @@
" private volatile Provider<Long> provideLong1Provider;",
" private volatile Provider<Long> provideLong2Provider;",
"",
- " private Provider<Integer> provideIntProvider() {",
+ " private Provider<Integer> getProvideIntProvider() {",
" Object local = provideIntProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -110,7 +110,7 @@
" return (Provider<Integer>) local;",
" }",
"",
- " private Provider<Long> provideLong0Provider() {",
+ " private Provider<Long> getProvideLong0Provider() {",
" Object local = provideLong0Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -119,7 +119,7 @@
" return (Provider<Long>) local;",
" }",
"",
- " private Provider<Long> provideLong1Provider() {",
+ " private Provider<Long> getProvideLong1Provider() {",
" Object local = provideLong1Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -128,7 +128,7 @@
" return (Provider<Long>) local;",
" }",
"",
- " private Provider<Long> provideLong2Provider() {",
+ " private Provider<Long> getProvideLong2Provider() {",
" Object local = provideLong2Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(3);",
@@ -160,7 +160,7 @@
" 0, MapModule_ProvideIntFactory.create());")
.addLinesIn(
FAST_INIT_MODE,
- " 0, provideIntProvider());")
+ " 0, getProvideIntProvider());")
.addLines(
" }",
"",
@@ -183,9 +183,9 @@
" .put(2L, MapModule_ProvideLong2Factory.create())")
.addLinesIn(
FAST_INIT_MODE,
- " .put(0L, provideLong0Provider())",
- " .put(1L, provideLong1Provider())",
- " .put(2L, provideLong2Provider())")
+ " .put(0L, getProvideLong0Provider())",
+ " .put(1L, getProvideLong1Provider())",
+ " .put(2L, getProvideLong2Provider())")
.addLines( //
" .build();", " }")
.addLinesIn(
@@ -274,7 +274,7 @@
"import other.UsesInaccessible;",
"import other.UsesInaccessible_Factory;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public UsesInaccessible usesInaccessible() {",
@@ -337,7 +337,7 @@
"test.DaggerParent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
" private final ParentModule parentModule;",
"",
@@ -360,7 +360,7 @@
}
private Compiler daggerCompilerWithoutGuava() {
- return compilerWithOptions(compilerMode.javacopts())
- .withClasspath(CLASS_PATH_WITHOUT_GUAVA_OPTION);
+ return daggerCompiler()
+ .withOptions(compilerMode.javacopts().append(CLASS_PATH_WITHOUT_GUAVA_OPTION));
}
}
diff --git a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java b/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
index 69ab5a7..aa1a715 100644
--- a/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
+++ b/javatests/dagger/internal/codegen/MapBindingExpressionWithGuavaTest.java
@@ -20,7 +20,8 @@
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
@@ -127,7 +128,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
@@ -136,7 +137,7 @@
" private volatile Provider<Long> provideLong1Provider;",
" private volatile Provider<Long> provideLong2Provider;",
"",
- " private Provider<Integer> provideIntProvider() {",
+ " private Provider<Integer> getProvideIntProvider() {",
" Object local = provideIntProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -145,7 +146,7 @@
" return (Provider<Integer>) local;",
" }",
"",
- " private Provider<Long> provideLong0Provider() {",
+ " private Provider<Long> getProvideLong0Provider() {",
" Object local = provideLong0Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -154,7 +155,7 @@
" return (Provider<Long>) local;",
" }",
"",
- " private Provider<Long> provideLong1Provider() {",
+ " private Provider<Long> getProvideLong1Provider() {",
" Object local = provideLong1Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -163,7 +164,7 @@
" return (Provider<Long>) local;",
" }",
"",
- " private Provider<Long> provideLong2Provider() {",
+ " private Provider<Long> getProvideLong2Provider() {",
" Object local = provideLong2Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(3);",
@@ -195,7 +196,7 @@
" 0, MapModule_ProvideIntFactory.create());")
.addLinesIn(
FAST_INIT_MODE, //
- " 0, provideIntProvider());")
+ " 0, getProvideIntProvider());")
.addLines(
" }",
"",
@@ -217,9 +218,9 @@
" 2L, MapModule_ProvideLong2Factory.create());")
.addLinesIn(
FAST_INIT_MODE,
- " 0L, provideLong0Provider(),",
- " 1L, provideLong1Provider(),",
- " 2L, provideLong2Provider());")
+ " 0L, getProvideLong0Provider(),",
+ " 1L, getProvideLong1Provider(),",
+ " 2L, getProvideLong2Provider());")
.addLines(
" }",
"",
@@ -236,7 +237,7 @@
" private volatile Provider<Long> provideLong5Provider;",
" private SubImpl() {}",
"",
- " private Provider<Long> provideLong3Provider() {",
+ " private Provider<Long> getProvideLong3Provider() {",
" Object local = provideLong3Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -245,7 +246,7 @@
" return (Provider<Long>) local;",
" }",
"",
- " private Provider<Long> provideLong4Provider() {",
+ " private Provider<Long> getProvideLong4Provider() {",
" Object local = provideLong4Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -254,7 +255,7 @@
" return (Provider<Long>) local;",
" }",
"",
- " private Provider<Long> provideLong5Provider() {",
+ " private Provider<Long> getProvideLong5Provider() {",
" Object local = provideLong5Provider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -288,12 +289,12 @@
" .put(5L, SubcomponentMapModule_ProvideLong5Factory.create())")
.addLinesIn(
FAST_INIT_MODE,
- " .put(0L, DaggerTestComponent.this.provideLong0Provider())",
- " .put(1L, DaggerTestComponent.this.provideLong1Provider())",
- " .put(2L, DaggerTestComponent.this.provideLong2Provider())",
- " .put(3L, provideLong3Provider())",
- " .put(4L, provideLong4Provider())",
- " .put(5L, provideLong5Provider())")
+ " .put(0L, DaggerTestComponent.this.getProvideLong0Provider())",
+ " .put(1L, DaggerTestComponent.this.getProvideLong1Provider())",
+ " .put(2L, DaggerTestComponent.this.getProvideLong2Provider())",
+ " .put(3L, getProvideLong3Provider())",
+ " .put(4L, getProvideLong4Provider())",
+ " .put(5L, getProvideLong5Provider())")
.addLines( //
" .build();", " }")
.addLinesIn(
@@ -340,7 +341,8 @@
"}")
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(mapModuleFile, componentFile, subcomponentModuleFile, subcomponent);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -401,7 +403,7 @@
"import other.UsesInaccessible;",
"import other.UsesInaccessible_Factory;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public UsesInaccessible usesInaccessible() {",
@@ -409,7 +411,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, inaccessible, usesInaccessible, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -463,7 +466,7 @@
"test.DaggerParent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
" private final ParentModule parentModule;",
"",
@@ -479,7 +482,7 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(parent, parentModule, child);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, parentModule, child);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerParent")
@@ -519,7 +522,7 @@
"",
"import dagger.producers.internal.CancellationListener;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent, "
+ "CancellationListener {",
" @Override",
diff --git a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
index ffdb2bc..746c60d 100644
--- a/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
+++ b/javatests/dagger/internal/codegen/MapKeyProcessorTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.auto.value.processor.AutoAnnotationProcessor;
@@ -73,7 +73,7 @@
"import com.google.auto.value.AutoAnnotation;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class PathKeyCreator {",
" private PathKeyCreator() {}",
"",
@@ -122,7 +122,7 @@
"import com.google.auto.value.AutoAnnotation;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class Container_PathKeyCreator {",
" private Container_PathKeyCreator() {}",
"",
diff --git a/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java b/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
index 753fb53..04b0986 100644
--- a/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
+++ b/javatests/dagger/internal/codegen/MapMultibindingValidationTest.java
@@ -17,9 +17,7 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.message;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
@@ -32,7 +30,7 @@
@RunWith(JUnit4.class)
public class MapMultibindingValidationTest {
@Test
- public void duplicateMapKeys_UnwrappedMapKey() {
+ public void duplicateMapKeys() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.MapModule",
@@ -67,19 +65,18 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Object>");
+ + "java.util.Map<java.lang.String,java.lang.Object>");
assertThat(compilation).hadErrorContaining("provideObjectForAKey()");
assertThat(compilation).hadErrorContaining("provideObjectForAKeyAgain()");
assertThat(compilation).hadErrorCount(1);
compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(module);
+ daggerCompiler().withOptions("-Adagger.fullBindingGraphValidation=ERROR").compile(module);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Provider<Object>>")
+ + "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>")
.inFile(module)
.onLineContaining("class MapModule");
assertThat(compilation).hadErrorContaining("provideObjectForAKey()");
@@ -98,7 +95,7 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Object>");
+ + "java.util.Map<java.lang.String,java.lang.Object>");
assertThat(compilation).hadErrorCount(1);
// If there's Map<K, V> and Map<K, Producer<V>>, report only Map<K, V>.
@@ -113,7 +110,7 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Object>");
+ + "java.util.Map<java.lang.String,java.lang.Object>");
assertThat(compilation).hadErrorCount(1);
// If there's Map<K, Provider<V>> and Map<K, Producer<V>>, report only Map<K, Provider<V>>.
@@ -128,7 +125,7 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Provider<Object>>");
+ + "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>");
assertThat(compilation).hadErrorCount(1);
compilation = daggerCompiler().compile(module, component("Map<String, Object> objects();"));
@@ -136,7 +133,7 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Object>");
+ + "java.util.Map<java.lang.String,java.lang.Object>");
assertThat(compilation).hadErrorCount(1);
compilation =
@@ -146,7 +143,7 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Provider<Object>>");
+ + "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>");
assertThat(compilation).hadErrorCount(1);
compilation =
@@ -157,59 +154,11 @@
assertThat(compilation)
.hadErrorContaining(
"The same map key is bound more than once for "
- + "Map<String,Producer<Object>>");
+ + "java.util.Map<java.lang.String,dagger.producers.Producer<java.lang.Object>>");
assertThat(compilation).hadErrorCount(1);
}
@Test
- public void duplicateMapKeys_WrappedMapKey() {
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.MapModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import dagger.multibindings.IntoMap;",
- "import dagger.MapKey;",
- "",
- "@Module",
- "abstract class MapModule {",
- "",
- " @MapKey(unwrapValue = false)",
- " @interface WrappedMapKey {",
- " String value();",
- " }",
- "",
- " @Provides",
- " @IntoMap",
- " @WrappedMapKey(\"foo\")",
- " static String stringMapEntry1() { return \"\"; }",
- "",
- " @Provides",
- " @IntoMap",
- " @WrappedMapKey(\"foo\")",
- " static String stringMapEntry2() { return \"\"; }",
- "}");
-
- JavaFileObject component = component("Map<test.MapModule.WrappedMapKey, String> objects();");
-
- Compilation compilation = daggerCompiler().compile(component, module);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "\033[1;31m[Dagger/MapKeys]\033[0m The same map key is bound more than once for "
- + "Map<MapModule.WrappedMapKey,String>",
- " @Provides @IntoMap @MapModule.WrappedMapKey(\"foo\") String "
- + "MapModule.stringMapEntry1()",
- " @Provides @IntoMap @MapModule.WrappedMapKey(\"foo\") String "
- + "MapModule.stringMapEntry2()"))
- .inFile(component)
- .onLineContaining("interface TestComponent");
- }
-
- @Test
public void inconsistentMapKeyAnnotations() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
@@ -256,19 +205,20 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Object>"
+ "java.util.Map<java.lang.String,java.lang.Object>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorContaining("provideObjectForAKey()");
assertThat(compilation).hadErrorContaining("provideObjectForBKey()");
assertThat(compilation).hadErrorCount(1);
compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(module, stringKeyTwoFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Provider<Object>>"
+ "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>"
+ " uses more than one @MapKey annotation type")
.inFile(module)
.onLineContaining("class MapModule");
@@ -288,7 +238,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Object>"
+ "java.util.Map<java.lang.String,java.lang.Object>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorCount(1);
@@ -304,7 +254,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Object>"
+ "java.util.Map<java.lang.String,java.lang.Object>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorCount(1);
@@ -320,7 +270,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Provider<Object>>"
+ "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorCount(1);
@@ -330,7 +280,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Object>"
+ "java.util.Map<java.lang.String,java.lang.Object>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorCount(1);
@@ -343,7 +293,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Provider<Object>>"
+ "java.util.Map<java.lang.String,javax.inject.Provider<java.lang.Object>>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorCount(1);
@@ -356,7 +306,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,Producer<Object>>"
+ "java.util.Map<java.lang.String,dagger.producers.Producer<java.lang.Object>>"
+ " uses more than one @MapKey annotation type");
assertThat(compilation).hadErrorCount(1);
}
diff --git a/javatests/dagger/internal/codegen/MembersInjectionTest.java b/javatests/dagger/internal/codegen/MembersInjectionTest.java
index ef69c71..edaedaf 100644
--- a/javatests/dagger/internal/codegen/MembersInjectionTest.java
+++ b/javatests/dagger/internal/codegen/MembersInjectionTest.java
@@ -22,8 +22,8 @@
import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import static javax.tools.StandardLocation.CLASS_OUTPUT;
@@ -87,7 +87,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Child child() {",
@@ -95,7 +95,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(childFile, parentFile, componentFile);
assertThat(compilation).succeeded();
@@ -146,7 +147,7 @@
"",
"import com.google.errorprone.annotations.CanIgnoreReturnValue;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Child child() {",
@@ -160,7 +161,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(childFile, parentFile, depFile, componentFile);
assertThat(compilation).succeeded();
@@ -182,47 +184,44 @@
"",
" @Inject void register(B b) {}",
"}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.GenericClass_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class GenericClass_MembersInjector<A, B>",
- " implements MembersInjector<GenericClass<A, B>> {",
- " private final Provider<A> aProvider;",
- " private final Provider<B> bProvider;",
- "",
- " public GenericClass_MembersInjector(Provider<A> aProvider, Provider<B> bProvider) {",
- " this.aProvider = aProvider;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " public static <A, B> MembersInjector<GenericClass<A, B>> create(",
- " Provider<A> aProvider, Provider<B> bProvider) {",
- " return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(GenericClass<A, B> instance) {",
- " injectA(instance, aProvider.get());",
- " injectRegister(instance, bProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.GenericClass.a\")",
- " public static <A, B> void injectA(Object instance, A a) {",
- " ((GenericClass<A, B>) instance).a = a;",
- " }",
- "",
- " public static <A, B> void injectRegister(Object instance, B b) {",
- " ((GenericClass<A, B>) instance).register(b);",
- " }",
- "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.GenericClass_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "public final class GenericClass_MembersInjector<A, B>",
+ " implements MembersInjector<GenericClass<A, B>> {",
+ " private final Provider<A> aProvider;",
+ " private final Provider<B> bProvider;",
+ "",
+ " public GenericClass_MembersInjector(Provider<A> aProvider, Provider<B> bProvider) {",
+ " this.aProvider = aProvider;",
+ " this.bProvider = bProvider;",
+ " }",
+ "",
+ " public static <A, B> MembersInjector<GenericClass<A, B>> create(",
+ " Provider<A> aProvider, Provider<B> bProvider) {",
+ " return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(GenericClass<A, B> instance) {",
+ " injectA(instance, aProvider.get());",
+ " injectRegister(instance, bProvider.get());",
+ " }",
+ "",
+ " public static <A, B> void injectA(Object instance, A a) {",
+ " ((GenericClass<A, B>) instance).a = a;",
+ " }",
+ "",
+ " public static <A, B> void injectRegister(Object instance, B b) {",
+ " ((GenericClass<A, B>) instance).register(b);",
+ " }",
+ "}");
assertAbout(javaSource())
.that(file)
.withCompilerOptions(compilerMode.javacopts())
@@ -272,67 +271,50 @@
"",
" @Inject Child() {}",
"}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.Child_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class Child_MembersInjector<T>",
- " implements MembersInjector<Child<T>> {",
- " private final Provider<T> xProvider;",
- " private final Provider<A> yProvider;",
- " private final Provider<A2> a2Provider;",
- " private final Provider<A> aProvider;",
- " private final Provider<T> tProvider;",
- "",
- " public Child_MembersInjector(",
- " Provider<T> xProvider,",
- " Provider<A> yProvider,",
- " Provider<A2> a2Provider,",
- " Provider<A> aProvider,",
- " Provider<T> tProvider) {",
- " this.xProvider = xProvider;",
- " this.yProvider = yProvider;",
- " this.a2Provider = a2Provider;",
- " this.aProvider = aProvider;",
- " this.tProvider = tProvider;",
- " }",
- "",
- " public static <T> MembersInjector<Child<T>> create(",
- " Provider<T> xProvider,",
- " Provider<A> yProvider,",
- " Provider<A2> a2Provider,",
- " Provider<A> aProvider,",
- " Provider<T> tProvider) {",
- " return new Child_MembersInjector<T>(xProvider, yProvider, a2Provider, aProvider,"
- + " tProvider);",
- "}",
- "",
- " @Override",
- " public void injectMembers(Child<T> instance) {",
- " Parent_MembersInjector.injectX(instance, xProvider.get());",
- " Parent_MembersInjector.injectY(instance, yProvider.get());",
- " Parent_MembersInjector.injectA2(instance, a2Provider.get());",
- " injectA(instance, aProvider.get());",
- " injectT(instance, tProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.Child.a\")",
- " public static <T> void injectA(Object instance, Object a) {",
- " ((Child<T>) instance).a = (A) a;",
- " }",
- "",
- " @InjectedFieldSignature(\"test.Child.t\")",
- " public static <T> void injectT(Object instance, T t) {",
- " ((Child<T>) instance).t = t;",
- " }",
- "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.Child_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "public final class Child_MembersInjector<T>",
+ " implements MembersInjector<Child<T>> {",
+ " private final Provider<T> tAndXProvider;",
+ " private final Provider<A> aAndYProvider;",
+ " private final Provider<A2> a2Provider;",
+ "",
+ " public Child_MembersInjector(",
+ " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
+ " this.tAndXProvider = tAndXProvider;",
+ " this.aAndYProvider = aAndYProvider;",
+ " this.a2Provider = a2Provider;",
+ " }",
+ "",
+ " public static <T> MembersInjector<Child<T>> create(",
+ " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
+ " return new Child_MembersInjector<T>(tAndXProvider, aAndYProvider, a2Provider);",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(Child<T> instance) {",
+ " Parent_MembersInjector.injectX(instance, tAndXProvider.get());",
+ " Parent_MembersInjector.injectY(instance, aAndYProvider.get());",
+ " Parent_MembersInjector.injectA2(instance, a2Provider.get());",
+ " injectA(instance, aAndYProvider.get());",
+ " injectT(instance, tAndXProvider.get());",
+ " }",
+ "",
+ " public static <T> void injectA(Object instance, Object a) {",
+ " ((Child<T>) instance).a = (A) a;",
+ " }",
+ "",
+ " public static <T> void injectT(Object instance, T t) {",
+ " ((Child<T>) instance).t = t;",
+ " }",
+ "}");
assertAbout(javaSources())
.that(ImmutableList.of(a, a2, parent, child))
.withCompilerOptions(compilerMode.javacopts())
@@ -363,50 +345,38 @@
"import dagger.Lazy;",
"import dagger.MembersInjector;",
"import dagger.internal.DoubleCheck;",
- "import dagger.internal.InjectedFieldSignature;",
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class FieldInjection_MembersInjector",
" implements MembersInjector<FieldInjection> {",
" private final Provider<String> stringProvider;",
- " private final Provider<String> stringProvider2;",
- " private final Provider<String> stringProvider3;",
"",
- " public FieldInjection_MembersInjector(Provider<String> stringProvider,",
- " Provider<String> stringProvider2, Provider<String> stringProvider3) {",
+ " public FieldInjection_MembersInjector(Provider<String> stringProvider) {",
" this.stringProvider = stringProvider;",
- " this.stringProvider2 = stringProvider2;",
- " this.stringProvider3 = stringProvider3;",
" }",
"",
" public static MembersInjector<FieldInjection> create(",
- " Provider<String> stringProvider,",
- " Provider<String> stringProvider2,",
- " Provider<String> stringProvider3) {",
- " return new FieldInjection_MembersInjector(",
- " stringProvider, stringProvider2, stringProvider3);",
+ " Provider<String> stringProvider) {",
+ " return new FieldInjection_MembersInjector(stringProvider);",
" }",
"",
" @Override",
" public void injectMembers(FieldInjection instance) {",
" injectString(instance, stringProvider.get());",
- " injectLazyString(instance, DoubleCheck.lazy(stringProvider2));",
- " injectStringProvider(instance, stringProvider3);",
+ " injectLazyString(instance, DoubleCheck.lazy(stringProvider));",
+ " injectStringProvider(instance, stringProvider);",
" }",
"",
- " @InjectedFieldSignature(\"test.FieldInjection.string\")",
" public static void injectString(Object instance, String string) {",
" ((FieldInjection) instance).string = string;",
" }",
"",
- " @InjectedFieldSignature(\"test.FieldInjection.lazyString\")",
" public static void injectLazyString(Object instance, Lazy<String> lazyString) {",
" ((FieldInjection) instance).lazyString = lazyString;",
" }",
"",
- " @InjectedFieldSignature(\"test.FieldInjection.stringProvider\")",
" public static void injectStringProvider(",
" Object instance, Provider<String> stringProvider) {",
" ((FieldInjection) instance).stringProvider = stringProvider;",
@@ -421,77 +391,6 @@
.generatesSources(expected);
}
- @Test
- public void fieldInjectionWithQualifier() {
- JavaFileObject file =
- JavaFileObjects.forSourceLines(
- "test.FieldInjectionWithQualifier",
- "package test;",
- "",
- "import dagger.Lazy;",
- "import javax.inject.Inject;",
- "import javax.inject.Named;",
- "import javax.inject.Provider;",
- "",
- "class FieldInjectionWithQualifier {",
- " @Inject @Named(\"A\") String a;",
- " @Inject @Named(\"B\") String b;",
- "}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.FieldInjectionWithQualifier_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Named;",
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class FieldInjectionWithQualifier_MembersInjector",
- " implements MembersInjector<FieldInjectionWithQualifier> {",
- " private final Provider<String> aProvider;",
- " private final Provider<String> bProvider;",
- "",
- " public FieldInjectionWithQualifier_MembersInjector(Provider<String> aProvider,",
- " Provider<String> bProvider) {",
- " this.aProvider = aProvider;",
- " this.bProvider = bProvider;",
- " }",
- "",
- " public static MembersInjector<FieldInjectionWithQualifier> create(",
- " Provider<String> aProvider, Provider<String> bProvider) {",
- " return new FieldInjectionWithQualifier_MembersInjector(aProvider, bProvider);",
- " }",
- "",
- "@Override",
- " public void injectMembers(FieldInjectionWithQualifier instance) {",
- " injectA(instance, aProvider.get());",
- " injectB(instance, bProvider.get());",
- "}",
- "",
- " @InjectedFieldSignature(\"test.FieldInjectionWithQualifier.a\")",
- " @Named(\"A\")",
- " public static void injectA(Object instance, String a) {",
- " ((FieldInjectionWithQualifier) instance).a = a;",
- " }",
- "",
- " @InjectedFieldSignature(\"test.FieldInjectionWithQualifier.b\")",
- " @Named(\"B\")",
- " public static void injectB(Object instance, String b) {",
- " ((FieldInjectionWithQualifier) instance).b = b;",
- " }",
- "}");
- assertAbout(javaSource())
- .that(file)
- .withCompilerOptions(compilerMode.javacopts())
- .processedWith(new ComponentProcessor())
- .compilesWithoutError()
- .and()
- .generatesSources(expected);
- }
-
@Test public void methodInjection() {
JavaFileObject file = JavaFileObjects.forSourceLines("test.MethodInjection",
"package test;",
@@ -517,32 +416,20 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class MethodInjection_MembersInjector",
" implements MembersInjector<MethodInjection> {",
- " private final Provider<String> stringProvider;",
- " private final Provider<String> stringProvider2;",
- " private final Provider<String> stringProvider3;",
- " private final Provider<String> stringProvider4;",
"",
- " public MethodInjection_MembersInjector(",
- " Provider<String> stringProvider,",
- " Provider<String> stringProvider2,",
- " Provider<String> stringProvider3,",
- " Provider<String> stringProvider4) {",
+ " private final Provider<String> stringProvider;",
+ "",
+ " public MethodInjection_MembersInjector(Provider<String> stringProvider) {",
" this.stringProvider = stringProvider;",
- " this.stringProvider2 = stringProvider2;",
- " this.stringProvider3 = stringProvider3;",
- " this.stringProvider4 = stringProvider4;",
" }",
"",
" public static MembersInjector<MethodInjection> create(",
- " Provider<String> stringProvider,",
- " Provider<String> stringProvider2,",
- " Provider<String> stringProvider3,",
- " Provider<String> stringProvider4) {",
- " return new MethodInjection_MembersInjector(",
- " stringProvider, stringProvider2, stringProvider3, stringProvider4);}",
+ " Provider<String> stringProvider) {",
+ " return new MethodInjection_MembersInjector(stringProvider);",
+ " }",
"",
" @Override",
" public void injectMembers(MethodInjection instance) {",
@@ -550,9 +437,9 @@
" injectOneArg(instance, stringProvider.get());",
" injectManyArgs(",
" instance,",
- " stringProvider2.get(),",
- " DoubleCheck.lazy(stringProvider3),",
- " stringProvider4);",
+ " stringProvider.get(),",
+ " DoubleCheck.lazy(stringProvider),",
+ " stringProvider);",
" }",
"",
" public static void injectNoArgs(Object instance) {",
@@ -596,69 +483,59 @@
" @Inject Object object;",
" @Inject void setObject(Object o) {}",
"}");
- JavaFileObject expected =
- JavaFileObjects.forSourceLines(
- "test.MixedMemberInjection_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class MixedMemberInjection_MembersInjector",
- " implements MembersInjector<MixedMemberInjection> {",
- " private final Provider<String> stringProvider;",
- " private final Provider<Object> objectProvider;",
- " private final Provider<String> sProvider;",
- " private final Provider<Object> oProvider;",
- "",
- " public MixedMemberInjection_MembersInjector(",
- " Provider<String> stringProvider,",
- " Provider<Object> objectProvider,",
- " Provider<String> sProvider,",
- " Provider<Object> oProvider) {",
- " this.stringProvider = stringProvider;",
- " this.objectProvider = objectProvider;",
- " this.sProvider = sProvider;",
- " this.oProvider = oProvider;",
- " }",
- "",
- " public static MembersInjector<MixedMemberInjection> create(",
- " Provider<String> stringProvider,",
- " Provider<Object> objectProvider,",
- " Provider<String> sProvider,",
- " Provider<Object> oProvider) {",
- " return new MixedMemberInjection_MembersInjector(",
- " stringProvider, objectProvider, sProvider, oProvider);}",
- "",
- " @Override",
- " public void injectMembers(MixedMemberInjection instance) {",
- " injectString(instance, stringProvider.get());",
- " injectObject(instance, objectProvider.get());",
- " injectSetString(instance, sProvider.get());",
- " injectSetObject(instance, oProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.MixedMemberInjection.string\")",
- " public static void injectString(Object instance, String string) {",
- " ((MixedMemberInjection) instance).string = string;",
- " }",
- "",
- " @InjectedFieldSignature(\"test.MixedMemberInjection.object\")",
- " public static void injectObject(Object instance, Object object) {",
- " ((MixedMemberInjection) instance).object = object;",
- " }",
- "",
- " public static void injectSetString(Object instance, String s) {",
- " ((MixedMemberInjection) instance).setString(s);",
- " }",
- "",
- " public static void injectSetObject(Object instance, Object o) {",
- " ((MixedMemberInjection) instance).setObject(o);",
- " }",
- "}");
+ JavaFileObject expected = JavaFileObjects.forSourceLines(
+ "test.MixedMemberInjection_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "public final class MixedMemberInjection_MembersInjector",
+ " implements MembersInjector<MixedMemberInjection> {",
+ "",
+ " private final Provider<String> stringAndSProvider;",
+ " private final Provider<Object> objectAndOProvider;",
+ "",
+ " public MixedMemberInjection_MembersInjector(",
+ " Provider<String> stringAndSProvider,",
+ " Provider<Object> objectAndOProvider) {",
+ " this.stringAndSProvider = stringAndSProvider;",
+ " this.objectAndOProvider = objectAndOProvider;",
+ " }",
+ "",
+ " public static MembersInjector<MixedMemberInjection> create(",
+ " Provider<String> stringAndSProvider,",
+ " Provider<Object> objectAndOProvider) {",
+ " return new MixedMemberInjection_MembersInjector(",
+ " stringAndSProvider, objectAndOProvider);",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(MixedMemberInjection instance) {",
+ " injectString(instance, stringAndSProvider.get());",
+ " injectObject(instance, objectAndOProvider.get());",
+ " injectSetString(instance, stringAndSProvider.get());",
+ " injectSetObject(instance, objectAndOProvider.get());",
+ " }",
+ "",
+ " public static void injectString(Object instance, String string) {",
+ " ((MixedMemberInjection) instance).string = string;",
+ " }",
+ "",
+ " public static void injectObject(Object instance, Object object) {",
+ " ((MixedMemberInjection) instance).object = object;",
+ " }",
+ "",
+ " public static void injectSetString(Object instance, String s) {",
+ " ((MixedMemberInjection) instance).setString(s);",
+ " }",
+ "",
+ " public static void injectSetObject(Object instance, Object o) {",
+ " ((MixedMemberInjection) instance).setObject(o);",
+ " }",
+ "}");
assertAbout(javaSource())
.that(file)
.withCompilerOptions(compilerMode.javacopts())
@@ -679,51 +556,45 @@
" @Inject AllInjections(String s) {}",
" @Inject void s(String s) {}",
"}");
- JavaFileObject expectedMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.AllInjections_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "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());",
- " }",
- "",
- // TODO(b/64477506): now that these all take "object", it would be nice to rename
- // "instance"
- // to the type name
- " @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);",
- " }",
- "",
- "}");
+ JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
+ "test.AllInjections_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "public final class AllInjections_MembersInjector ",
+ " implements MembersInjector<AllInjections> {",
+ "",
+ " private final Provider<String> sProvider;",
+ "",
+ " public AllInjections_MembersInjector(Provider<String> sProvider) {",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " public static MembersInjector<AllInjections> create(Provider<String> sProvider) {",
+ " return new AllInjections_MembersInjector(sProvider);",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(AllInjections instance) {",
+ " injectS(instance, sProvider.get());",
+ " injectS2(instance, sProvider.get());",
+ " }",
+ "",
+ // TODO(b/64477506): now that these all take "object", it would be nice to rename "instance"
+ // to the type name
+ " public static void injectS(Object instance, String s) {",
+ " ((AllInjections) instance).s = s;",
+ " }",
+ "",
+ " public static void injectS2(Object instance, String s) {",
+ " ((AllInjections) instance).s(s);",
+ " }",
+ "",
+ "}");
assertAbout(javaSource())
.that(file)
.withCompilerOptions(compilerMode.javacopts())
@@ -746,38 +617,35 @@
"class B extends A {",
" @Inject String s;",
"}");
- JavaFileObject expectedMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.AllInjections_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class B_MembersInjector implements MembersInjector<B> {",
- " private final Provider<String> sProvider;",
- "",
- " public B_MembersInjector(Provider<String> sProvider) {",
- " this.sProvider = sProvider;",
- " }",
- "",
- " public static MembersInjector<B> create(Provider<String> sProvider) {",
- " return new B_MembersInjector(sProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(B instance) {",
- " injectS(instance, sProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.B.s\")",
- " public static void injectS(Object instance, String s) {",
- " ((B) instance).s = s;",
- " }",
- "}");
+ JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
+ "test.AllInjections_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "public final class B_MembersInjector implements MembersInjector<B> {",
+ " private final Provider<String> sProvider;",
+ "",
+ " public B_MembersInjector(Provider<String> sProvider) {",
+ " this.sProvider = sProvider;",
+ " }",
+ "",
+ " public static MembersInjector<B> create(Provider<String> sProvider) {",
+ " return new B_MembersInjector(sProvider);",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(B instance) {",
+ " injectS(instance, sProvider.get());",
+ " }",
+ "",
+ " public static void injectS(Object instance, String s) {",
+ " ((B) instance).s = s;",
+ " }",
+ "}");
assertAbout(javaSources())
.that(ImmutableList.of(aFile, bFile))
.withCompilerOptions(compilerMode.javacopts())
@@ -808,40 +676,36 @@
" void inject(B b);",
" }",
"}");
- JavaFileObject bMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.OuterType_B_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class OuterType_B_MembersInjector",
- " implements MembersInjector<OuterType.B> {",
- " private final Provider<OuterType.A> aProvider;",
- "",
- " public OuterType_B_MembersInjector(Provider<OuterType.A> aProvider) {",
- " this.aProvider = aProvider;",
- " }",
- "",
- " public static MembersInjector<OuterType.B> create(",
- " Provider<OuterType.A> aProvider) {",
- " return new OuterType_B_MembersInjector(aProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(OuterType.B instance) {",
- " injectA(instance, aProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.OuterType.B.a\")",
- " public static void injectA(Object instance, Object a) {",
- " ((OuterType.B) instance).a = (OuterType.A) a;",
- " }",
- "}");
+ JavaFileObject bMembersInjector = JavaFileObjects.forSourceLines(
+ "test.OuterType_B_MembersInjector",
+ "package test;",
+ "",
+ "import dagger.MembersInjector;",
+ IMPORT_GENERATED_ANNOTATION,
+ "import javax.inject.Provider;",
+ "",
+ GENERATED_ANNOTATION,
+ "public final class OuterType_B_MembersInjector",
+ " implements MembersInjector<OuterType.B> {",
+ " private final Provider<OuterType.A> aProvider;",
+ "",
+ " public OuterType_B_MembersInjector(Provider<OuterType.A> aProvider) {",
+ " this.aProvider = aProvider;",
+ " }",
+ "",
+ " public static MembersInjector<OuterType.B> create(Provider<OuterType.A> aProvider) {",
+ " return new OuterType_B_MembersInjector(aProvider);",
+ " }",
+ "",
+ " @Override",
+ " public void injectMembers(OuterType.B instance) {",
+ " injectA(instance, aProvider.get());",
+ " }",
+ "",
+ " public static void injectA(Object instance, Object a) {",
+ " ((OuterType.B) instance).a = (OuterType.A) a;",
+ " }",
+ "}");
assertAbout(javaSources())
.that(ImmutableList.of(nestedTypesFile))
.withCompilerOptions(compilerMode.javacopts())
@@ -880,11 +744,10 @@
"package test;",
"",
"import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class OuterType_B_MembersInjector",
" implements MembersInjector<OuterType.B> {",
" private final Provider<OuterType.A> aProvider;",
@@ -903,7 +766,6 @@
" injectA(instance, aProvider.get());",
" }",
"",
- " @InjectedFieldSignature(\"test.OuterType.B.a\")",
" public static void injectA(Object instance, Object a) {",
" ((OuterType.B) instance).a = (OuterType.A) a;",
" }",
@@ -990,7 +852,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(foo, fooModule, fooComponent);
assertThat(compilation).succeeded();
assertThat(compilation).generatedFile(CLASS_OUTPUT, "test", "foo_MembersInjector.class");
@@ -1056,11 +919,10 @@
"package test;",
"",
"import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class Child_MembersInjector implements MembersInjector<Child> {",
" private final Provider<Foo> objectProvider;",
" private final Provider<Bar> objectProvider2;",
@@ -1082,7 +944,6 @@
" injectObject(instance, objectProvider2.get());",
" }",
"",
- " @InjectedFieldSignature(\"test.Child.object\")",
" public static void injectObject(Object instance, Object object) {",
" ((Child) instance).object = (Bar) object;",
" }",
@@ -1108,7 +969,7 @@
" @Inject int field;",
" }",
"}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(file);
+ Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("Dagger does not support injection into private classes")
@@ -1128,7 +989,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(
+ daggerCompiler()
+ .withOptions(
compilerMode.javacopts().append("-Adagger.privateMemberValidation=WARNING"))
.compile(file);
assertThat(compilation).succeeded();
@@ -1151,7 +1013,7 @@
" @Inject int field;",
" }",
"}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(file);
+ Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
assertThat(compilation).succeeded();
}
@@ -1175,37 +1037,15 @@
" void inject(RawProviderField rawProviderField);",
"}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(file);
+ Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("Provider cannot be provided")
+ .hadErrorContaining("javax.inject.Provider cannot be provided")
.inFile(file)
.onLineContaining("interface C");
}
@Test
- public void throwExceptionInjectedMethod() {
- JavaFileObject file =
- JavaFileObjects.forSourceLines(
- "test.",
- "package test;",
- "",
- "import dagger.Component;",
- "import javax.inject.Inject;",
- "class SomeClass {",
- "@Inject void inject() throws Exception {}",
- "}");
-
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(file);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Methods with @Inject may not throw checked exceptions. "
- + "Please wrap your exceptions in a RuntimeException instead.")
- .inFile(file)
- .onLineContaining("throws Exception");
- }
-
- @Test
public void rawFrameworkTypeParameter() {
JavaFileObject file =
JavaFileObjects.forSourceLines(
@@ -1225,10 +1065,10 @@
" void inject(RawProviderParameter rawProviderParameter);",
"}");
- Compilation compilation = compilerWithOptions(compilerMode.javacopts()).compile(file);
+ Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("Provider cannot be provided")
+ .hadErrorContaining("javax.inject.Provider cannot be provided")
.inFile(file)
.onLineContaining("interface C");
}
@@ -1254,38 +1094,34 @@
"package test;",
"",
"import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectedType_MembersInjector ",
" implements MembersInjector<InjectedType> {",
- " private final Provider<Integer> primitiveIntProvider;",
- " private final Provider<Integer> boxedIntProvider;",
+ " private final Provider<Integer> boxedIntAndPrimitiveIntProvider;",
"",
" public InjectedType_MembersInjector(",
- " Provider<Integer> primitiveIntProvider, Provider<Integer> boxedIntProvider) {",
- " this.primitiveIntProvider = primitiveIntProvider;",
- " this.boxedIntProvider = boxedIntProvider;",
+ " Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
+ " this.boxedIntAndPrimitiveIntProvider = boxedIntAndPrimitiveIntProvider;",
" }",
"",
" public static MembersInjector<InjectedType> create(",
- " Provider<Integer> primitiveIntProvider, Provider<Integer> boxedIntProvider) {",
- " return new InjectedType_MembersInjector(primitiveIntProvider, boxedIntProvider);}",
+ " Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
+ " return new InjectedType_MembersInjector(boxedIntAndPrimitiveIntProvider);",
+ " }",
"",
" @Override",
" public void injectMembers(InjectedType instance) {",
- " injectPrimitiveInt(instance, primitiveIntProvider.get());",
- " injectBoxedInt(instance, boxedIntProvider.get());",
+ " injectPrimitiveInt(instance, boxedIntAndPrimitiveIntProvider.get());",
+ " injectBoxedInt(instance, boxedIntAndPrimitiveIntProvider.get());",
" }",
"",
- " @InjectedFieldSignature(\"test.InjectedType.primitiveInt\")",
" public static void injectPrimitiveInt(Object instance, int primitiveInt) {",
" ((InjectedType) instance).primitiveInt = primitiveInt;",
" }",
"",
- " @InjectedFieldSignature(\"test.InjectedType.boxedInt\")",
" public static void injectBoxedInt(Object instance, Integer boxedInt) {",
" ((InjectedType) instance).boxedInt = boxedInt;",
" }",
@@ -1299,30 +1135,27 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class InjectedType_Factory implements Factory<InjectedType> {",
- " private final Provider<Integer> primitiveIntProvider;",
+ " private final Provider<Integer> boxedIntAndPrimitiveIntProvider;",
"",
- " private final Provider<Integer> boxedIntProvider;",
- "",
- " public InjectedType_Factory(",
- " Provider<Integer> primitiveIntProvider, Provider<Integer> boxedIntProvider) {",
- " this.primitiveIntProvider = primitiveIntProvider;",
- " this.boxedIntProvider = boxedIntProvider;",
+ " public InjectedType_Factory(Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
+ " this.boxedIntAndPrimitiveIntProvider = boxedIntAndPrimitiveIntProvider;",
" }",
"",
" @Override",
" public InjectedType get() {",
- " InjectedType instance = newInstance();",
+ " InjectedType instance = new InjectedType();",
" InjectedType_MembersInjector.injectPrimitiveInt(",
- " instance, primitiveIntProvider.get());",
- " InjectedType_MembersInjector.injectBoxedInt(instance, boxedIntProvider.get());",
+ " instance, boxedIntAndPrimitiveIntProvider.get());",
+ " InjectedType_MembersInjector.injectBoxedInt(",
+ " instance, boxedIntAndPrimitiveIntProvider.get());",
" return instance;",
" }",
"",
" public static InjectedType_Factory create(",
- " Provider<Integer> primitiveIntProvider, Provider<Integer> boxedIntProvider) {",
- " return new InjectedType_Factory(primitiveIntProvider, boxedIntProvider);",
+ " Provider<Integer> boxedIntAndPrimitiveIntProvider) {",
+ " return new InjectedType_Factory(boxedIntAndPrimitiveIntProvider);",
" }",
"",
" public static InjectedType newInstance() {",
@@ -1330,7 +1163,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(injectedType);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(injectedType);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.InjectedType_MembersInjector")
@@ -1388,7 +1221,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(foo, inaccessible, usesInaccessible, component);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -1399,33 +1233,28 @@
"package other;",
"",
"import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class Inaccessible_MembersInjector",
" implements MembersInjector<Inaccessible> {",
" private final Provider<Foo> fooProvider;",
- " private final Provider<Foo> fooProvider2;",
"",
- " public Inaccessible_MembersInjector(",
- " Provider<Foo> fooProvider, Provider<Foo> fooProvider2) {",
+ " public Inaccessible_MembersInjector(Provider<Foo> fooProvider) {",
" this.fooProvider = fooProvider;",
- " this.fooProvider2 = fooProvider2;",
" }",
"",
- " public static MembersInjector<Inaccessible> create(",
- " Provider<Foo> fooProvider, Provider<Foo> fooProvider2) {",
- " return new Inaccessible_MembersInjector(fooProvider, fooProvider2);}",
+ " public static MembersInjector<Inaccessible> create(Provider<Foo> fooProvider) {",
+ " return new Inaccessible_MembersInjector(fooProvider);",
+ " }",
"",
" @Override",
" public void injectMembers(Inaccessible instance) {",
" injectFoo(instance, fooProvider.get());",
- " injectMethod(instance, fooProvider2.get());",
+ " injectMethod(instance, fooProvider.get());",
" }",
"",
- " @InjectedFieldSignature(\"other.Inaccessible.foo\")",
" public static void injectFoo(Object instance, Object foo) {",
" ((Inaccessible) instance).foo = (Foo) foo;",
" }",
@@ -1447,16 +1276,16 @@
"import other.UsesInaccessible;",
"import other.UsesInaccessible_Factory;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
- " private Object inaccessible() {",
+ " private Object getInaccessible() {",
" return injectInaccessible(Inaccessible_Factory.newInstance());",
" }",
"",
" @Override",
" public UsesInaccessible usesInaccessible() {",
" return UsesInaccessible_Factory.newInstance(",
- " inaccessible());",
+ " getInaccessible());",
" }",
"",
// TODO(ronshapiro): if possible, it would be great to rename "instance", but we
@@ -1529,7 +1358,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(inaccessible, inaccessiblesModule, usesInaccessibles, component);
assertThat(compilation).succeeded();
JavaFileObject generatedComponent =
@@ -1545,13 +1375,13 @@
"import other.UsesInaccessibles_Factory;",
"import other.UsesInaccessibles_MembersInjector;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object listOfInaccessible = new MemoizedSentinel();",
"",
- " private List listOfInaccessible() {",
+ " private List getListOfInaccessible() {",
" Object local = listOfInaccessible;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -1589,7 +1419,7 @@
" UsesInaccessibles_MembersInjector.injectInaccessibles(")
.addLinesIn(
FAST_INIT_MODE,
- " instance, (List) listOfInaccessible());")
+ " instance, (List) getListOfInaccessible());")
.addLinesIn(
DEFAULT_MODE,
" instance, (List) inaccessiblesProvider.get());")
@@ -1658,7 +1488,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(foo, supertype, subtype, injectsSubtype, component);
assertThat(compilation).succeeded();
JavaFileObject generatedComponent =
@@ -1674,15 +1505,15 @@
"import other.Supertype;",
"import other.Supertype_MembersInjector;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
- " private Object subtype() {",
+ " private Object getSubtype() {",
" return injectSubtype(Subtype_Factory.newInstance());",
" }",
"",
" @Override",
" public InjectsSubtype injectsSubtype() {",
- " return InjectsSubtype_Factory.newInstance(subtype());",
+ " return InjectsSubtype_Factory.newInstance(getSubtype());",
" }",
"",
" @CanIgnoreReturnValue",
@@ -1697,227 +1528,4 @@
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(generatedComponent);
}
-
- // Shows that we shouldn't create a members injector for a type that doesn't have
- // @Inject fields or @Inject constructor even if it extends and is extended by types that do.
- @Test
- public void middleClassNoFieldInjection() {
- JavaFileObject classA =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class A extends B {",
- " @Inject String valueA;",
- "}");
- JavaFileObject classB =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "class B extends C {",
- "}");
- JavaFileObject classC =
- JavaFileObjects.forSourceLines(
- "test.C",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class C { ",
- " @Inject String valueC;",
- "}");
- JavaFileObject expectedAMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.A_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class A_MembersInjector implements MembersInjector<A> {",
- " private final Provider<String> valueCProvider;",
- " private final Provider<String> valueAProvider;",
- "",
- " public A_MembersInjector(",
- " Provider<String> valueCProvider, Provider<String> valueAProvider) {",
- " this.valueCProvider = valueCProvider;",
- " this.valueAProvider = valueAProvider;",
- " }",
- "",
- " public static MembersInjector<A> create(",
- " Provider<String> valueCProvider, Provider<String> valueAProvider) {",
- " return new A_MembersInjector(valueCProvider, valueAProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(A instance) {",
- " C_MembersInjector.injectValueC(instance, valueCProvider.get());",
- " injectValueA(instance, valueAProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.A.valueA\")",
- " public static void injectValueA(Object instance, String valueA) {",
- " ((A) instance).valueA = valueA;",
- " }",
- "}");
-
- JavaFileObject expectedCMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.C_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class C_MembersInjector implements MembersInjector<C> {",
- " private final Provider<String> valueCProvider;",
- "",
- " public C_MembersInjector(Provider<String> valueCProvider) {",
- " this.valueCProvider = valueCProvider;",
- " }",
- "",
- " public static MembersInjector<C> create(",
- " Provider<String> valueCProvider) {",
- " return new C_MembersInjector(valueCProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(C instance) {",
- " injectValueC(instance, valueCProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.C.valueC\")",
- " public static void injectValueC(Object instance, String valueC) {",
- " ((C) instance).valueC = valueC;",
- " }",
- "}");
-
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
- .compile(classA, classB, classC);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.A_MembersInjector")
- .hasSourceEquivalentTo(expectedAMembersInjector);
- assertThat(compilation)
- .generatedSourceFile("test.C_MembersInjector")
- .hasSourceEquivalentTo(expectedCMembersInjector);
-
- try {
- assertThat(compilation).generatedSourceFile("test.B_MembersInjector");
- // Can't throw an assertion error since it would be caught.
- throw new IllegalStateException("Test generated a B_MembersInjector");
- } catch (AssertionError expected) {
- }
- }
-
- // Shows that we do generate a MembersInjector for a type that has an @Inject
- // constructor and that extends a type with @Inject fields, even if it has no local field
- // injection sites
- // TODO(erichang): Are these even used anymore?
- @Test
- public void testConstructorInjectedFieldInjection() {
- JavaFileObject classA =
- JavaFileObjects.forSourceLines(
- "test.A",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class A extends B {",
- " @Inject A() {}",
- "}");
- JavaFileObject classB =
- JavaFileObjects.forSourceLines(
- "test.B",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class B { ",
- " @Inject String valueB;",
- "}");
- JavaFileObject expectedAMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.A_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class A_MembersInjector implements MembersInjector<A> {",
- " private final Provider<String> valueBProvider;",
- "",
- " public A_MembersInjector(Provider<String> valueBProvider) {",
- " this.valueBProvider = valueBProvider;",
- " }",
- "",
- " public static MembersInjector<A> create(Provider<String> valueBProvider) {",
- " return new A_MembersInjector(valueBProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(A instance) {",
- " B_MembersInjector.injectValueB(instance, valueBProvider.get());",
- " }",
- "}");
-
- JavaFileObject expectedBMembersInjector =
- JavaFileObjects.forSourceLines(
- "test.B_MembersInjector",
- "package test;",
- "",
- "import dagger.MembersInjector;",
- "import dagger.internal.InjectedFieldSignature;",
- IMPORT_GENERATED_ANNOTATION,
- "import javax.inject.Provider;",
- "",
- GENERATED_CODE_ANNOTATIONS,
- "public final class B_MembersInjector implements MembersInjector<B> {",
- " private final Provider<String> valueBProvider;",
- "",
- " public B_MembersInjector(Provider<String> valueBProvider) {",
- " this.valueBProvider = valueBProvider;",
- " }",
- "",
- " public static MembersInjector<B> create(",
- " Provider<String> valueBProvider) {",
- " return new B_MembersInjector(valueBProvider);",
- " }",
- "",
- " @Override",
- " public void injectMembers(B instance) {",
- " injectValueB(instance, valueBProvider.get());",
- " }",
- "",
- " @InjectedFieldSignature(\"test.B.valueB\")",
- " public static void injectValueB(Object instance, String valueB) {",
- " ((B) instance).valueB = valueB;",
- " }",
- "}");
-
-
- Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
- .compile(classA, classB);
- assertThat(compilation).succeeded();
- assertThat(compilation)
- .generatedSourceFile("test.A_MembersInjector")
- .hasSourceEquivalentTo(expectedAMembersInjector);
- assertThat(compilation)
- .generatedSourceFile("test.B_MembersInjector")
- .hasSourceEquivalentTo(expectedBMembersInjector);
- }
}
diff --git a/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java b/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
index d8cd6d9..68d5daa 100644
--- a/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
+++ b/javatests/dagger/internal/codegen/MembersInjectionValidationTest.java
@@ -236,177 +236,4 @@
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("static fields").inFile(injected).onLine(6);
}
-
- @Test
- public void missingMembersInjectorForKotlinProperty() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinInjectedQualifier;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(KotlinInjectedQualifier injected);",
- "}");
- JavaFileObject module =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Named;",
- "",
- "@Module",
- "class TestModule {",
- " @Provides",
- " @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.");
- }
-
- @Test
- public void memberInjectionForKotlinObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinObjectWithMemberInjection;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(KotlinObjectWithMemberInjection injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(component, testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
- }
-
- @Test
- public void setterMemberInjectionForKotlinObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinObjectWithSetterMemberInjection;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(KotlinObjectWithSetterMemberInjection injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(component, testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
- }
-
- @Test
- public void memberInjectionForKotlinClassWithCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinClassWithMemberInjectedCompanion;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(KotlinClassWithMemberInjectedCompanion injected);",
- " void injectCompanion(KotlinClassWithMemberInjectedCompanion.Companion injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(component, testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into static fields");
- }
-
- @Test
- public void setterMemberInjectionForKotlinClassWithCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinClassWithSetterMemberInjectedCompanion;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(KotlinClassWithSetterMemberInjectedCompanion.Companion injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(component, testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
- }
-
- @Test
- public void memberInjectionForKotlinClassWithNamedCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinClassWithMemberInjectedNamedCompanion;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(KotlinClassWithMemberInjectedNamedCompanion injected);",
- " void injectCompanion(KotlinClassWithMemberInjectedNamedCompanion.TheCompanion"
- + " injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(component, testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into static fields");
- }
-
- @Test
- public void setterMemberInjectionForKotlinClassWithNamedCompanionObjectFails() {
- JavaFileObject component =
- JavaFileObjects.forSourceLines(
- "test.TestComponent",
- "package test;",
- "",
- "import dagger.Component;",
- "import dagger.internal.codegen.KotlinClassWithSetterMemberInjectedNamedCompanion;",
- "",
- "@Component(modules = TestModule.class)",
- "interface TestComponent {",
- " void inject(",
- " KotlinClassWithSetterMemberInjectedNamedCompanion.TheCompanion injected);",
- "}");
- Compilation compilation = daggerCompiler().compile(component, testModule);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining("Dagger does not support injection into Kotlin objects");
- }
-
- private final JavaFileObject testModule =
- JavaFileObjects.forSourceLines(
- "test.TestModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "class TestModule {",
- " @Provides",
- " String theString() { return \"\"; }",
- "}");
}
diff --git a/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java b/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
index 6d2f989..687c29a 100644
--- a/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
+++ b/javatests/dagger/internal/codegen/MethodSignatureFormatterTest.java
@@ -22,20 +22,12 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.testing.compile.CompilationRule;
-import dagger.BindsInstance;
-import dagger.Component;
-import dagger.Module;
-import dagger.Provides;
import dagger.internal.codegen.MethodSignatureFormatterTest.OuterClass.InnerClass;
-import dagger.internal.codegen.binding.InjectionAnnotations;
-import dagger.internal.codegen.binding.MethodSignatureFormatter;
import dagger.internal.codegen.langmodel.DaggerElements;
import dagger.internal.codegen.langmodel.DaggerTypes;
-import javax.inject.Inject;
import javax.inject.Singleton;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,10 +37,6 @@
public class MethodSignatureFormatterTest {
@Rule public CompilationRule compilationRule = new CompilationRule();
- @Inject DaggerElements elements;
- @Inject DaggerTypes types;
- @Inject InjectionAnnotations injectionAnnotations;
-
static class OuterClass {
@interface Foo {
Class<?> bar();
@@ -65,15 +53,13 @@
}
}
- @Before
- public void setUp() {
- DaggerMethodSignatureFormatterTest_TestComponent.factory().create(compilationRule).inject(this);
- }
-
@Test public void methodSignatureTest() {
+ DaggerElements elements =
+ new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
+ DaggerTypes types = new DaggerTypes(compilationRule.getTypes(), elements);
TypeElement inner = elements.getTypeElement(InnerClass.class);
ExecutableElement method = Iterables.getOnlyElement(methodsIn(inner.getEnclosedElements()));
- String formatted = new MethodSignatureFormatter(types, injectionAnnotations).format(method);
+ String formatted = new MethodSignatureFormatter(types).format(method);
// This is gross, but it turns out that annotation order is not guaranteed when getting
// all the AnnotationMirrors from an Element, so I have to test this chopped-up to make it
// less brittle.
@@ -85,28 +71,4 @@
assertThat(formatted).contains(" String "); // return type compressed
assertThat(formatted).contains("int, ImmutableList<Boolean>)"); // parameters compressed.
}
-
- @Singleton
- @Component(modules = TestModule.class)
- interface TestComponent {
- void inject(MethodSignatureFormatterTest test);
-
- @Component.Factory
- interface Factory {
- TestComponent create(@BindsInstance CompilationRule compilationRule);
- }
- }
-
- @Module
- static class TestModule {
- @Provides
- static DaggerElements elements(CompilationRule compilationRule) {
- return new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
- }
-
- @Provides
- static DaggerTypes types(CompilationRule compilationRule, DaggerElements elements) {
- return new DaggerTypes(compilationRule.getTypes(), elements);
- }
- }
}
diff --git a/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java b/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
index 3c066ba..e2f9634 100644
--- a/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
+++ b/javatests/dagger/internal/codegen/MissingBindingSuggestionsTest.java
@@ -18,7 +18,6 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.TestUtils.message;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
@@ -95,9 +94,8 @@
Compilation compilation =
daggerCompiler().compile(fooComponent, barComponent, topComponent, foo, bar, barModule);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
- .hadErrorContaining("A binding with matching key exists in component: BarComponent");
+ .hadErrorContaining("A binding with matching key exists in component: test.BarComponent");
}
@Test public void suggestsBindingInNestedSubcomponent() {
@@ -156,164 +154,7 @@
daggerCompiler()
.compile(fooComponent, barComponent, bazComponent, topComponent, foo, baz, bazModule);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
- .hadErrorContaining("A binding with matching key exists in component: BazComponent");
- }
-
- @Test
- public void missingBindingInParentComponent() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "Parent",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Foo foo();",
- " Bar bar();",
- " Child child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "Child",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules=BazModule.class)",
- "interface Child {",
- " Foo foo();",
- " Baz baz();",
- "}");
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "Foo",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo(Bar bar) {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "Bar",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar(Baz baz) {}",
- "}");
- JavaFileObject baz = JavaFileObjects.forSourceLines("Baz", "class Baz {}");
- JavaFileObject bazModule = JavaFileObjects.forSourceLines(
- "BazModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "@Module",
- "final class BazModule {",
- " @Provides Baz provideBaz() {return new Baz();}",
- "}");
-
- Compilation compilation = daggerCompiler().compile(parent, child, foo, bar, baz, bazModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "\033[1;31m[Dagger/MissingBinding]\033[0m Baz cannot be provided without an "
- + "@Inject constructor or an @Provides-annotated method.",
- "A binding with matching key exists in component: Child",
- " Baz is injected at",
- " Bar(baz)",
- " Bar is requested at",
- " Parent.bar()",
- "The following other entry points also depend on it:",
- " Parent.foo()",
- " Child.foo() [Parent → Child]"))
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-
- @Test
- public void missingBindingInSiblingComponent() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "Parent",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Foo foo();",
- " Bar bar();",
- " Child1 child1();",
- " Child2 child2();",
- "}");
- JavaFileObject child1 =
- JavaFileObjects.forSourceLines(
- "Child1",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child1 {",
- " Foo foo();",
- " Baz baz();",
- "}");
- JavaFileObject child2 =
- JavaFileObjects.forSourceLines(
- "Child2",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = BazModule.class)",
- "interface Child2 {",
- " Foo foo();",
- " Baz baz();",
- "}");
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "Foo",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo(Bar bar) {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "Bar",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar(Baz baz) {}",
- "}");
- JavaFileObject baz = JavaFileObjects.forSourceLines("Baz", "class Baz {}");
- JavaFileObject bazModule = JavaFileObjects.forSourceLines(
- "BazModule",
- "import dagger.Module;",
- "import dagger.Provides;",
- "import javax.inject.Inject;",
- "",
- "@Module",
- "final class BazModule {",
- " @Provides Baz provideBaz() {return new Baz();}",
- "}");
-
- Compilation compilation =
- daggerCompiler().compile(parent, child1, child2, foo, bar, baz, bazModule);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "\033[1;31m[Dagger/MissingBinding]\033[0m Baz cannot be provided without an "
- + "@Inject constructor or an @Provides-annotated method.",
- "A binding with matching key exists in component: Child2",
- " Baz is injected at",
- " Bar(baz)",
- " Bar is requested at",
- " Parent.bar()",
- "The following other entry points also depend on it:",
- " Parent.foo()",
- " Child1.foo() [Parent → Child1]",
- " Child2.foo() [Parent → Child2]",
- " Child1.baz() [Parent → Child1]"))
- .inFile(parent)
- .onLineContaining("interface Parent");
+ .hadErrorContaining("A binding with matching key exists in component: test.BazComponent");
}
}
diff --git a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
index 1aabd48..8eaa8d5 100644
--- a/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
+++ b/javatests/dagger/internal/codegen/MissingBindingValidationTest.java
@@ -56,9 +56,8 @@
"interface Bar {}");
Compilation compilation = daggerCompiler().compile(component, injectable, nonInjectable);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
- .hadErrorContaining("Bar cannot be provided without an @Provides-annotated method.")
+ .hadErrorContaining("test.Bar cannot be provided without an @Provides-annotated method.")
.inFile(component)
.onLineContaining("interface MyComponent");
}
@@ -82,10 +81,9 @@
"}");
Compilation compilation = daggerCompiler().compile(component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "\033[1;31m[Dagger/MissingBinding]\033[0m TestClass.A cannot be provided "
+ "[Dagger/MissingBinding] test.TestClass.A cannot be provided "
+ "without an @Provides-annotated method.")
.inFile(component)
.onLineContaining("interface AComponent");
@@ -112,10 +110,9 @@
"}");
Compilation compilation = daggerCompiler().compile(component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "\033[1;31m[Dagger/MissingBinding]\033[0m @TestClass.Q TestClass.A cannot be provided "
+ "[Dagger/MissingBinding] @test.TestClass.Q test.TestClass.A cannot be provided "
+ "without an @Provides-annotated method.")
.inFile(component)
.onLineContaining("interface AComponent");
@@ -143,10 +140,9 @@
Compilation compilation = daggerCompiler().compile(component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "TestClass.A cannot be provided without an @Inject constructor or an "
+ "test.TestClass.A cannot be provided without an @Inject constructor or an "
+ "@Provides-annotated method.")
.inFile(component)
.onLineContaining("interface AComponent");
@@ -178,10 +174,9 @@
Compilation compilation = daggerCompiler().compile(component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "TestClass.B cannot be provided without an @Inject constructor or an "
+ "test.TestClass.B cannot be provided without an @Inject constructor or an "
+ "@Provides-annotated method. This type supports members injection but cannot be "
+ "implicitly provided.")
.inFile(component)
@@ -215,9 +210,8 @@
Compilation compilation = daggerCompiler().compile(self, component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
- .hadErrorContaining("Self cannot be provided without an @Inject constructor")
+ .hadErrorContaining("test.Self cannot be provided without an @Inject constructor")
.inFile(component)
.onLineContaining("interface SelfComponent");
}
@@ -247,10 +241,9 @@
"}");
Compilation compilation = daggerCompiler().compile(component, foo);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
- "Foo<? extends Number> cannot be provided "
+ "test.Foo<? extends java.lang.Number> cannot be provided "
+ "without an @Provides-annotated method");
}
@@ -307,22 +300,21 @@
Compilation compilation = daggerCompiler().compile(component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "TestClass.A cannot be provided without an @Provides-annotated method.",
- " TestClass.A is injected at",
- " TestClass.B(a)",
- " TestClass.B is injected at",
- " TestClass.C.b",
- " TestClass.C is injected at",
- " TestClass.AComponent.injectC(TestClass.C)",
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.",
+ " test.TestClass.A is injected at",
+ " test.TestClass.B(a)",
+ " test.TestClass.B is injected at",
+ " test.TestClass.C.b",
+ " test.TestClass.C is injected at",
+ " test.TestClass.AComponent.injectC(test.TestClass.C)",
"The following other entry points also depend on it:",
- " TestClass.AComponent.getFoo()",
- " TestClass.AComponent.cProvider()",
- " TestClass.AComponent.lazyC()",
- " TestClass.AComponent.lazyCProvider()"))
+ " test.TestClass.AComponent.getFoo()",
+ " test.TestClass.AComponent.cProvider()",
+ " test.TestClass.AComponent.lazyC()",
+ " test.TestClass.AComponent.lazyCProvider()"))
.inFile(component)
.onLineContaining("interface AComponent");
}
@@ -362,17 +354,16 @@
Compilation compilation =
daggerCompiler().compile(component, module, interfaceFile, implementationFile);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "String cannot be provided without an @Inject constructor or an "
+ "java.lang.String cannot be provided without an @Inject constructor or an "
+ "@Provides-annotated method.",
- " String is injected at",
+ " java.lang.String is injected at",
" TestImplementation(missingBinding)",
" TestImplementation is injected at",
" TestModule.bindTestInterface(implementation)",
- " TestInterface is requested at",
+ " TestInterface is provided at",
" TestComponent.testInterface()"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -417,19 +408,18 @@
Compilation compilation = daggerCompiler().compile(generic, testClass, usesTest, component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "List cannot be provided without an @Provides-annotated method.",
- " List is injected at",
- " TestClass(list)",
- " TestClass is injected at",
- " Generic(t)",
- " Generic<TestClass> is injected at",
- " UsesTest(genericTestClass)",
- " UsesTest is requested at",
- " TestComponent.usesTest()"));
+ "java.util.List cannot be provided without an @Provides-annotated method.",
+ " java.util.List is injected at",
+ " test.TestClass(list)",
+ " test.TestClass is injected at",
+ " test.Generic(t)",
+ " test.Generic<test.TestClass> is injected at",
+ " test.UsesTest(genericTestClass)",
+ " test.UsesTest is provided at",
+ " test.TestComponent.usesTest()"));
}
@Test public void resolvedVariablesInDependencyTrace() {
@@ -472,19 +462,18 @@
Compilation compilation = daggerCompiler().compile(generic, testClass, usesTest, component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "List cannot be provided without an @Provides-annotated method.",
- " List is injected at",
- " TestClass(list)",
- " TestClass is injected at",
- " Generic.t",
- " Generic<TestClass> is injected at",
- " UsesTest(genericTestClass)",
- " UsesTest is requested at",
- " TestComponent.usesTest()"));
+ "java.util.List cannot be provided without an @Provides-annotated method.",
+ " java.util.List is injected at",
+ " test.TestClass(list)",
+ " test.TestClass is injected at",
+ " test.Generic.t",
+ " test.Generic<test.TestClass> is injected at",
+ " test.UsesTest(genericTestClass)",
+ " test.UsesTest is provided at",
+ " test.TestComponent.usesTest()"));
}
@Test
@@ -535,10 +524,9 @@
Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContainingMatch(
- "(?s)\\QString cannot be provided\\E.*\\QChild.needsString()\\E")
+ "(?s)\\Qjava.lang.String cannot be provided\\E.*\\QChild.needsString()\\E")
.inFile(parent)
.onLineContaining("interface Parent");
}
@@ -611,10 +599,9 @@
Compilation compilation =
daggerCompiler().compile(parent, parentModule, child, childModule, grandchild);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContainingMatch(
- "(?s)\\QDouble cannot be provided\\E.*"
+ "(?s)\\Qjava.lang.Double cannot be provided\\E.*"
+ "\\QGrandchild.object() [Parent → Child → Grandchild]\\E$")
.inFile(parent)
.onLineContaining("interface Parent");
@@ -659,20 +646,19 @@
"interface NotBound {}");
Compilation compilation = daggerCompiler().compile(component, module, notBound);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "\033[1;31m[Dagger/MissingBinding]\033[0m "
- + "NotBound cannot be provided without an @Provides-annotated method.",
- " NotBound is injected at",
- " TestModule.object(notBound)",
- " Object is requested at",
- " TestComponent.object()",
+ "[Dagger/MissingBinding] "
+ + "test.NotBound cannot be provided without an @Provides-annotated method.",
+ " test.NotBound is injected at",
+ " test.TestModule.object(notBound)",
+ " java.lang.Object is provided at",
+ " test.TestComponent.object()",
"It is also requested at:",
- " TestModule.string(notBound, …)",
+ " test.TestModule.string(notBound, …)",
"The following other entry points also depend on it:",
- " TestComponent.string()"))
+ " test.TestComponent.string()"))
.inFile(component)
.onLineContaining("interface TestComponent");
assertThat(compilation).hadErrorCount(1);
@@ -719,25 +705,24 @@
Compilation compilation = daggerCompiler().compile(foo, component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "\033[1;31m[Dagger/MissingBinding]\033[0m String cannot be provided without an "
- + "@Inject constructor or an @Provides-annotated method.",
- " String is requested at",
- " TestComponent.string()",
+ "[Dagger/MissingBinding] java.lang.String cannot be provided without an @Inject "
+ + "constructor or an @Provides-annotated method.",
+ " java.lang.String is provided at",
+ " test.TestComponent.string()",
"It is also requested at:",
- " Foo(one, …)",
- " Foo(…, two, …)",
- " Foo(…, three, …)",
- " Foo(…, four, …)",
- " Foo(…, five, …)",
- " Foo(…, six, …)",
- " Foo(…, seven, …)",
- " Foo(…, eight, …)",
- " Foo(…, nine, …)",
- " Foo(…, ten, …)",
+ " test.Foo(one, …)",
+ " test.Foo(…, two, …)",
+ " test.Foo(…, three, …)",
+ " test.Foo(…, four, …)",
+ " test.Foo(…, five, …)",
+ " test.Foo(…, six, …)",
+ " test.Foo(…, seven, …)",
+ " test.Foo(…, eight, …)",
+ " test.Foo(…, nine, …)",
+ " test.Foo(…, ten, …)",
" and 3 others"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -770,162 +755,26 @@
Compilation compilation = daggerCompiler().compile(component);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
assertThat(compilation)
.hadErrorContaining(
message(
- "\033[1;31m[Dagger/MissingBinding]\033[0m String cannot be provided without an "
- + "@Inject constructor or an @Provides-annotated method.",
- " String is requested at",
- " TestComponent.string1()",
+ "[Dagger/MissingBinding] java.lang.String cannot be provided without an @Inject "
+ + "constructor or an @Provides-annotated method.",
+ " java.lang.String is provided at",
+ " test.TestComponent.string1()",
"The following other entry points also depend on it:",
- " TestComponent.string2()",
- " TestComponent.string3()",
- " TestComponent.string4()",
- " TestComponent.string5()",
- " TestComponent.string6()",
- " TestComponent.string7()",
- " TestComponent.string8()",
- " TestComponent.string9()",
- " TestComponent.string10()",
- " TestComponent.string11()",
+ " test.TestComponent.string2()",
+ " test.TestComponent.string3()",
+ " test.TestComponent.string4()",
+ " test.TestComponent.string5()",
+ " test.TestComponent.string6()",
+ " test.TestComponent.string7()",
+ " test.TestComponent.string8()",
+ " test.TestComponent.string9()",
+ " test.TestComponent.string10()",
+ " test.TestComponent.string11()",
" and 1 other"))
.inFile(component)
.onLineContaining("interface TestComponent");
}
-
- @Test
- public void missingBindingInAllComponentsAndEntryPoints() {
- JavaFileObject parent =
- JavaFileObjects.forSourceLines(
- "Parent",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Foo foo();",
- " Bar bar();",
- " Child child();",
- "}");
- JavaFileObject child =
- JavaFileObjects.forSourceLines(
- "Child",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child {",
- " Foo foo();",
- " Baz baz();",
- "}");
- JavaFileObject foo =
- JavaFileObjects.forSourceLines(
- "Foo",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo(Bar bar) {}",
- "}");
- JavaFileObject bar =
- JavaFileObjects.forSourceLines(
- "Bar",
- "import javax.inject.Inject;",
- "",
- "class Bar {",
- " @Inject Bar(Baz baz) {}",
- "}");
- JavaFileObject baz = JavaFileObjects.forSourceLines("Baz", "class Baz {}");
-
- Compilation compilation = daggerCompiler().compile(parent, child, foo, bar, baz);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "\033[1;31m[Dagger/MissingBinding]\033[0m Baz cannot be provided without an "
- + "@Inject constructor or an @Provides-annotated method.",
- " Baz is injected at",
- " Bar(baz)",
- " Bar is requested at",
- " Parent.bar()",
- "The following other entry points also depend on it:",
- " Parent.foo()",
- " Child.foo() [Parent → Child]",
- " Child.baz() [Parent → Child]"))
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-
- // Regression test for b/147423208 where if the same subcomponent was used
- // in two different parts of the hierarchy and only one side had a missing binding
- // incorrect caching during binding graph conversion might cause validation to pass
- // incorrectly.
- @Test
- public void sameSubcomponentUsedInDifferentHierarchies() {
- JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@Component",
- "interface Parent {",
- " Child1 getChild1();",
- " Child2 getChild2();",
- "}");
- JavaFileObject child1 = JavaFileObjects.forSourceLines("test.Child1",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent(modules = LongModule.class)",
- "interface Child1 {",
- " RepeatedSub getSub();",
- "}");
- JavaFileObject child2 = JavaFileObjects.forSourceLines("test.Child2",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface Child2 {",
- " RepeatedSub getSub();",
- "}");
- JavaFileObject repeatedSub = JavaFileObjects.forSourceLines("test.RepeatedSub",
- "package test;",
- "",
- "import dagger.Subcomponent;",
- "",
- "@Subcomponent",
- "interface RepeatedSub {",
- " Foo getFoo();",
- "}");
- JavaFileObject injectable = JavaFileObjects.forSourceLines("test.Foo",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class Foo {",
- " @Inject Foo(Long value) {}",
- "}");
- JavaFileObject module = JavaFileObjects.forSourceLines("test.LongModule",
- "package test;",
- "",
- "import dagger.Module;",
- "import dagger.Provides;",
- "",
- "@Module",
- "interface LongModule {",
- " @Provides static Long provideLong() {",
- " return 0L;",
- " }",
- "}");
- Compilation compilation = daggerCompiler().compile(
- parent, child1, child2, repeatedSub, injectable, module);
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContaining("Long cannot be provided without an @Inject constructor")
- .inFile(parent)
- .onLineContaining("interface Parent");
- }
-
}
diff --git a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
index cbda1b8..50c41ed 100644
--- a/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/ModuleFactoryGeneratorTest.java
@@ -24,8 +24,9 @@
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatMethodInUnannotatedClass;
import static dagger.internal.codegen.DaggerModuleMethodSubject.Factory.assertThatModuleMethod;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
+import static dagger.internal.codegen.GeneratedLines.NPE_FROM_PROVIDES_METHOD;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
@@ -228,7 +229,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
"",
@@ -245,7 +246,8 @@
" }",
"",
" public static String provideString(TestModule instance) {",
- " return Preconditions.checkNotNullFromProvides(instance.provideString());",
+ " return Preconditions.checkNotNull(",
+ " instance.provideString(), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
assertAbout(javaSource()).that(moduleFile)
@@ -275,7 +277,7 @@
"import dagger.internal.Factory;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
"",
@@ -321,7 +323,7 @@
"import dagger.internal.Factory;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
"",
@@ -395,7 +397,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideObjectsFactory",
" implements Factory<List<Object>> {",
" private final TestModule module;",
@@ -430,8 +432,8 @@
"",
" public static List<Object> provideObjects(",
" TestModule instance, Object a, Object b, MembersInjector<X> xInjector) {",
- " return Preconditions.checkNotNullFromProvides(",
- " instance.provideObjects(a, b, xInjector));",
+ " return Preconditions.checkNotNull(",
+ " instance.provideObjects(a, b, xInjector), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
assertAbout(javaSources()).that(
@@ -465,7 +467,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideStringFactory implements Factory<String> {",
" private final TestModule module;",
"",
@@ -482,7 +484,9 @@
" }",
"",
" public static String provideString(TestModule instance) {",
- " return Preconditions.checkNotNullFromProvides(instance.provideString());",
+ " return Preconditions.checkNotNull(instance.provideString(), "
+ + NPE_FROM_PROVIDES_METHOD
+ + ");",
" }",
"}");
assertAbout(javaSource()).that(moduleFile)
@@ -518,7 +522,7 @@
"import java.util.List;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideWildcardListFactory implements "
+ "Factory<List<List<?>>> {",
" private final TestModule module;",
@@ -536,8 +540,8 @@
" }",
"",
" public static List<List<?>> provideWildcardList(TestModule instance) {",
- " return Preconditions.checkNotNullFromProvides(",
- " instance.provideWildcardList());",
+ " return Preconditions.checkNotNull(",
+ " instance.provideWildcardList(), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
assertAbout(javaSource()).that(moduleFile)
@@ -571,7 +575,7 @@
"import java.util.Set;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_ProvideStringsFactory implements Factory<Set<String>> {",
" private final TestModule module;",
"",
@@ -588,8 +592,8 @@
" }",
"",
" public static Set<String> provideStrings(TestModule instance) {",
- " return Preconditions.checkNotNullFromProvides(",
- " instance.provideStrings());",
+ " return Preconditions.checkNotNull(",
+ " instance.provideStrings(), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
assertAbout(javaSource()).that(moduleFile)
@@ -720,7 +724,6 @@
.onLine(6);
}
-
@Test
public void enclosedInPrivateModule() {
JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
@@ -883,7 +886,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ParentModule_ProvideListBFactory<A extends CharSequence,",
" B, C extends Number & Comparable<C>> implements Factory<List<B>> {",
" private final ParentModule<A, B, C> module;",
@@ -908,7 +911,8 @@
"",
" public static <A extends CharSequence, B, C extends Number & Comparable<C>> List<B>",
" provideListB(ParentModule<A, B, C> instance, B b) {",
- " return Preconditions.checkNotNullFromProvides(instance.provideListB(b));",
+ " return Preconditions.checkNotNull(",
+ " instance.provideListB(b), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
JavaFileObject bElementFactory =
@@ -921,7 +925,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ParentModule_ProvideBElementFactory<A extends CharSequence,",
" B, C extends Number & Comparable<C>> implements Factory<B> {",
" private final ParentModule<A, B, C> module;",
@@ -947,7 +951,8 @@
" public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
" B provideBElement(",
" ParentModule<A, B, C> instance, B b) {",
- " return Preconditions.checkNotNullFromProvides(instance.provideBElement(b));",
+ " return Preconditions.checkNotNull(",
+ " instance.provideBElement(b), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
JavaFileObject bEntryFactory =
@@ -960,7 +965,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ParentModule_ProvideBEntryFactory<A extends CharSequence,",
" B, C extends Number & Comparable<C>> implements Factory<B>> {",
" private final ParentModule<A, B, C> module;",
@@ -986,7 +991,8 @@
" public static <A extends CharSequence, B, C extends Number & Comparable<C>>",
" B provideBEntry(",
" ParentModule<A, B, C> instance, B b) {",
- " return Preconditions.checkNotNullFromProvides(instance.provideBEntry(b));",
+ " return Preconditions.checkNotNull(",
+ " instance.provideBEntry(b), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
JavaFileObject numberFactory =
@@ -998,7 +1004,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ChildNumberModule_ProvideNumberFactory",
" implements Factory<Number> {",
" private final ChildNumberModule module;",
@@ -1018,7 +1024,8 @@
" }",
"",
" public static Number provideNumber(ChildNumberModule instance) {",
- " return Preconditions.checkNotNullFromProvides(instance.provideNumber());",
+ " return Preconditions.checkNotNull(",
+ " instance.provideNumber(), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
JavaFileObject integerFactory =
@@ -1030,7 +1037,7 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ChildIntegerModule_ProvideIntegerFactory",
" implements Factory<Integer> {",
" private final ChildIntegerModule module;",
@@ -1050,8 +1057,8 @@
" }",
"",
" public static Integer provideInteger(ChildIntegerModule instance) {",
- " return Preconditions.checkNotNullFromProvides(",
- " instance.provideInteger());",
+ " return Preconditions.checkNotNull(",
+ " instance.provideInteger(), " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
assertAbout(javaSources())
@@ -1104,26 +1111,24 @@
"import java.util.Map;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ParameterizedModule_ProvideMapStringNumberFactory",
" implements Factory<Map<String, Number>> {",
+ " private static final ParameterizedModule_ProvideMapStringNumberFactory INSTANCE =",
+ " new ParameterizedModule_ProvideMapStringNumberFactory();",
+ "",
" @Override",
" public Map<String, Number> get() {",
" return provideMapStringNumber();",
" }",
"",
" public static ParameterizedModule_ProvideMapStringNumberFactory create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static Map<String, Number> provideMapStringNumber() {",
- " return Preconditions.checkNotNullFromProvides(",
- " ParameterizedModule.provideMapStringNumber());",
- " }",
- "",
- " private static final class InstanceHolder {",
- " private static final ParameterizedModule_ProvideMapStringNumberFactory INSTANCE =",
- " new ParameterizedModule_ProvideMapStringNumberFactory();",
+ " return Preconditions.checkNotNull(ParameterizedModule.provideMapStringNumber(),",
+ " " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
@@ -1136,26 +1141,24 @@
"import dagger.internal.Preconditions;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ParameterizedModule_ProvideNonGenericTypeFactory",
" implements Factory<Object> {",
+ " private static final ParameterizedModule_ProvideNonGenericTypeFactory INSTANCE = ",
+ " new ParameterizedModule_ProvideNonGenericTypeFactory();",
+ "",
" @Override",
" public Object get() {",
" return provideNonGenericType();",
" }",
"",
" public static ParameterizedModule_ProvideNonGenericTypeFactory create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static Object provideNonGenericType() {",
- " return Preconditions.checkNotNullFromProvides(",
- " ParameterizedModule.provideNonGenericType());",
- " }",
- "",
- " private static final class InstanceHolder {",
- " private static final ParameterizedModule_ProvideNonGenericTypeFactory INSTANCE =",
- " new ParameterizedModule_ProvideNonGenericTypeFactory();",
+ " return Preconditions.checkNotNull(ParameterizedModule.provideNonGenericType(),",
+ " " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
@@ -1169,7 +1172,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class ParameterizedModule_ProvideNonGenericTypeWithDepsFactory",
" implements Factory<String> {",
" private final Provider<Object> oProvider;",
@@ -1190,8 +1193,9 @@
" }",
"",
" public static String provideNonGenericTypeWithDeps(Object o) {",
- " return Preconditions.checkNotNullFromProvides(",
- " ParameterizedModule.provideNonGenericTypeWithDeps(o));",
+ " return Preconditions.checkNotNull(",
+ " ParameterizedModule.provideNonGenericTypeWithDeps(o),",
+ " " + NPE_FROM_PROVIDES_METHOD + ");",
" }",
"}");
@@ -1406,7 +1410,7 @@
"test.TestModule_GetFactory",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_GetFactory implements Factory<Integer> {",
" @Override",
" public Integer get() {",
@@ -1414,7 +1418,7 @@
" }",
"",
" public static TestModule_GetFactory create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static int proxyGet() {",
@@ -1429,7 +1433,7 @@
"test.TestModule_CreateFactory",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"public final class TestModule_CreateFactory implements Factory<Boolean> {",
" @Override",
" public Boolean get() {",
@@ -1437,7 +1441,7 @@
" }",
"",
" public static TestModule_CreateFactory create() {",
- " return InstanceHolder.INSTANCE;",
+ " return INSTANCE;",
" }",
"",
" public static boolean proxyCreate() {",
diff --git a/javatests/dagger/internal/codegen/ModuleValidationTest.java b/javatests/dagger/internal/codegen/ModuleValidationTest.java
index 162c8c0..649649a 100644
--- a/javatests/dagger/internal/codegen/ModuleValidationTest.java
+++ b/javatests/dagger/internal/codegen/ModuleValidationTest.java
@@ -342,18 +342,10 @@
"",
"@Module(includes = BadModule.class)",
"abstract class IncludesBadModule {}");
- Compilation compilation = daggerCompiler().compile(badModule, module);
- assertThat(compilation).hadErrorCount(2);
- assertThat(compilation)
+ assertThat(daggerCompiler().compile(badModule, module))
.hadErrorContaining("test.BadModule has errors")
.inFile(module)
.onLine(5);
- assertThat(compilation)
- .hadErrorContaining(
- "@Binds methods must have exactly one parameter, whose type is assignable to the "
- + "return type")
- .inFile(badModule)
- .onLine(8);
}
@Test
diff --git a/javatests/dagger/internal/codegen/MultibindingTest.java b/javatests/dagger/internal/codegen/MultibindingTest.java
index 152adb0..2bf9494 100644
--- a/javatests/dagger/internal/codegen/MultibindingTest.java
+++ b/javatests/dagger/internal/codegen/MultibindingTest.java
@@ -131,7 +131,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Map<String,String> "
+ "java.util.Map<java.lang.String,java.lang.String> "
+ "cannot be provided without an @Provides-annotated method")
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -183,7 +183,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Set<Produced<String>> "
+ "java.util.Set<dagger.producers.Produced<java.lang.String>> "
+ "cannot be provided without an @Provides- or @Produces-annotated method")
.inFile(component)
.onLineContaining("interface TestComponent");
diff --git a/javatests/dagger/internal/codegen/NullableBindingValidationTest.java b/javatests/dagger/internal/codegen/NullableBindingValidationTest.java
new file mode 100644
index 0000000..24d5636
--- /dev/null
+++ b/javatests/dagger/internal/codegen/NullableBindingValidationTest.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2018 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.testing.compile.CompilationSubject.assertThat;
+import static com.google.testing.compile.Compiler.javac;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.NullableBindingValidator.nullableToNonNullable;
+
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.JavaFileObjects;
+import javax.tools.JavaFileObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class NullableBindingValidationTest {
+ private static final JavaFileObject NULLABLE =
+ JavaFileObjects.forSourceLines(
+ "test.Nullable", // force one-string-per-line format
+ "package test;",
+ "",
+ "public @interface Nullable {}");
+
+ @Test public void nullCheckForConstructorParameters() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(String string) {}",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ Compilation compilation2 =
+ javac()
+ .withOptions("-Adagger.nullableValidation=WARNING")
+ .withProcessors(new ComponentProcessor())
+ .compile(NULLABLE, a, module, component);
+ assertThat(compilation2).succeeded();
+ }
+
+ @Test public void nullCheckForMembersInjectParam() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A() {}",
+ " @Inject void register(String string) {}",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ Compilation compilation2 =
+ javac()
+ .withOptions("-Adagger.nullableValidation=WARNING")
+ .withProcessors(new ComponentProcessor())
+ .compile(NULLABLE, a, module, component);
+ assertThat(compilation2).succeeded();
+ }
+
+ @Test public void nullCheckForVariable() {
+ JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
+ "package test;",
+ "",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject String string;",
+ " @Inject A() {}",
+ "}");
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ Compilation compilation2 =
+ javac()
+ .withOptions("-Adagger.nullableValidation=WARNING")
+ .withProcessors(new ComponentProcessor())
+ .compile(NULLABLE, a, module, component);
+ assertThat(compilation2).succeeded();
+ }
+
+ @Test public void nullCheckForComponentReturn() {
+ JavaFileObject module = JavaFileObjects.forSourceLines("test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "final class TestModule {",
+ " @Nullable @Provides String provideString() { return null; }",
+ "}");
+ JavaFileObject component = JavaFileObjects.forSourceLines("test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " String string();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+
+ // but if we disable the validation, then it compiles fine.
+ Compilation compilation2 =
+ javac()
+ .withOptions("-Adagger.nullableValidation=WARNING")
+ .withProcessors(new ComponentProcessor())
+ .compile(NULLABLE, module, component);
+ assertThat(compilation2).succeeded();
+ }
+
+ @Test
+ public void nullCheckForOptionalInstance() {
+ JavaFileObject a =
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import com.google.common.base.Optional;",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(Optional<String> optional) {}",
+ "}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "abstract class TestModule {",
+ " @Nullable @Provides static String provideString() { return null; }",
+ " @BindsOptionalOf abstract String optionalString();",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@test.Nullable @Provides String test.TestModule.provideString()"));
+ }
+
+ @Test
+ public void nullCheckForOptionalProvider() {
+ JavaFileObject a =
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import com.google.common.base.Optional;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class A {",
+ " @Inject A(Optional<Provider<String>> optional) {}",
+ "}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "abstract class TestModule {",
+ " @Nullable @Provides static String provideString() { return null; }",
+ " @BindsOptionalOf abstract String optionalString();",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).succeeded();
+ }
+
+ @Test
+ public void nullCheckForOptionalLazy() {
+ JavaFileObject a =
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import com.google.common.base.Optional;",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "",
+ "final class A {",
+ " @Inject A(Optional<Lazy<String>> optional) {}",
+ "}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "abstract class TestModule {",
+ " @Nullable @Provides static String provideString() { return null; }",
+ " @BindsOptionalOf abstract String optionalString();",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).succeeded();
+ }
+
+ @Test
+ public void nullCheckForOptionalProviderOfLazy() {
+ JavaFileObject a =
+ JavaFileObjects.forSourceLines(
+ "test.A",
+ "package test;",
+ "",
+ "import com.google.common.base.Optional;",
+ "import dagger.Lazy;",
+ "import javax.inject.Inject;",
+ "import javax.inject.Provider;",
+ "",
+ "final class A {",
+ " @Inject A(Optional<Provider<Lazy<String>>> optional) {}",
+ "}");
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.BindsOptionalOf;",
+ "import dagger.Provides;",
+ "import javax.inject.Inject;",
+ "",
+ "@dagger.Module",
+ "abstract class TestModule {",
+ " @Nullable @Provides static String provideString() { return null; }",
+ " @BindsOptionalOf abstract String optionalString();",
+ "}");
+ JavaFileObject component =
+ JavaFileObjects.forSourceLines(
+ "test.TestComponent",
+ "package test;",
+ "",
+ "import dagger.Component;",
+ "",
+ "@Component(modules = TestModule.class)",
+ "interface TestComponent {",
+ " A a();",
+ "}");
+ Compilation compilation = daggerCompiler().compile(NULLABLE, a, module, component);
+ assertThat(compilation).succeeded();
+ }
+
+ @Test
+ public void moduleValidation() {
+ JavaFileObject module =
+ JavaFileObjects.forSourceLines(
+ "test.TestModule",
+ "package test;",
+ "",
+ "import dagger.Binds;",
+ "import dagger.Module;",
+ "import dagger.Provides;",
+ "",
+ "@Module",
+ "abstract class TestModule {",
+ " @Provides @Nullable static String nullableString() { return null; }",
+ " @Binds abstract Object object(String string);",
+ "}");
+
+ Compilation compilation =
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ .compile(module, NULLABLE);
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ nullableToNonNullable(
+ "java.lang.String",
+ "@Provides @test.Nullable String test.TestModule.nullableString()"));
+ }
+}
diff --git a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
index 60b6898..b765166 100644
--- a/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/OptionalBindingRequestFulfillmentTest.java
@@ -20,7 +20,7 @@
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
@@ -110,13 +110,13 @@
"",
"import com.google.common.base.Optional;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Provider<Maybe> provideMaybeProvider;",
"",
- " private Provider<Maybe> maybeProvider() {",
+ " private Provider<Maybe> getMaybeProvider() {",
" Object local = provideMaybeProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -139,7 +139,7 @@
" Maybe_MaybeModule_ProvideMaybeFactory.create()));")
.addLinesIn(
FAST_INIT_MODE, //
- " maybeProvider()));")
+ " getMaybeProvider()));")
.addLines(
" }",
"",
@@ -250,7 +250,7 @@
"import com.google.common.base.Optional;",
"import dagger.producers.internal.CancellationListener;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent, CancellationListener {",
" @Override",
" public ListenableFuture<Optional<Maybe>> maybe() {",
@@ -261,6 +261,7 @@
" @Override",
" public ListenableFuture<Optional<DefinitelyNot>> definitelyNot() {",
" return Futures.immediateFuture(Optional.<DefinitelyNot>absent());",
+
" }",
"",
" @Override",
diff --git a/javatests/dagger/internal/codegen/OptionalBindingTest.java b/javatests/dagger/internal/codegen/OptionalBindingTest.java
index 4e158ef..1755101 100644
--- a/javatests/dagger/internal/codegen/OptionalBindingTest.java
+++ b/javatests/dagger/internal/codegen/OptionalBindingTest.java
@@ -89,7 +89,7 @@
Compilation compilation = daggerCompiler().compile(parent, parentModule, child, childModule);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("Optional<String> is bound multiple times")
+ .hadErrorContaining("Optional<java.lang.String> is bound multiple times")
.inFile(parent)
.onLineContaining("interface Parent");
}
diff --git a/javatests/dagger/internal/codegen/PluginsVisitFullBindingGraphTest.java b/javatests/dagger/internal/codegen/PluginsVisitFullBindingGraphTest.java
deleted file mode 100644
index b766463..0000000
--- a/javatests/dagger/internal/codegen/PluginsVisitFullBindingGraphTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2018 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.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-import static dagger.internal.codegen.TestUtils.endsWithMessage;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-import com.google.testing.compile.Compilation;
-import com.google.testing.compile.Compiler;
-import com.google.testing.compile.JavaFileObjects;
-import dagger.model.BindingGraph;
-import dagger.spi.BindingGraphPlugin;
-import dagger.spi.DiagnosticReporter;
-import java.util.regex.Pattern;
-import javax.tools.JavaFileObject;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Tests for -Adagger.pluginsVisitFullBindingGraph. */
-@RunWith(JUnit4.class)
-public final class PluginsVisitFullBindingGraphTest {
- private static final JavaFileObject MODULE_WITHOUT_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithoutErrors",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface ModuleWithoutErrors {",
- " @Binds Object object(String string);",
- "}");
-
- private static final JavaFileObject MODULE_WITH_ERRORS =
- JavaFileObjects.forSourceLines(
- "test.ModuleWithErrors",
- "package test;",
- "",
- "import dagger.Binds;",
- "import dagger.Module;",
- "",
- "@Module",
- "interface ModuleWithErrors {",
- " @Binds Object object1(String string);",
- " @Binds Object object2(Long l);",
- "}");
-
- private static final Pattern PLUGIN_ERROR_MESSAGE =
- endsWithMessage(
- "[dagger.internal.codegen.PluginsVisitFullBindingGraphTest.ErrorPlugin] Error!");
-
- @Test
- public void testNoFlags() {
- Compilation compilation = daggerCompiler().compile(MODULE_WITH_ERRORS);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void testWithVisitPlugins() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.pluginsVisitFullBindingGraphs=Enabled")
- .compile(MODULE_WITH_ERRORS);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContainingMatch(PLUGIN_ERROR_MESSAGE)
- .inFile(MODULE_WITH_ERRORS)
- .onLineContaining("interface ModuleWithErrors");
- }
-
- @Test
- public void testWithValidationNone() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=NONE")
- .compile(MODULE_WITHOUT_ERRORS);
- assertThat(compilation).succeeded();
- }
-
- @Test
- public void testWithValidationError() {
- // Test that pluginsVisitFullBindingGraph is enabled with fullBindingGraphValidation.
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .compile(MODULE_WITHOUT_ERRORS);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContainingMatch(PLUGIN_ERROR_MESSAGE)
- .inFile(MODULE_WITHOUT_ERRORS)
- .onLineContaining("interface ModuleWithoutErrors");
- }
-
- @Test
- public void testWithValidationErrorAndVisitPlugins() {
- Compilation compilation =
- daggerCompiler()
- .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
- .withOptions("-Adagger.pluginsVisitFullBindingGraphs=Enabled")
- .compile(MODULE_WITHOUT_ERRORS);
-
- assertThat(compilation).failed();
- assertThat(compilation).hadErrorCount(1);
- assertThat(compilation)
- .hadErrorContainingMatch(PLUGIN_ERROR_MESSAGE)
- .inFile(MODULE_WITHOUT_ERRORS)
- .onLineContaining("interface ModuleWithoutErrors");
- }
-
- /** A test plugin that just reports each component with the given {@link Diagnostic.Kind}. */
- private static final class ErrorPlugin implements BindingGraphPlugin {
- @Override
- public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter diagnosticReporter) {
- diagnosticReporter.reportComponent(ERROR, bindingGraph.rootComponentNode(), "Error!");
- }
- }
-
- private static Compiler daggerCompiler() {
- return javac().withProcessors(ComponentProcessor.forTesting(new ErrorPlugin()));
- }
-}
diff --git a/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java b/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
index d41bc2d..0b6ef8f 100644
--- a/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
+++ b/javatests/dagger/internal/codegen/ProducerModuleFactoryGeneratorTest.java
@@ -214,7 +214,6 @@
.onLine(6);
}
-
@Test
public void enclosedInPrivateModule() {
JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.Enclosing",
@@ -370,8 +369,8 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
+ "@SuppressWarnings(\"FutureReturnValueIgnored\")",
GENERATED_ANNOTATION,
- "@SuppressWarnings({\"FutureReturnValueIgnored\", \"unchecked\", \"rawtypes\"})",
"public final class TestModule_ProduceStringFactory",
" extends AbstractProducesMethodProducer<Void, String> {",
" private final TestModule module;",
@@ -443,8 +442,8 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
+ "@SuppressWarnings(\"FutureReturnValueIgnored\")",
GENERATED_ANNOTATION,
- "@SuppressWarnings({\"FutureReturnValueIgnored\", \"unchecked\", \"rawtypes\"})",
"public final class TestModule_ProduceStringFactory",
" extends AbstractProducesMethodProducer<Void, String> {",
" private final TestModule module;",
diff --git a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
index 797fe2e..9a852c7 100644
--- a/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
+++ b/javatests/dagger/internal/codegen/ProductionComponentProcessorTest.java
@@ -19,9 +19,8 @@
import static com.google.common.truth.Truth.assertAbout;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
@@ -70,7 +69,7 @@
" INSTANCE",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("interface");
}
@@ -84,7 +83,7 @@
"@ProductionComponent",
"@interface NotAComponent {}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("interface");
}
@@ -98,7 +97,7 @@
"@ProductionComponent(modules = Object.class)",
"interface NotAComponent {}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(componentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(componentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining("is not annotated with one of @Module, @ProducerModule");
@@ -162,16 +161,17 @@
.compile(moduleFile, producerModuleFile, componentFile);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("String may not depend on the production executor")
+ .hadErrorContaining("java.lang.String may not depend on the production executor")
.inFile(componentFile)
.onLineContaining("interface SimpleComponent");
compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(producerModuleFile);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("String may not depend on the production executor")
+ .hadErrorContaining("java.lang.String may not depend on the production executor")
.inFile(producerModuleFile)
.onLineContaining("class SimpleModule");
// TODO(dpb): Report at the binding if enclosed in the module.
@@ -248,7 +248,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestClass_SimpleComponent",
" implements TestClass.SimpleComponent, CancellationListener {",
" private final TestClass.BModule bModule;",
@@ -278,7 +278,7 @@
" return new Builder().build();",
" }",
"",
- " private Executor productionImplementationExecutor() {",
+ " private Executor getProductionImplementationExecutor() {",
" Object local = productionImplementationExecutor;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -295,7 +295,7 @@
" return (Executor) local;",
" }",
"",
- " private Provider<Executor> productionImplementationExecutorProvider() {",
+ " private Provider<Executor> getProductionImplementationExecutorProvider() {",
" Object local = productionImplementationExecutorProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -304,7 +304,7 @@
" return (Provider<Executor>) local;",
" }",
"",
- " private ProductionComponentMonitor productionComponentMonitor() {",
+ " private ProductionComponentMonitor getProductionComponentMonitor() {",
" Object local = productionComponentMonitor;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -325,7 +325,7 @@
" }",
"",
" private Provider<ProductionComponentMonitor>",
- " productionComponentMonitorProvider() {",
+ " getProductionComponentMonitorProvider() {",
" Object local = monitorProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(1);",
@@ -334,11 +334,11 @@
" return (Provider<ProductionComponentMonitor>) local;",
" }",
"",
- " private TestClass.B b() {",
+ " private TestClass.B getB() {",
" return TestClass_BModule_BFactory.b(bModule, new TestClass.C());",
" }",
"",
- " private Provider<TestClass.B> bProvider() {",
+ " private Provider<TestClass.B> getBProvider() {",
" Object local = bProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(2);",
@@ -353,12 +353,12 @@
" final TestClass.BModule bModuleParam) {",
" this.simpleComponentProvider =",
" InstanceFactory.create((TestClass.SimpleComponent) this);",
- " this.bProducer = Producers.producerFromProvider(bProvider());",
+ " this.bProducer = Producers.producerFromProvider(getBProvider());",
" this.aProducer =",
" TestClass_AModule_AFactory.create(",
" aModuleParam,",
- " productionImplementationExecutorProvider(),",
- " productionComponentMonitorProvider(),",
+ " getProductionImplementationExecutorProvider(),",
+ " getProductionComponentMonitorProvider(),",
" bProducer);",
" this.aEntryPoint = Producers.entryPointViewOf(aProducer, this);",
" }",
@@ -413,11 +413,11 @@
" public T get() {",
" switch (id) {",
" case 0: return (T) DaggerTestClass_SimpleComponent.this",
- " .productionImplementationExecutor();",
+ " .getProductionImplementationExecutor();",
" case 1: return (T)",
- " DaggerTestClass_SimpleComponent.this.productionComponentMonitor();",
+ " DaggerTestClass_SimpleComponent.this.getProductionComponentMonitor();",
" case 2: return (T)",
- " DaggerTestClass_SimpleComponent.this.b();",
+ " DaggerTestClass_SimpleComponent.this.getB();",
" default: throw new AssertionError(id);",
" }",
" }",
@@ -443,7 +443,7 @@
IMPORT_GENERATED_ANNOTATION,
"import javax.inject.Provider;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestClass_SimpleComponent",
" implements TestClass.SimpleComponent, CancellationListener {",
" private Producer<TestClass.A> aEntryPoint;",
@@ -592,7 +592,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(component);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(component);
assertThat(compilation).succeeded();
assertThat(compilation)
.hadWarningContaining("@Nullable on @Produces methods does not do anything")
@@ -641,7 +641,8 @@
" ProductionScoped productionScoped();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(productionScoped, parent, child);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -650,7 +651,7 @@
new JavaFileBuilder(compilerMode, "test.DaggerRoot")
.addLines(
"package test;",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent, CancellationListener {",
" private final class ChildImpl implements Child, CancellationListener {",
" @Override",
@@ -660,7 +661,7 @@
" return DaggerParent.this.productionScopedProvider.get();")
.addLinesIn(
CompilerMode.FAST_INIT_MODE, //
- " return DaggerParent.this.productionScoped();")
+ " return DaggerParent.this.getProductionScoped();")
.addLines(
" }", //
" }", //
diff --git a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
index 3e416e9..8453e03 100644
--- a/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
+++ b/javatests/dagger/internal/codegen/ProductionGraphValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import com.google.testing.compile.Compilation;
@@ -78,7 +77,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Bar cannot be provided without an @Inject constructor or an @Provides- or "
+ "test.Bar cannot be provided without an @Inject constructor or an @Provides- or "
+ "@Produces-annotated method.")
.inFile(component)
.onLineContaining("interface MyComponent");
@@ -104,7 +103,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "TestClass.A cannot be provided without an @Provides- or @Produces-annotated "
+ "test.TestClass.A cannot be provided without an @Provides- or @Produces-annotated "
+ "method.")
.inFile(component)
.onLineContaining("interface AComponent");
@@ -149,16 +148,17 @@
Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("TestClass.A is a provision, which cannot depend on a production.")
+ .hadErrorContaining("test.TestClass.A is a provision, which cannot depend on a production.")
.inFile(component)
.onLineContaining("interface AComponent");
compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(EXECUTOR_MODULE, component);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("TestClass.A is a provision, which cannot depend on a production.")
+ .hadErrorContaining("test.TestClass.A is a provision, which cannot depend on a production.")
.inFile(component)
.onLineContaining("class AModule");
}
@@ -194,7 +194,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "TestClass.A is a provision entry-point, which cannot depend on a production.")
+ "test.TestClass.A is a provision entry-point, which cannot depend on a production.")
.inFile(component)
.onLineContaining("interface AComponent");
}
@@ -252,7 +252,7 @@
Compilation compilation = daggerCompiler().compile(EXECUTOR_MODULE, component);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("TestClass.A is a provision, which cannot depend on a production")
+ .hadErrorContaining("test.TestClass.A is a provision, which cannot depend on a production")
.inFile(component)
.onLineContaining("interface AComponent");
}
@@ -303,7 +303,7 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "TestClass.A cannot be provided without an @Provides-annotated method.")
+ "test.TestClass.A cannot be provided without an @Provides-annotated method.")
.inFile(component)
.onLineContaining("interface StringComponent");
}
@@ -357,8 +357,8 @@
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Set<ProductionComponentMonitor.Factory>"
- + " TestClass.MonitoringModule#monitorFactory is a provision,"
+ "java.util.Set<dagger.producers.monitoring.ProductionComponentMonitor.Factory>"
+ + " test.TestClass.MonitoringModule#monitorFactory is a provision,"
+ " which cannot depend on a production.")
.inFile(component)
.onLineContaining("interface StringComponent");
@@ -488,7 +488,7 @@
Compilation compilation = daggerCompiler().compile(badModule, badComponent);
assertThat(compilation).failed();
assertThat(compilation)
- .hadErrorContaining("BadModule has errors")
+ .hadErrorContaining("test.BadModule has errors")
.inFile(badComponent)
.onLine(7);
}
diff --git a/javatests/dagger/internal/codegen/ScopingValidationTest.java b/javatests/dagger/internal/codegen/ScopingValidationTest.java
index 58ab2af..9efcc2a 100644
--- a/javatests/dagger/internal/codegen/ScopingValidationTest.java
+++ b/javatests/dagger/internal/codegen/ScopingValidationTest.java
@@ -17,7 +17,6 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static dagger.internal.codegen.TestUtils.message;
@@ -77,9 +76,9 @@
assertThat(compilation)
.hadErrorContaining(
message(
- "MyComponent (unscoped) may not reference scoped bindings:",
- " @Singleton class ScopedType",
- " @Provides @Singleton String ScopedModule.string()"));
+ "test.MyComponent (unscoped) may not reference scoped bindings:",
+ " @Singleton class test.ScopedType",
+ " @Provides @Singleton String test.ScopedModule.string()"));
}
@Test // b/79859714
@@ -158,9 +157,9 @@
assertThat(compilation)
.hadErrorContaining(
message(
- "Parent scoped with @Singleton may not reference bindings with different "
+ "test.Parent scoped with @Singleton may not reference bindings with different "
+ "scopes:",
- " @Binds @ChildScope Foo ParentModule.bind(FooImpl)"));
+ " @Binds @test.ChildScope test.Foo test.ParentModule.bind(test.FooImpl)"));
}
@Test
@@ -233,27 +232,28 @@
assertThat(compilation)
.hadErrorContaining(
message(
- "MyComponent scoped with @Singleton "
+ "test.MyComponent scoped with @Singleton "
+ "may not reference bindings with different scopes:",
- " @PerTest class ScopedType",
- " @Provides @PerTest String ScopedModule.string()",
- " @Provides @Per(MyComponent.class) boolean "
- + "ScopedModule.bool()"))
+ " @test.PerTest class test.ScopedType",
+ " @Provides @test.PerTest String test.ScopedModule.string()",
+ " @Provides @test.Per(test.MyComponent.class) boolean "
+ + "test.ScopedModule.bool()"))
.inFile(componentFile)
.onLineContaining("interface MyComponent");
compilation =
- compilerWithOptions("-Adagger.fullBindingGraphValidation=ERROR")
+ daggerCompiler()
+ .withOptions("-Adagger.fullBindingGraphValidation=ERROR")
.compile(componentFile, scopeFile, scopeWithAttribute, typeFile, moduleFile);
// The @Inject binding for ScopedType should not appear here, but the @Singleton binding should.
assertThat(compilation)
.hadErrorContaining(
message(
- "ScopedModule contains bindings with different scopes:",
- " @Provides @PerTest String ScopedModule.string()",
- " @Provides @Singleton float ScopedModule.floatingPoint()",
- " @Provides @Per(MyComponent.class) boolean "
- + "ScopedModule.bool()"))
+ "test.ScopedModule contains bindings with different scopes:",
+ " @Provides @test.PerTest String test.ScopedModule.string()",
+ " @Provides @Singleton float test.ScopedModule.floatingPoint()",
+ " @Provides @test.Per(test.MyComponent.class) boolean "
+ + "test.ScopedModule.bool()"))
.inFile(moduleFile)
.onLineContaining("class ScopedModule");
}
@@ -261,7 +261,8 @@
@Test
public void fullBindingGraphValidationDoesNotReportForOneScope() {
Compilation compilation =
- compilerWithOptions(
+ daggerCompiler()
+ .withOptions(
"-Adagger.fullBindingGraphValidation=ERROR",
"-Adagger.moduleHasDifferentScopesValidation=ERROR")
.compile(
@@ -285,7 +286,8 @@
@Test
public void fullBindingGraphValidationDoesNotReportInjectBindings() {
Compilation compilation =
- compilerWithOptions(
+ daggerCompiler()
+ .withOptions(
"-Adagger.fullBindingGraphValidation=ERROR",
"-Adagger.moduleHasDifferentScopesValidation=ERROR")
.compile(
@@ -382,8 +384,9 @@
}
@Test
- public void componentWithScopeCanDependOnMultipleScopedComponents() {
- // If a scoped component will have dependencies, they can include multiple scoped component
+ public void componentWithScopeMayDependOnOnlyOneScopedComponent() {
+ // If a scoped component will have dependencies, they must only include, at most, a single
+ // scoped component
JavaFileObject type =
JavaFileObjects.forSourceLines(
"test.SimpleType",
@@ -458,116 +461,14 @@
daggerCompiler()
.compile(
type, simpleScope, simpleScoped, singletonScopedA, singletonScopedB, scopeless);
- assertThat(compilation).succeededWithoutWarnings();
- }
-
-
-
- // Tests the following component hierarchy:
- //
- // @ScopeA
- // ComponentA
- // [SimpleType getSimpleType()]
- // / \
- // / \
- // @ScopeB @ScopeB
- // ComponentB1 ComponentB2
- // \ [SimpleType getSimpleType()]
- // \ /
- // \ /
- // @ScopeC
- // ComponentC
- // [SimpleType getSimpleType()]
- @Test
- public void componentWithScopeCanDependOnMultipleScopedComponentsEvenDoingADiamond() {
- JavaFileObject type =
- JavaFileObjects.forSourceLines(
- "test.SimpleType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class SimpleType {",
- " @Inject SimpleType() {}",
- "}");
- JavaFileObject simpleScope =
- JavaFileObjects.forSourceLines(
- "test.SimpleScope",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface SimpleScope {}");
- JavaFileObject scopeA =
- JavaFileObjects.forSourceLines(
- "test.ScopeA",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeA {}");
- JavaFileObject scopeB =
- JavaFileObjects.forSourceLines(
- "test.ScopeB",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeB {}");
- JavaFileObject componentA =
- JavaFileObjects.forSourceLines(
- "test.ComponentA",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeA",
- "@Component",
- "interface ComponentA {",
- " SimpleType type();",
- "}");
- JavaFileObject componentB1 =
- JavaFileObjects.forSourceLines(
- "test.ComponentB1",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeB",
- "@Component(dependencies = ComponentA.class)",
- "interface ComponentB1 {",
- " SimpleType type();",
- "}");
- JavaFileObject componentB2 =
- JavaFileObjects.forSourceLines(
- "test.ComponentB2",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeB",
- "@Component(dependencies = ComponentA.class)",
- "interface ComponentB2 {",
- "}");
- JavaFileObject componentC =
- JavaFileObjects.forSourceLines(
- "test.ComponentC",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@SimpleScope",
- "@Component(dependencies = {ComponentB1.class, ComponentB2.class})",
- "interface ComponentC {",
- " SimpleType type();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .compile(
- type, simpleScope, scopeA, scopeB,
- componentA, componentB1, componentB2, componentC);
- assertThat(compilation).succeededWithoutWarnings();
+ assertThat(compilation).failed();
+ assertThat(compilation)
+ .hadErrorContaining(
+ message(
+ "@test.SimpleScope test.SimpleScopedComponent depends on more than one scoped "
+ + "component:",
+ " @Singleton test.SingletonComponentA",
+ " @Singleton test.SingletonComponentB"));
}
@Test
@@ -675,98 +576,6 @@
}
@Test
- public void componentScopeWithMultipleScopedDependenciesMustNotCycle() {
- JavaFileObject type =
- JavaFileObjects.forSourceLines(
- "test.SimpleType",
- "package test;",
- "",
- "import javax.inject.Inject;",
- "",
- "class SimpleType {",
- " @Inject SimpleType() {}",
- "}");
- JavaFileObject scopeA =
- JavaFileObjects.forSourceLines(
- "test.ScopeA",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeA {}");
- JavaFileObject scopeB =
- JavaFileObjects.forSourceLines(
- "test.ScopeB",
- "package test;",
- "",
- "import javax.inject.Scope;",
- "",
- "@Scope @interface ScopeB {}");
- JavaFileObject longLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentLong",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeA",
- "@Component",
- "interface ComponentLong {",
- " SimpleType type();",
- "}");
- JavaFileObject mediumLifetime1 =
- JavaFileObjects.forSourceLines(
- "test.ComponentMedium1",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeB",
- "@Component(dependencies = ComponentLong.class)",
- "interface ComponentMedium1 {",
- " SimpleType type();",
- "}");
- JavaFileObject mediumLifetime2 =
- JavaFileObjects.forSourceLines(
- "test.ComponentMedium2",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeB",
- "@Component",
- "interface ComponentMedium2 {",
- "}");
- JavaFileObject shortLifetime =
- JavaFileObjects.forSourceLines(
- "test.ComponentShort",
- "package test;",
- "",
- "import dagger.Component;",
- "",
- "@ScopeA",
- "@Component(dependencies = {ComponentMedium1.class, ComponentMedium2.class})",
- "interface ComponentShort {",
- " SimpleType type();",
- "}");
-
- Compilation compilation =
- daggerCompiler()
- .compile(
- type, scopeA, scopeB,
- longLifetime, mediumLifetime1, mediumLifetime2, shortLifetime);
- assertThat(compilation).failed();
- assertThat(compilation)
- .hadErrorContaining(
- message(
- "test.ComponentShort depends on scoped components in a non-hierarchical scope "
- + "ordering:",
- " @test.ScopeA test.ComponentLong",
- " @test.ScopeB test.ComponentMedium1",
- " @test.ScopeA test.ComponentShort"));
- }
-
- @Test
public void componentScopeAncestryMustNotCycle() {
// The dependency relationship of components is necessarily from shorter lifetimes to
// longer lifetimes. The scoping annotations must reflect this, and so one cannot declare
@@ -845,14 +654,6 @@
" @test.ScopeA test.ComponentLong",
" @test.ScopeB test.ComponentMedium",
" @test.ScopeA test.ComponentShort"));
-
-
- // Test that compilation succeeds when transitive validation is disabled because the scope cycle
- // cannot be detected.
- compilation =
- compilerWithOptions("-Adagger.validateTransitiveComponentDependencies=DISABLED")
- .compile(type, scopeA, scopeB, longLifetime, mediumLifetime, shortLifetime);
- assertThat(compilation).succeeded();
}
@Test
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
index e143370..3fb0e9c 100644
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentTest.java
@@ -18,8 +18,8 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.CLASS_PATH_WITHOUT_GUAVA_OPTION;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
@@ -96,7 +96,7 @@
"",
"import dagger.internal.SetBuilder;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Set<String> strings() {",
@@ -191,9 +191,9 @@
"import other.UsesInaccessible;",
"import other.UsesInaccessible_Factory;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
- " private Set setOfInaccessible2() {",
+ " private Set getSetOfInaccessible2() {",
" return SetBuilder.newSetBuilder(1)",
" .addAll(TestModule_EmptySetFactory.emptySet())",
" .build();",
@@ -203,7 +203,7 @@
" public UsesInaccessible usesInaccessible() {",
" return UsesInaccessible_Factory.newInstance(",
" (Set) Collections.emptySet(),",
- " (Set) setOfInaccessible2());",
+ " (Set) getSetOfInaccessible2());",
" }",
"}");
Compilation compilation =
@@ -266,7 +266,7 @@
"import java.util.Set;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
" private DaggerParent() {}",
"",
@@ -316,7 +316,7 @@
}
private Compiler daggerCompilerWithoutGuava() {
- return compilerWithOptions(compilerMode.javacopts())
- .withClasspath(CLASS_PATH_WITHOUT_GUAVA_OPTION);
+ return daggerCompiler()
+ .withOptions(compilerMode.javacopts().append(CLASS_PATH_WITHOUT_GUAVA_OPTION));
}
}
diff --git a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
index 2e3686f..7a47393 100644
--- a/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
+++ b/javatests/dagger/internal/codegen/SetBindingRequestFulfillmentWithGuavaTest.java
@@ -17,8 +17,8 @@
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.Compilers.daggerCompiler;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
@@ -99,7 +99,7 @@
"",
"import com.google.common.collect.ImmutableSet;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Set<String> strings() {",
@@ -122,7 +122,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(emptySetModuleFile, setModuleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -202,9 +203,9 @@
"import other.UsesInaccessible;",
"import other.UsesInaccessible_Factory;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
- " private Set setOfInaccessible2() {",
+ " private Set getSetOfInaccessible2() {",
" return ImmutableSet.copyOf(TestModule_EmptySetFactory.emptySet());",
" }",
"",
@@ -212,11 +213,12 @@
" public UsesInaccessible usesInaccessible() {",
" return UsesInaccessible_Factory.newInstance(",
" (Set) ImmutableSet.of(),",
- " (Set) setOfInaccessible2());",
+ " (Set) getSetOfInaccessible2());",
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, inaccessible, inaccessible2, usesInaccessible, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -272,7 +274,7 @@
"",
"import com.google.common.collect.ImmutableSet;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParent implements Parent {",
" private final class ChildImpl implements Child {",
" @Override",
@@ -283,7 +285,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(parent, parentModule, child);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, parentModule, child);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerParent")
@@ -331,7 +333,7 @@
"import java.util.Set;",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent, "
+ "CancellationListener {",
" private DaggerTestComponent() {}",
@@ -344,14 +346,14 @@
" return new Builder().build();",
" }",
"",
- " private Set<String> setOfString() {",
+ " private Set<String> getSetOfString() {",
" return ImmutableSet.<String>copyOf(",
" EmptySetModule_EmptySetFactory.emptySet());",
" }",
"",
" @Override",
" public ListenableFuture<Set<String>> strings() {",
- " return Futures.immediateFuture(setOfString());",
+ " return Futures.immediateFuture(getSetOfString());",
" }",
"",
" @Override",
@@ -367,7 +369,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(emptySetModuleFile, componentFile);
assertThat(compilation).succeeded();
assertThat(compilation)
diff --git a/javatests/dagger/internal/codegen/SourceFilesTest.java b/javatests/dagger/internal/codegen/SourceFilesTest.java
index 248e2ef..c7fe998 100644
--- a/javatests/dagger/internal/codegen/SourceFilesTest.java
+++ b/javatests/dagger/internal/codegen/SourceFilesTest.java
@@ -17,10 +17,9 @@
package dagger.internal.codegen;
import static com.google.common.truth.Truth.assertThat;
-import static dagger.internal.codegen.binding.SourceFiles.simpleVariableName;
+import static dagger.internal.codegen.SourceFiles.simpleVariableName;
import com.google.testing.compile.CompilationRule;
-import dagger.internal.codegen.binding.SourceFiles;
import java.util.List;
import javax.lang.model.element.TypeElement;
import org.junit.Rule;
diff --git a/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
index 0fd7e08..5dab4c4 100644
--- a/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentBuilderValidationTest.java
@@ -18,12 +18,11 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ErrorMessages.creatorMessagesFor;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.ErrorMessages.creatorMessagesFor;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ErrorMessages;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java b/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
index ea0b4cc..de0067f 100644
--- a/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentCreatorRequestFulfillmentTest.java
@@ -21,15 +21,14 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.testing.compile.Compilation;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -101,7 +100,7 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerC implements C {",
" @Override",
" public Sub.Builder sBuilder() {",
diff --git a/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
index 371253a..b5753d4 100644
--- a/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentCreatorValidationTest.java
@@ -18,19 +18,18 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
+import static dagger.internal.codegen.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
+import static dagger.internal.codegen.ComponentCreatorKind.BUILDER;
+import static dagger.internal.codegen.ComponentCreatorKind.FACTORY;
+import static dagger.internal.codegen.ComponentKind.SUBCOMPONENT;
+import static dagger.internal.codegen.ErrorMessages.ComponentCreatorMessages.moreThanOneRefToSubcomponent;
+import static dagger.internal.codegen.ErrorMessages.componentMessagesFor;
import static dagger.internal.codegen.TestUtils.message;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorAnnotation.SUBCOMPONENT_FACTORY;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.BUILDER;
-import static dagger.internal.codegen.binding.ComponentCreatorKind.FACTORY;
-import static dagger.internal.codegen.binding.ComponentKind.SUBCOMPONENT;
-import static dagger.internal.codegen.binding.ErrorMessages.ComponentCreatorMessages.moreThanOneRefToSubcomponent;
-import static dagger.internal.codegen.binding.ErrorMessages.componentMessagesFor;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.binding.ComponentCreatorAnnotation;
import java.util.Collection;
import javax.tools.JavaFileObject;
import org.junit.Test;
@@ -674,18 +673,19 @@
Compilation compilation = compile(componentFile, childComponentFile);
assertThat(compilation).failed();
String firstBinding = creatorKind.equals(FACTORY)
- ? "ChildComponent.Factory.create(s1, …)"
- : "@BindsInstance void ChildComponent.Builder.set1(String)";
+ ? "test.ChildComponent.Factory.create(s1, …)"
+ : "@BindsInstance void test.ChildComponent.Builder.set1(String)";
String secondBinding = creatorKind.equals(FACTORY)
- ? "ChildComponent.Factory.create(…, s2)"
- : "@BindsInstance void ChildComponent.Builder.set2(String)";
+ ? "test.ChildComponent.Factory.create(…, s2)"
+ : "@BindsInstance void test.ChildComponent.Builder.set2(String)";
assertThat(compilation)
.hadErrorContaining(
message(
- "String is bound multiple times:",
+ "java.lang.String is bound multiple times:",
" " + firstBinding,
" " + secondBinding,
- " in component: [ParentComponent → ChildComponent]"))
+ " java.lang.String is provided at",
+ " test.ChildComponent.s() [test.ParentComponent → test.ChildComponent]"))
.inFile(componentFile)
.onLineContaining("interface ParentComponent {");
}
diff --git a/javatests/dagger/internal/codegen/SubcomponentValidationTest.java b/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
index 19a27ff..ad08160 100644
--- a/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
+++ b/javatests/dagger/internal/codegen/SubcomponentValidationTest.java
@@ -19,9 +19,8 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
-import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION;
import com.google.testing.compile.Compilation;
@@ -84,7 +83,8 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(componentFile, childComponentFile, moduleFile);
assertThat(compilation).failed();
assertThat(compilation)
@@ -152,15 +152,16 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(component, childComponent, grandchildComponent, grandchildModule);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "[ChildComponent.newGrandchildComponent()] "
- + "GrandchildComponent requires modules which have no visible default "
+ "[test.ChildComponent.newGrandchildComponent()] "
+ + "test.GrandchildComponent requires modules which have no visible default "
+ "constructors. Add the following modules as parameters to this method: "
- + "GrandchildModule")
+ + "test.GrandchildModule")
.inFile(component)
.onLineContaining("interface TestComponent");
}
@@ -183,7 +184,8 @@
"@Subcomponent",
"interface ChildComponent {}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(componentFile, childComponentFile);
assertThat(compilation).failed();
assertThat(compilation)
@@ -219,7 +221,8 @@
"@Subcomponent(modules = TestModule.class)",
"interface ChildComponent {}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(moduleFile, componentFile, childComponentFile);
assertThat(compilation).failed();
assertThat(compilation)
@@ -256,7 +259,8 @@
"@Subcomponent",
"interface ChildComponent {}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(moduleFile, componentFile, childComponentFile);
assertThat(compilation).failed();
assertThat(compilation)
@@ -296,15 +300,16 @@
"",
"@Subcomponent(modules = TestModule.class)",
"interface ChildComponent {",
- " String string();",
+ " String getString();",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(moduleFile, componentFile, childComponentFile);
assertThat(compilation).failed();
assertThat(compilation)
.hadErrorContaining(
- "Integer cannot be provided without an @Inject constructor or an "
+ "java.lang.Integer cannot be provided without an @Inject constructor or an "
+ "@Provides-annotated method")
.inFile(componentFile)
.onLineContaining("interface TestComponent");
@@ -319,7 +324,7 @@
"@Subcomponent",
"final class NotASubcomponent {}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(subcomponentFile);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(subcomponentFile);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("interface");
}
@@ -343,7 +348,7 @@
"",
"@Subcomponent(modules = ChildModule.class)",
"interface ChildComponent {",
- " Object object();",
+ " Object getObject();",
"}");
JavaFileObject moduleFile = JavaFileObjects.forSourceLines("test.ChildModule",
"package test;",
@@ -357,7 +362,8 @@
" @Provides @Singleton Object provideObject() { return null; }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(componentFile, subcomponentFile, moduleFile);
assertThat(compilation).failed();
assertThat(compilation).hadErrorContaining("@Singleton");
@@ -377,8 +383,8 @@
"@Component",
"interface ParentComponent {",
" ChildComponent childComponent();",
- " Dep1 dep1();",
- " Dep2 dep2();",
+ " Dep1 getDep1();",
+ " Dep2 getDep2();",
"}");
JavaFileObject childComponentFile =
JavaFileObjects.forSourceLines(
@@ -389,7 +395,7 @@
"",
"@Subcomponent(modules = ChildModule.class)",
"interface ChildComponent {",
- " Object object();",
+ " Object getObject();",
"}");
JavaFileObject childModuleFile =
JavaFileObjects.forSourceLines(
@@ -457,7 +463,7 @@
.addLines(
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParentComponent implements ParentComponent {")
.addLinesIn(
DEFAULT_MODE,
@@ -469,7 +475,7 @@
"")
.addLines(
" @Override", //
- " public Dep1 dep1() {")
+ " public Dep1 getDep1() {")
.addLinesIn(
FAST_INIT_MODE,
" Object local = dep1;",
@@ -490,7 +496,7 @@
" }", //
"",
" @Override",
- " public Dep2 dep2() {")
+ " public Dep2 getDep2() {")
.addLinesIn(
FAST_INIT_MODE,
" Object local = dep2;",
@@ -539,34 +545,34 @@
"")
.addLinesIn(
DEFAULT_MODE,
- " private NeedsDep1 needsDep1() {",
+ " private NeedsDep1 getNeedsDep1() {",
" return new NeedsDep1(DaggerParentComponent.this.dep1Provider.get());",
" }")
.addLinesIn(
FAST_INIT_MODE,
- " private NeedsDep1 needsDep1() {",
- " return new NeedsDep1(DaggerParentComponent.this.dep1());",
+ " private NeedsDep1 getNeedsDep1() {",
+ " return new NeedsDep1(DaggerParentComponent.this.getDep1());",
" }")
.addLines(
- " private A a() {",
+ " private A getA() {",
" return injectA(",
" A_Factory.newInstance(",
- " needsDep1(),")
+ " getNeedsDep1(),")
.addLinesIn(
DEFAULT_MODE,
" DaggerParentComponent.this.dep1Provider.get(),",
" DaggerParentComponent.this.dep2Provider.get()));")
.addLinesIn(
FAST_INIT_MODE,
- " DaggerParentComponent.this.dep1(),",
- " DaggerParentComponent.this.dep2()));")
+ " DaggerParentComponent.this.getDep1(),",
+ " DaggerParentComponent.this.getDep2()));")
.addLines(
" }",
"",
" @Override",
- " public Object object() {",
+ " public Object getObject() {",
" return ChildModule_ProvideObjectFactory.provideObject(",
- " childModule, a());",
+ " childModule, getA());",
" }",
"",
" @CanIgnoreReturnValue",
@@ -579,7 +585,8 @@
.build();
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(
parentComponentFile,
childComponentFile,
@@ -656,7 +663,7 @@
"",
"import test.subpackage.Sub;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public Foo.Sub newInstanceSubcomponent() {",
@@ -693,7 +700,8 @@
" private final class NoConflictImpl implements NoConflict {}",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(parent, foo, bar, baz, noConflict);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -738,7 +746,7 @@
"test.DaggerParentComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public Sub newSubcomponent() {",
@@ -764,7 +772,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerParentComponent")
@@ -803,7 +811,7 @@
JavaFileObjects.forSourceLines(
"DaggerParentComponent",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public Sub newSubcomponent() {",
@@ -827,7 +835,7 @@
"");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, sub, deepSub);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("DaggerParentComponent")
@@ -880,7 +888,7 @@
"",
"import top1.a.b.c.d.E;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerParentComponent implements ParentComponent {",
" @Override",
" public E.F.Sub top1() {",
@@ -901,7 +909,7 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(parent, top1, top2);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent, top1, top2);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerParentComponent")
@@ -937,7 +945,7 @@
"test.DaggerC",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerC implements C {",
" @Override",
" public Foo.C newInstanceC() {",
@@ -948,7 +956,8 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(parent, subcomponentWithSameSimpleNameAsParent);
assertThat(compilation).succeeded();
assertThat(compilation)
@@ -998,7 +1007,7 @@
"",
IMPORT_GENERATED_ANNOTATION,
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerC implements C {",
" @Override",
" public C.Foo.Sub.Builder fooBuilder() {",
@@ -1010,7 +1019,7 @@
" return new B_SubBuilder();",
" }",
"",
- // TODO(bcorso): Reverse the order of subcomponent and builder so that subcomponent
+ // TODO(user): Reverse the order of subcomponent and builder so that subcomponent
// comes first.
" private final class F_SubBuilder implements C.Foo.Sub.Builder {",
" @Override",
@@ -1035,7 +1044,7 @@
" }",
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts()).compile(parent);
+ daggerCompiler().withOptions(compilerMode.javacopts()).compile(parent);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerC")
@@ -1088,16 +1097,17 @@
"}");
Compilation compilation =
- compilerWithOptions(compilerMode.javacopts())
+ daggerCompiler()
+ .withOptions(compilerMode.javacopts())
.compile(module, component, subcomponent);
assertThat(compilation).failed();
- assertThat(compilation).hadErrorContaining("Sub.Builder is bound multiple times:");
+ assertThat(compilation).hadErrorContaining("test.Sub.Builder is bound multiple times:");
assertThat(compilation)
.hadErrorContaining(
- "@Provides Sub.Builder "
- + "TestModule.providesConflictsWithModuleSubcomponents()");
+ "@Provides test.Sub.Builder "
+ + "test.TestModule.providesConflictsWithModuleSubcomponents()");
assertThat(compilation)
- .hadErrorContaining("@Module(subcomponents = Sub.class) for TestModule");
+ .hadErrorContaining("@Module(subcomponents = test.Sub.class) for test.TestModule");
}
@Test
diff --git a/javatests/dagger/internal/codegen/SwitchingProviderTest.java b/javatests/dagger/internal/codegen/SwitchingProviderTest.java
index 593ad49..2898f2e 100644
--- a/javatests/dagger/internal/codegen/SwitchingProviderTest.java
+++ b/javatests/dagger/internal/codegen/SwitchingProviderTest.java
@@ -18,7 +18,7 @@
import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.Compiler.javac;
-import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
+import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION;
import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
@@ -68,7 +68,7 @@
JavaFileObjects.forSourceLines(
"test.DaggerTestComponent",
"package test;",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
@@ -248,11 +248,11 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private volatile Provider<String> sProvider;",
"",
- " private Provider<String> stringProvider() {",
+ " private Provider<String> getStringProvider() {",
" Object local = sProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
@@ -263,12 +263,12 @@
"",
" @Override",
" public Provider<Object> objectProvider() {",
- " return (Provider) stringProvider();",
+ " return (Provider) getStringProvider();",
" }",
"",
" @Override",
" public Provider<CharSequence> charSequenceProvider() {",
- " return (Provider) stringProvider();",
+ " return (Provider) getStringProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
@@ -333,12 +333,12 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private volatile Object charSequence = new MemoizedSentinel();",
" private volatile Provider<CharSequence> cProvider;",
"",
- " private CharSequence charSequence() {",
+ " private CharSequence getCharSequence() {",
" Object local = charSequence;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
@@ -373,7 +373,7 @@
" public T get() {",
" switch (id) {",
" case 0:",
- " return (T) DaggerTestComponent.this.charSequence();",
+ " return (T) DaggerTestComponent.this.getCharSequence();",
" default:",
" throw new AssertionError(id);",
" }",
@@ -424,7 +424,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @Override",
" public Provider<Set<String>> setProvider() {",
@@ -469,7 +469,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" private Provider<MembersInjector<Foo>> fooMembersInjectorProvider;",
"",
@@ -540,7 +540,7 @@
"test.DaggerTestComponent",
"package test;",
"",
- GENERATED_CODE_ANNOTATIONS,
+ GENERATED_ANNOTATION,
"final class DaggerTestComponent implements TestComponent {",
" @SuppressWarnings(\"rawtypes\")",
" private static final Provider ABSENT_JDK_OPTIONAL_PROVIDER =",
diff --git a/javatests/dagger/internal/codegen/TypeProtoConverterTest.java b/javatests/dagger/internal/codegen/TypeProtoConverterTest.java
new file mode 100644
index 0000000..8c8628c
--- /dev/null
+++ b/javatests/dagger/internal/codegen/TypeProtoConverterTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.internal.codegen;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+import static javax.lang.model.util.ElementFilter.fieldsIn;
+
+import com.google.testing.compile.CompilationRule;
+import dagger.internal.Factory;
+import dagger.internal.codegen.langmodel.DaggerElements;
+import dagger.internal.codegen.langmodel.DaggerTypes;
+import dagger.internal.codegen.serialization.TypeProto;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.lang.model.type.TypeMirror;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests {@link TypeProtoConverter}. */
+@RunWith(JUnit4.class)
+public class TypeProtoConverterTest {
+ @Rule public CompilationRule compilationRule = new CompilationRule();
+
+ private DaggerElements elements;
+ private DaggerTypes types;
+ private TypeProtoConverter typeProtoConverter;
+
+ @Before
+ public void setUp() {
+ this.elements = new DaggerElements(compilationRule.getElements(), compilationRule.getTypes());
+ this.types = new DaggerTypes(compilationRule.getTypes(), elements);
+ this.typeProtoConverter = new TypeProtoConverter(types, elements);
+ }
+
+ static class Outer<O> {
+ @SuppressWarnings("ClassCanBeStatic") // We want to specifically test inner classes
+ class Inner<I> {}
+ }
+
+ @SuppressWarnings({"rawtypes", "unused"})
+ static class TypeMirrorConversionSubjects {
+ private Map rawMap;
+ private List<String> listOfString;
+ private List<HashMap<String, Integer>> listOfHashMapOfStringToInteger;
+ private Map<HashMap<String, Integer>, Set<Factory>> mapOfHashMapOfStringToIntegerToSetOfFactory;
+ private Map<HashMap<String, Integer>, Set<Factory>>[][]
+ arrayOfArrayOfMapOfHashMapOfStringToIntegerToSetOfFactory;
+ private Map<HashMap<?, Integer>, ?> mapOfHashMapOfWildcardToIntegerToWildcard;
+ private List<? extends String> listOfWildcardExtendsString;
+ private List<? extends Set<? super String>> listOfWildcardExtendsSetOfWildcardSuperString;
+ private Outer<Object>.Inner<Integer> outerOfObjectDotInnerOfInteger;
+ private List<int[]> listOfIntArray;
+ private List<? extends CharSequence[]> listOfWildcardExtendsCharSequenceArray;
+ }
+
+ @Test
+ public void typeMirrorProtoConversions() {
+ assertProtoConversionEquality(fieldType("rawMap"));
+ assertProtoConversionEquality(fieldType("listOfString"));
+ assertProtoConversionEquality(fieldType("listOfHashMapOfStringToInteger"));
+ assertProtoConversionEquality(fieldType("mapOfHashMapOfStringToIntegerToSetOfFactory"));
+ assertProtoConversionEquality(
+ fieldType("arrayOfArrayOfMapOfHashMapOfStringToIntegerToSetOfFactory"));
+ assertProtoConversionEquality(fieldType("mapOfHashMapOfWildcardToIntegerToWildcard"));
+ assertProtoConversionEquality(fieldType("listOfWildcardExtendsString"));
+ assertProtoConversionEquality(fieldType("listOfWildcardExtendsSetOfWildcardSuperString"));
+ assertProtoConversionEquality(fieldType("outerOfObjectDotInnerOfInteger"));
+ assertProtoConversionEquality(fieldType("listOfIntArray"));
+ assertProtoConversionEquality(fieldType("listOfWildcardExtendsCharSequenceArray"));
+ }
+
+ private TypeMirror fieldType(String fieldName) {
+ return fieldsIn(
+ elements.getTypeElement(TypeMirrorConversionSubjects.class).getEnclosedElements())
+ .stream()
+ .filter(field -> field.getSimpleName().contentEquals(fieldName))
+ .findFirst()
+ .get()
+ .asType();
+ }
+
+ /**
+ * Converts {@link TypeMirror} to a {@link dagger.internal.codegen.serialization.TypeProto} and
+ * back to a {@link TypeMirror}. Asserts that the round-trip conversion is lossless.
+ */
+ private void assertProtoConversionEquality(TypeMirror typeMirror) {
+ TypeProto toProto = TypeProtoConverter.toProto(typeMirror);
+ TypeMirror fromProto = typeProtoConverter.fromProto(toProto);
+ assertWithMessage("expected: %s\nactual : %s", typeMirror, fromProto)
+ .that(types.isSameType(typeMirror, fromProto))
+ .isTrue();
+ }
+}
diff --git a/javatests/dagger/internal/codegen/ValidationReportTest.java b/javatests/dagger/internal/codegen/ValidationReportTest.java
index d1c3a2e..b0f2f2f 100644
--- a/javatests/dagger/internal/codegen/ValidationReportTest.java
+++ b/javatests/dagger/internal/codegen/ValidationReportTest.java
@@ -23,8 +23,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
-import dagger.internal.codegen.validation.ValidationReport;
-import dagger.internal.codegen.validation.ValidationReport.Builder;
+import dagger.internal.codegen.ValidationReport.Builder;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
diff --git a/javatests/dagger/internal/codegen/javapoet/BUILD b/javatests/dagger/internal/codegen/javapoet/BUILD
index 438d377..99c11bd 100644
--- a/javatests/dagger/internal/codegen/javapoet/BUILD
+++ b/javatests/dagger/internal/codegen/javapoet/BUILD
@@ -15,11 +15,11 @@
# Description:
# Tests for dagger.internal.codegen.javapoet
+package(default_visibility = ["//:src"])
+
load("//:build_defs.bzl", "DOCLINT_HTML_AND_SYNTAX")
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "javapoet_tests",
srcs = glob(["*.java"]),
@@ -28,10 +28,10 @@
deps = [
"//java/dagger/internal/codegen/javapoet",
"//java/dagger/internal/codegen/langmodel",
+ "@google_bazel_common//third_party/java/auto:common",
"@google_bazel_common//third_party/java/compile_testing",
"@google_bazel_common//third_party/java/javapoet",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/truth",
- "@maven//:com_google_auto_auto_common",
],
)
diff --git a/javatests/dagger/lint/BUILD b/javatests/dagger/lint/BUILD
deleted file mode 100644
index 268340d..0000000
--- a/javatests/dagger/lint/BUILD
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2020 The Dagger Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Description:
-# Tests for the Dagger Lint Rules
-
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_test")
-
-package(default_visibility = ["//:src"])
-
-kt_jvm_test(
- name = "DaggerKotlinIssueDetectorTest",
- srcs = ["DaggerKotlinIssueDetectorTest.kt"],
- deps = [
- "@google_bazel_common//third_party/java/junit",
- "//java/dagger/lint:lint-artifact-lib",
- "@maven//:com_android_tools_lint_lint_checks",
- "@maven//:com_android_tools_lint_lint_tests",
- "@maven//:com_android_tools_testutils",
- "@maven//:org_jetbrains_kotlin_kotlin_stdlib",
- ],
-)
diff --git a/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt b/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt
deleted file mode 100644
index f112392..0000000
--- a/javatests/dagger/lint/DaggerKotlinIssueDetectorTest.kt
+++ /dev/null
@@ -1,246 +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.lint
-
-import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Issue
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@Suppress("UnstableApiUsage")
-@RunWith(JUnit4::class)
-class DaggerKotlinIssueDetectorTest : LintDetectorTest() {
-
- private companion object {
- private val javaxInjectStubs = kotlin(
- """
- package javax.inject
-
- annotation class Inject
- annotation class Qualifier
- """
- ).indented()
-
- private val daggerStubs = kotlin(
- """
- package dagger
-
- annotation class Provides
- annotation class Module
- """
- ).indented()
-
- // For some reason in Bazel the stdlib dependency on the classpath isn't visible to the
- // LintTestTask, so we just include it ourselves here for now.
- private val jvmStaticStubs = kotlin(
- """
- package kotlin.jvm
-
- annotation class JvmStatic
- """
- ).indented()
- }
-
- override fun getDetector(): Detector = DaggerKotlinIssueDetector()
-
- override fun getIssues(): List<Issue> = DaggerKotlinIssueDetector.issues
-
- @Test
- fun simpleSmokeTestForQualifiersAndProviders() {
- lint()
- .allowMissingSdk()
- .files(
- javaxInjectStubs,
- daggerStubs,
- jvmStaticStubs,
- kotlin(
- """
- package foo
- import javax.inject.Inject
- import javax.inject.Qualifier
- import kotlin.jvm.JvmStatic
- import dagger.Provides
- import dagger.Module
-
- @Qualifier
- annotation class MyQualifier
-
- class InjectedTest {
- // This should fail because of `:field`
- @Inject
- @field:MyQualifier
- lateinit var prop: String
-
- // This is fine!
- @Inject
- @MyQualifier
- lateinit var prop2: String
- }
-
- @Module
- object ObjectModule {
- // This should fail because it uses `@JvmStatic`
- @JvmStatic
- @Provides
- fun provideFoo(): String {
-
- }
-
- // This is fine!
- @Provides
- fun provideBar(): String {
-
- }
- }
-
- @Module
- class ClassModule {
- companion object {
- // This should fail because the companion object is part of ClassModule, so this is unnecessary.
- @JvmStatic
- @Provides
- fun provideBaz(): String {
-
- }
- }
- }
-
- @Module
- class ClassModuleQualified {
- companion object {
- // This should fail because the companion object is part of ClassModule, so this is unnecessary.
- // This specifically tests a fully qualified annotation
- @kotlin.jvm.JvmStatic
- @Provides
- fun provideBaz(): String {
-
- }
- }
- }
-
- @Module
- class ClassModule2 {
- // This should fail because the companion object is part of ClassModule
- @Module
- companion object {
- @Provides
- fun provideBaz(): String {
-
- }
- }
- }
-
- @Module
- class ClassModule2Qualified {
- // This should fail because the companion object is part of ClassModule
- // This specifically tests a fully qualified annotation
- @dagger.Module
- companion object {
- @Provides
- fun provideBaz(): String {
-
- }
- }
- }
-
- // This is correct as of Dagger 2.26!
- @Module
- class ClassModule3 {
- companion object {
- @Provides
- fun provideBaz(): String {
-
- }
- }
- }
-
- class ClassModule4 {
- // This is should fail because this should be extracted to a standalone object.
- @Module
- companion object {
- @Provides
- fun provideBaz(): String {
-
- }
- }
- }
- """
- ).indented()
- )
- .allowCompilationErrors(false)
- .run()
- .expect(
- """
- src/foo/MyQualifier.kt:14: Warning: Redundant 'field:' used for Dagger qualifier annotation. [FieldSiteTargetOnQualifierAnnotation]
- @field:MyQualifier
- ~~~~~~~~~~~~~~~~~~
- src/foo/MyQualifier.kt:26: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector]
- @JvmStatic
- ~~~~~~~~~~
- src/foo/MyQualifier.kt:43: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector]
- @JvmStatic
- ~~~~~~~~~~
- src/foo/MyQualifier.kt:56: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector]
- @kotlin.jvm.JvmStatic
- ~~~~~~~~~~~~~~~~~~~~~
- src/foo/MyQualifier.kt:66: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects]
- // This should fail because the companion object is part of ClassModule
- ^
- src/foo/MyQualifier.kt:78: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects]
- // This should fail because the companion object is part of ClassModule
- ^
- src/foo/MyQualifier.kt:101: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects]
- // This is should fail because this should be extracted to a standalone object.
- ^
- 0 errors, 7 warnings
- """.trimIndent()
- )
- .expectFixDiffs(
- """
- Fix for src/foo/MyQualifier.kt line 14: Remove 'field:':
- @@ -14 +14
- - @field:MyQualifier
- + @MyQualifier
- Fix for src/foo/MyQualifier.kt line 26: Remove @JvmStatic:
- @@ -26 +26
- - @JvmStatic
- +
- Fix for src/foo/MyQualifier.kt line 43: Remove @JvmStatic:
- @@ -43 +43
- - @JvmStatic
- +
- Fix for src/foo/MyQualifier.kt line 56: Remove @JvmStatic:
- @@ -56 +56
- - @kotlin.jvm.JvmStatic
- +
- Fix for src/foo/MyQualifier.kt line 66: Remove @Module:
- @@ -67 +67
- - @Module
- +
- Fix for src/foo/MyQualifier.kt line 78: Remove @Module:
- @@ -80 +80
- - @dagger.Module
- +
- Fix for src/foo/MyQualifier.kt line 101: Remove @Module:
- @@ -102 +102
- - @Module
- +
- """.trimIndent()
- )
- }
-}
diff --git a/javatests/dagger/producers/BUILD b/javatests/dagger/producers/BUILD
index 9404d85..1e1bd66 100644
--- a/javatests/dagger/producers/BUILD
+++ b/javatests/dagger/producers/BUILD
@@ -15,6 +15,8 @@
# Description:
# Tests for dagger.producers
+package(default_visibility = ["//:src"])
+
load(
"//:build_defs.bzl",
"DOCLINT_HTML_AND_SYNTAX",
@@ -23,17 +25,14 @@
)
load("//:test_defs.bzl", "GenJavaTests")
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "producers_tests",
srcs = glob(["**/*.java"]),
functional = 0,
javacopts = SOURCE_7_TARGET_7 + DOCLINT_REFERENCES + DOCLINT_HTML_AND_SYNTAX,
deps = [
- "//java/dagger/internal/guava:collect",
- "//java/dagger/internal/guava:concurrent",
"//java/dagger/producers",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/guava:testlib",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/mockito",
diff --git a/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java b/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java
index af13504..b29cb3c 100644
--- a/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java
+++ b/javatests/dagger/producers/internal/AbstractProducesMethodProducerTest.java
@@ -18,8 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@@ -56,7 +55,7 @@
public void initMocks() {
MockitoAnnotations.initMocks(this);
monitor = Mockito.mock(ProducerMonitor.class, Mockito.CALLS_REAL_METHODS);
- when(componentMonitor.producerMonitorFor(nullable(ProducerToken.class))).thenReturn(monitor);
+ when(componentMonitor.producerMonitorFor(any(ProducerToken.class))).thenReturn(monitor);
componentMonitorProvider =
new Provider<ProductionComponentMonitor>() {
@Override
diff --git a/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.java b/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.java
index 5c443a4..449b5a6 100644
--- a/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.java
+++ b/javatests/dagger/producers/monitoring/TimingProductionComponentMonitorTest.java
@@ -16,7 +16,7 @@
package dagger.producers.monitoring;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
diff --git a/javatests/dagger/producers/monitoring/TimingRecordersTest.java b/javatests/dagger/producers/monitoring/TimingRecordersTest.java
index eefcb01..4e5d74f 100644
--- a/javatests/dagger/producers/monitoring/TimingRecordersTest.java
+++ b/javatests/dagger/producers/monitoring/TimingRecordersTest.java
@@ -17,9 +17,8 @@
package dagger.producers.monitoring;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -97,8 +96,7 @@
public void singleRecorder_nullProducerTimingRecorder() {
when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
.thenReturn(mockProductionComponentTimingRecorder);
- when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(null);
ProductionComponentTimingRecorder.Factory factory =
TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
@@ -112,8 +110,7 @@
public void singleRecorder_throwingProductionComponentTimingRecorder() {
when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
.thenReturn(mockProductionComponentTimingRecorder);
- when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(any(ProducerToken.class)))
.thenThrow(new RuntimeException("monkey"));
ProductionComponentTimingRecorder.Factory factory =
TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
@@ -223,8 +220,7 @@
.thenReturn(mockProductionComponentTimingRecorderA);
when(mockProductionComponentTimingRecorderFactoryB.create(any(Object.class))).thenReturn(null);
when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(mockProducerTimingRecorderA);
ProductionComponentTimingRecorder.Factory factory =
TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
@@ -253,8 +249,7 @@
.thenThrow(new RuntimeException("monkey"));
when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
.thenThrow(new RuntimeException("monkey"));
- when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(mockProducerTimingRecorderA);
ProductionComponentTimingRecorder.Factory factory =
TimingRecorders.delegatingProductionComponentTimingRecorderFactory(
@@ -345,8 +340,7 @@
private void setUpNormalSingleRecorder() {
when(mockProductionComponentTimingRecorderFactory.create(any(Object.class)))
.thenReturn(mockProductionComponentTimingRecorder);
- when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorder.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(mockProducerTimingRecorder);
}
@@ -357,14 +351,11 @@
.thenReturn(mockProductionComponentTimingRecorderB);
when(mockProductionComponentTimingRecorderFactoryC.create(any(Object.class)))
.thenReturn(mockProductionComponentTimingRecorderC);
- when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorderA.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(mockProducerTimingRecorderA);
- when(mockProductionComponentTimingRecorderB.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorderB.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(mockProducerTimingRecorderB);
- when(mockProductionComponentTimingRecorderC.producerTimingRecorderFor(
- nullable(ProducerToken.class)))
+ when(mockProductionComponentTimingRecorderC.producerTimingRecorderFor(any(ProducerToken.class)))
.thenReturn(mockProducerTimingRecorderC);
}
}
diff --git a/javatests/dagger/producers/monitoring/internal/MonitorsTest.java b/javatests/dagger/producers/monitoring/internal/MonitorsTest.java
index ada4e33..47ccccb 100644
--- a/javatests/dagger/producers/monitoring/internal/MonitorsTest.java
+++ b/javatests/dagger/producers/monitoring/internal/MonitorsTest.java
@@ -17,8 +17,7 @@
package dagger.producers.monitoring.internal;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -88,7 +87,7 @@
public void singleMonitor_nullProducerMonitor() {
when(mockProductionComponentMonitorFactory.create(any(Object.class)))
.thenReturn(mockProductionComponentMonitor);
- when(mockProductionComponentMonitor.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitor.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(null);
ProductionComponentMonitor.Factory factory =
Monitors.delegatingProductionComponentMonitorFactory(
@@ -104,7 +103,7 @@
.thenReturn(mockProductionComponentMonitor);
doThrow(new RuntimeException("monkey"))
.when(mockProductionComponentMonitor)
- .producerMonitorFor(nullable(ProducerToken.class));
+ .producerMonitorFor(any(ProducerToken.class));
ProductionComponentMonitor.Factory factory =
Monitors.delegatingProductionComponentMonitorFactory(
ImmutableList.of(mockProductionComponentMonitorFactory));
@@ -165,9 +164,7 @@
doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).requested();
doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodStarting();
doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).methodFinished();
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerMonitor)
- .succeeded(nullable(Object.class));
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitor).succeeded(any(Object.class));
ProductionComponentMonitor.Factory factory =
Monitors.delegatingProductionComponentMonitorFactory(
ImmutableList.of(mockProductionComponentMonitorFactory));
@@ -255,7 +252,7 @@
.thenReturn(mockProductionComponentMonitorA);
when(mockProductionComponentMonitorFactoryB.create(any(Object.class))).thenReturn(null);
when(mockProductionComponentMonitorFactoryC.create(any(Object.class))).thenReturn(null);
- when(mockProductionComponentMonitorA.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(mockProducerMonitorA);
ProductionComponentMonitor.Factory factory =
Monitors.delegatingProductionComponentMonitorFactory(
@@ -291,7 +288,7 @@
doThrow(new RuntimeException("monkey"))
.when(mockProductionComponentMonitorFactoryC)
.create(any(Object.class));
- when(mockProductionComponentMonitorA.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(mockProducerMonitorA);
ProductionComponentMonitor.Factory factory =
Monitors.delegatingProductionComponentMonitorFactory(
@@ -393,9 +390,7 @@
doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).requested();
doThrow(new RuntimeException("monkey")).when(mockProducerMonitorA).methodStarting();
doThrow(new RuntimeException("monkey")).when(mockProducerMonitorB).methodFinished();
- doThrow(new RuntimeException("monkey"))
- .when(mockProducerMonitorC)
- .succeeded(nullable(Object.class));
+ doThrow(new RuntimeException("monkey")).when(mockProducerMonitorC).succeeded(any(Object.class));
ProductionComponentMonitor.Factory factory =
Monitors.delegatingProductionComponentMonitorFactory(
ImmutableList.of(
@@ -470,7 +465,7 @@
private void setUpNormalSingleMonitor() {
when(mockProductionComponentMonitorFactory.create(any(Object.class)))
.thenReturn(mockProductionComponentMonitor);
- when(mockProductionComponentMonitor.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitor.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(mockProducerMonitor);
}
@@ -481,11 +476,11 @@
.thenReturn(mockProductionComponentMonitorB);
when(mockProductionComponentMonitorFactoryC.create(any(Object.class)))
.thenReturn(mockProductionComponentMonitorC);
- when(mockProductionComponentMonitorA.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitorA.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(mockProducerMonitorA);
- when(mockProductionComponentMonitorB.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitorB.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(mockProducerMonitorB);
- when(mockProductionComponentMonitorC.producerMonitorFor(nullable(ProducerToken.class)))
+ when(mockProductionComponentMonitorC.producerMonitorFor(any(ProducerToken.class)))
.thenReturn(mockProducerMonitorC);
}
}
diff --git a/javatests/dagger/spi/BUILD b/javatests/dagger/spi/BUILD
index 849037b..a94461b 100644
--- a/javatests/dagger/spi/BUILD
+++ b/javatests/dagger/spi/BUILD
@@ -15,6 +15,8 @@
# Description:
# Tests for the Dagger SPI
+package(default_visibility = ["//:src"])
+
load("//:test_defs.bzl", "GenJavaTests")
load(
"//:build_defs.bzl",
@@ -22,8 +24,6 @@
"DOCLINT_REFERENCES",
)
-package(default_visibility = ["//:src"])
-
GenJavaTests(
name = "spi_tests",
srcs = glob(["*.java"]),
@@ -32,11 +32,11 @@
deps = [
"//java/dagger:core",
"//java/dagger/internal/codegen:processor",
- "//java/dagger/internal/guava:base",
- "//java/dagger/internal/guava:collect",
+ "//java/dagger/model",
"//java/dagger/spi",
"@google_bazel_common//third_party/java/auto:service",
"@google_bazel_common//third_party/java/compile_testing",
+ "@google_bazel_common//third_party/java/guava",
"@google_bazel_common//third_party/java/jsr330_inject",
"@google_bazel_common//third_party/java/junit",
"@google_bazel_common//third_party/java/truth",
diff --git a/javatests/dagger/spi/FailingPlugin.java b/javatests/dagger/spi/FailingPlugin.java
index 2d13e21..8fd0e35 100644
--- a/javatests/dagger/spi/FailingPlugin.java
+++ b/javatests/dagger/spi/FailingPlugin.java
@@ -83,6 +83,7 @@
.forEach(
edge -> diagnosticReporter.reportDependency(ERROR, edge, "Bad Dependency: %s", edge));
}
+
}
@Override
diff --git a/javatests/dagger/spi/SpiPluginTest.java b/javatests/dagger/spi/SpiPluginTest.java
index 1df8cd1..613a915 100644
--- a/javatests/dagger/spi/SpiPluginTest.java
+++ b/javatests/dagger/spi/SpiPluginTest.java
@@ -53,9 +53,7 @@
javac()
.withProcessors(new ComponentProcessor())
.withOptions(
- "-Aerror_on_binding=java.lang.Integer",
- "-Adagger.fullBindingGraphValidation=ERROR",
- "-Adagger.pluginsVisitFullBindingGraphs=ENABLED")
+ "-Aerror_on_binding=java.lang.Integer", "-Adagger.fullBindingGraphValidation=ERROR")
.compile(module);
assertThat(compilation).failed();
assertThat(compilation)
@@ -99,7 +97,7 @@
.hadErrorContaining(
message(
"[FailingPlugin] Bad Binding: @Inject test.Foo()",
- " test.Foo is requested at",
+ " test.Foo is provided at",
" test.TestComponent.foo()"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -187,7 +185,7 @@
.hadErrorContaining(
message(
"[FailingPlugin] Bad Dependency: test.TestComponent.entryPoint() (entry point)",
- " test.EntryPoint is requested at",
+ " test.EntryPoint is provided at",
" test.TestComponent.entryPoint()"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -197,7 +195,7 @@
"[FailingPlugin] Bad Dependency: test.EntryPoint(…, dup1, …)",
" test.Duplicated is injected at",
" test.EntryPoint(…, dup1, …)",
- " test.EntryPoint is requested at",
+ " test.EntryPoint is provided at",
" test.TestComponent.entryPoint()"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -207,7 +205,7 @@
"[FailingPlugin] Bad Dependency: test.EntryPoint(…, dup2)",
" test.Duplicated is injected at",
" test.EntryPoint(…, dup2)",
- " test.EntryPoint is requested at",
+ " test.EntryPoint is provided at",
" test.TestComponent.entryPoint()"))
.inFile(component)
.onLineContaining("interface TestComponent");
@@ -222,7 +220,7 @@
" test.Foo(inFooDep)",
" test.Foo is injected at",
" test.EntryPoint(foo, …)",
- " test.EntryPoint is requested at",
+ " test.EntryPoint is provided at",
" test.TestComponent.entryPoint()",
"The following other entry points also depend on it:",
" test.TestComponent.chain()"))
@@ -282,7 +280,7 @@
message(
"[FailingPlugin] Bad Dependency: "
+ "test.TestSubcomponent.childEntryPoint() (entry point)",
- " test.EntryPoint is requested at",
+ " test.EntryPoint is provided at",
" test.TestSubcomponent.childEntryPoint()"
+ " [test.TestComponent → test.TestSubcomponent]"))
.inFile(component)
@@ -297,7 +295,7 @@
"[FailingPlugin] Bad Dependency: test.EntryPoint(foo)",
" test.Foo is injected at",
" test.EntryPoint(foo)",
- " test.EntryPoint is requested at",
+ " test.EntryPoint is provided at",
" test.TestSubcomponent.childEntryPoint() "
+ "[test.TestComponent → test.TestSubcomponent]"))
.inFile(component)
@@ -474,7 +472,7 @@
" test.Chain2(chain)",
" test.Chain2 is injected at",
" test.Chain1(chain)",
- " test.Chain1 is requested at",
+ " test.Chain1 is provided at",
" test.TestComponent.chain()",
"The following other entry points also depend on it:",
" test.TestSubcomponent.exposedOnSubcomponent() "
diff --git a/lib/NOTICE b/lib/NOTICE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/lib/NOTICE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/lib/auto-common-0.10-sources.jar b/lib/auto-common-0.10-sources.jar
new file mode 100644
index 0000000..59bf056
--- /dev/null
+++ b/lib/auto-common-0.10-sources.jar
Binary files differ
diff --git a/lib/auto-common-0.10-sources.jar.asc b/lib/auto-common-0.10-sources.jar.asc
new file mode 100644
index 0000000..ecc3339
--- /dev/null
+++ b/lib/auto-common-0.10-sources.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQEcBAABAgAGBQJaYLeuAAoJEF4feafCmGYeVzIH/A0rkeHli229WFOj5c3HnFqK
+hbyy32JRw8GZXTqNFamkuxWDF03jHwQn0ymp0nxRQ+I3JRTzbfuTnT73e+kiNSI8
+02PowzbrghgsuaifiOGpHaO/FRSBaexzjE1TbZncO6jM8RIg1J7GPqgUenRwA5YT
+7VL7Ig+5G9bXOZMcQ4OuHwqi2O1rSfnSDDIFGlDqmKNiJWHi4KijxNred9CvUGeW
+7zFBOzQkqUqm7Vs2MHmBvNM79fcD1F1SFa2I7+p6/oD1ecC0TAHLdlLhR1/sLBaG
+iw3uQeeflVZ6ilzJg93Rl2kNUw77nnywkt12SY76j1tpF5Ny2l8tid3bBrQEUPE=
+=0e1a
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-common-0.10-sources.jar.sha1 b/lib/auto-common-0.10-sources.jar.sha1
new file mode 100644
index 0000000..b9b3bee
--- /dev/null
+++ b/lib/auto-common-0.10-sources.jar.sha1
@@ -0,0 +1 @@
+913c8de9604380c6e135086132adb26c77fa6c53
\ No newline at end of file
diff --git a/lib/auto-common-0.10.jar b/lib/auto-common-0.10.jar
new file mode 100644
index 0000000..8cbfa72
--- /dev/null
+++ b/lib/auto-common-0.10.jar
Binary files differ
diff --git a/lib/auto-common-0.10.jar.asc b/lib/auto-common-0.10.jar.asc
new file mode 100644
index 0000000..6d81bdf
--- /dev/null
+++ b/lib/auto-common-0.10.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQEcBAABAgAGBQJaYLeuAAoJEF4feafCmGYe/1gIAInqdd+9NqxfOKRw6ujpL3nT
+XmmsP9gR/Tvvi3xRKj8PjcO9ydO2IfQ9ySAS6qbKuS9SIQn+Plq+6E+rwYkKy5t/
+MZ7Ff59XgMW0uxFEA2zUbcprgQyR6M4A31MYVmKuZ2fGBs5OsoN0+sZPCDmo4EzN
+TIgZ/LdNUWXLIsIRAKzCnUkYjlnNHKcJbW527obNH0UF/TBARrEAtmfCbKT6f91/
+zl1GtnxNR/9LVRxErFHQPcHrRxVP72xRHjdTCJHsL0t5cJJPr9maqkXq8DAyyptU
+XcjisvelIubTqnBDXcqJBIM3beGYPa5rot+3NjnNbylbfSqMED1dSGJL/fypY/U=
+=5BoX
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-common-0.10.jar.sha1 b/lib/auto-common-0.10.jar.sha1
new file mode 100644
index 0000000..2056a80
--- /dev/null
+++ b/lib/auto-common-0.10.jar.sha1
@@ -0,0 +1 @@
+c8f153ebe04a17183480ab4016098055fb474364
\ No newline at end of file
diff --git a/lib/auto-factory-1.0-beta6-sources.jar b/lib/auto-factory-1.0-beta6-sources.jar
new file mode 100644
index 0000000..56c6909
--- /dev/null
+++ b/lib/auto-factory-1.0-beta6-sources.jar
Binary files differ
diff --git a/lib/auto-factory-1.0-beta6-sources.jar.asc b/lib/auto-factory-1.0-beta6-sources.jar.asc
new file mode 100644
index 0000000..be05c6e
--- /dev/null
+++ b/lib/auto-factory-1.0-beta6-sources.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQEzBAABCgAdFiEEMoi4voUS1sDKGFJoxR5svH/0bwsFAlvN1rYACgkQxR5svH/0
+bwsyngf8C60gBeqMcbTJ05w6IccmLONiVEBfXXVASLGxJRW6A4C6CZCOaeu/JTGV
+RlyKSL4RxT6LdN4IE1k/b+SWwhAGxES6n2J1G9TFq/SiRSEjPL2a41qRynjXo9Sx
+D/jWX4flGS4fT229EDx18d+Vy3So5+jPNLN7KyB4E9yBZfnTTmeENsgvs0Y1jw5D
+MNK73Nwwg+f7R42J+07FauRU8YXPYcG1UYZcnmAeHNDmwfL1UOsfSzrglHbU59mw
+MrupMb3h5VSBZcqknQUBbPQUUWo7e+jSJZKDB750CxBNSBfF3tN2D1vJ1/ynCIDA
+i+iY39xggnIbyKTPj1/aOGTBVfiVJQ==
+=xs9M
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-factory-1.0-beta6-sources.jar.sha1 b/lib/auto-factory-1.0-beta6-sources.jar.sha1
new file mode 100644
index 0000000..9b5c0a8
--- /dev/null
+++ b/lib/auto-factory-1.0-beta6-sources.jar.sha1
@@ -0,0 +1 @@
+fab31580230ac3001579238a8857a74bd045e3b9
\ No newline at end of file
diff --git a/lib/auto-factory-1.0-beta6.jar b/lib/auto-factory-1.0-beta6.jar
new file mode 100644
index 0000000..e47130f
--- /dev/null
+++ b/lib/auto-factory-1.0-beta6.jar
Binary files differ
diff --git a/lib/auto-factory-1.0-beta6.jar.asc b/lib/auto-factory-1.0-beta6.jar.asc
new file mode 100644
index 0000000..5da4253
--- /dev/null
+++ b/lib/auto-factory-1.0-beta6.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQEzBAABCgAdFiEEMoi4voUS1sDKGFJoxR5svH/0bwsFAlvN1rIACgkQxR5svH/0
+bwt0VAf/S4AELEOE7cdcSkSF8vNCUhHgJbyRIb9SLT9Jh6ZXt0sVt1ZMB4Jcx9WL
+GfIwCAZhPcidTF3yVRvK0Sj2zHq53bGNsejL5BLO73oSoVowv7NV96v42zbBtMDU
+K6AI8G7lXEHYDlW4gwiyz/5CjP8VYSJgQ5vuC81rNL0vrBY0S30MlzHmCLjCvE2b
+DpV+thGWluhStwJRwvQArtUDgXYW6BPGetls/Mr0LKiSvz9uS9EvRvcQHiiwqxPu
+Jj5vheKyyeaRq7BOOswoUvfidr+UrNBt/Jit3L2kuo5n4n7sfb6irR610X8mMMN/
+kx5cA78f+p7XHbLZh6w3pySp+HCvKw==
+=1KAq
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-factory-1.0-beta6.jar.sha1 b/lib/auto-factory-1.0-beta6.jar.sha1
new file mode 100644
index 0000000..57a5e61
--- /dev/null
+++ b/lib/auto-factory-1.0-beta6.jar.sha1
@@ -0,0 +1 @@
+58c804763a4d80c0884ac8a740fcff4d61da72bc
\ No newline at end of file
diff --git a/lib/auto-service-1.0-rc5-sources.jar b/lib/auto-service-1.0-rc5-sources.jar
new file mode 100644
index 0000000..8a05c9d
--- /dev/null
+++ b/lib/auto-service-1.0-rc5-sources.jar
Binary files differ
diff --git a/lib/auto-service-1.0-rc5-sources.jar.asc b/lib/auto-service-1.0-rc5-sources.jar.asc
new file mode 100644
index 0000000..08ea732
--- /dev/null
+++ b/lib/auto-service-1.0-rc5-sources.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQEzBAABCgAdFiEEMoi4voUS1sDKGFJoxR5svH/0bwsFAlyZH5AACgkQxR5svH/0
+bwuBWwf/QMOlEF0td8ykweHGoOt5B6JmBLk4lPNhZDZdGmvqn+RzbWHo7F5QoBL6
+RQ+Wn97UDroLrIeMRsWvOzL/dA/kMhE2tNX8OKP1kaU7d1ahSkY6PRrPrdcf34IA
+Ku62psSXM5L78HdmhfVpf6UBsa3QJ9ZtLrBMjubxJ7aVrHCTIPP8obVgfgFWHnZD
+nGiynMUNXT6H+L9mDtkWHnVEkC07VBTCFr+6HA3TIf76KQ8LiIj6h+7l6KlPz48h
+eyaElzUUn5deTIG7jrPC2SaVhC0fKu/j1ZazN8tj/25+v9Q9mgZieYYEtiKjrEJU
+tli80ajN26E2NduLldkSVPt6N1Nf/w==
+=6nn7
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-service-1.0-rc5-sources.jar.sha1 b/lib/auto-service-1.0-rc5-sources.jar.sha1
new file mode 100644
index 0000000..3638b53
--- /dev/null
+++ b/lib/auto-service-1.0-rc5-sources.jar.sha1
@@ -0,0 +1 @@
+76bf7fbfc5a924f13115005a134546c4e2d1b245
\ No newline at end of file
diff --git a/lib/auto-service-1.0-rc5.jar b/lib/auto-service-1.0-rc5.jar
new file mode 100644
index 0000000..8c43e8f
--- /dev/null
+++ b/lib/auto-service-1.0-rc5.jar
Binary files differ
diff --git a/lib/auto-service-1.0-rc5.jar.2 b/lib/auto-service-1.0-rc5.jar.2
new file mode 100644
index 0000000..8c43e8f
--- /dev/null
+++ b/lib/auto-service-1.0-rc5.jar.2
Binary files differ
diff --git a/lib/auto-service-1.0-rc5.jar.asc b/lib/auto-service-1.0-rc5.jar.asc
new file mode 100644
index 0000000..e1d0163
--- /dev/null
+++ b/lib/auto-service-1.0-rc5.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQEzBAABCgAdFiEEMoi4voUS1sDKGFJoxR5svH/0bwsFAlyZH48ACgkQxR5svH/0
+bwuZSAgAgmJ8gEx+MLtdt8IJY0ZGZtzntCOv2kTmieTQdwLKbmEc/WeQBXZeAWjb
+xKctEnesbNGwJY5jpPBiQH0nDd0MyIOc25gCvug2ezveo9eNe9ptOQFi+4gsG3mv
+0SGD9ZnRkzW8wNyMMWdBUJYdGPJp/FshsOVajBVsMDSev3OBxw8qfT4ZqhTO3LN6
+UnFydeqtbukqBiQRBrWEO7zXDmeHP+6GMWOD4Tkt60VRrSo7Sk6WeUkSJcB0rrmw
++/blQ3jBlN2/ummOc1dWUu7EyBoWhJhChQDQAuwev5oMMyQnhTLiFcHPvoKWFTlO
+GsBFENSqqxlW4j2ZYpoMX42inuaqbQ==
+=AMUZ
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-service-1.0-rc5.jar.sha1 b/lib/auto-service-1.0-rc5.jar.sha1
new file mode 100644
index 0000000..2edbbf4
--- /dev/null
+++ b/lib/auto-service-1.0-rc5.jar.sha1
@@ -0,0 +1 @@
+d25246bae325b4bcc63b55d6d782515fac32215a
\ No newline at end of file
diff --git a/lib/auto-service-annotations-1.0-rc5-sources.jar b/lib/auto-service-annotations-1.0-rc5-sources.jar
new file mode 100644
index 0000000..72fd4a9
--- /dev/null
+++ b/lib/auto-service-annotations-1.0-rc5-sources.jar
Binary files differ
diff --git a/lib/auto-service-annotations-1.0-rc5-sources.jar.asc b/lib/auto-service-annotations-1.0-rc5-sources.jar.asc
new file mode 100644
index 0000000..0058623
--- /dev/null
+++ b/lib/auto-service-annotations-1.0-rc5-sources.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQEzBAABCgAdFiEEMoi4voUS1sDKGFJoxR5svH/0bwsFAlyZH4IACgkQxR5svH/0
+bwtnEwgAntYeAk/i4kaPhOdKCni4pZpkJ3WcEaDIiZROIvxn3GLFxDp1+WaFOuZS
+kYrqKLmDJdOwEK31FGP/XjsedmB6PP90pp01apaw2XS7pAzXQyNGMOypgCntJsN6
+ZkQYNLum8HQ6XXvEQh9j0eKU/9D+x7DRaxQZ69GkjFS1EwpytEYIEdFsjvHz3SYW
+G15++0H5+l7ZyNjXCs//x6tQ73nqhEu6UylwR4A9YvDuZhpMoFPNvB1+L6mlARgi
+cDRtm8hGLhsNeIYqGmbUEzwwKtKY/n7NwJX1zpXAg86/9E8R1xdbdzfGL6ctqQal
+w3WSYcNnmiZQfPinZuGHnrqDk/rN2w==
+=lgp6
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-service-annotations-1.0-rc5-sources.jar.sha1 b/lib/auto-service-annotations-1.0-rc5-sources.jar.sha1
new file mode 100644
index 0000000..fc01aa3
--- /dev/null
+++ b/lib/auto-service-annotations-1.0-rc5-sources.jar.sha1
@@ -0,0 +1 @@
+a2e50e3ba1f9a88f89142e7ea9a0f5380574f4e4
\ No newline at end of file
diff --git a/lib/auto-service-annotations-1.0-rc5.jar b/lib/auto-service-annotations-1.0-rc5.jar
new file mode 100644
index 0000000..fbc08ab
--- /dev/null
+++ b/lib/auto-service-annotations-1.0-rc5.jar
Binary files differ
diff --git a/lib/auto-service-annotations-1.0-rc5.jar.asc b/lib/auto-service-annotations-1.0-rc5.jar.asc
new file mode 100644
index 0000000..b7e43ce
--- /dev/null
+++ b/lib/auto-service-annotations-1.0-rc5.jar.asc
@@ -0,0 +1,11 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQEzBAABCgAdFiEEMoi4voUS1sDKGFJoxR5svH/0bwsFAlyZH4EACgkQxR5svH/0
+bwtNcwf+IvcoHSI7AvrM+z6Lhqes8wEdU9Q59ixakvEos/umjYwCXoGJyAG/w8N5
+4woRDJRg8KgWC0Kls7CGs5ZwplQTLRte/SmXWux8CV0/3v6OlIP4voWvXBueqKST
+gNN/Miy0Qx5uX1Qwh0inqlFF7jOj+IuTofQ4ZM3UjZPLVYhSfS/wTwLmNWNawQq7
+b/PkxaYgC1RuNv9onA8Vru2UCIlH8NFP9iPqPMwhRVVxoSaZzo5NxrRNRPZUfPzF
+GUH/SRDOfXHJ1joeZRK21s8adOGzZZJsSxxZ393xx1jl5qLdoowjTtENgc9gOSQG
+FzxOfWCoWncsJP10KfyYRV70JnJMrQ==
+=dWz/
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-service-annotations-1.0-rc5.jar.sha1 b/lib/auto-service-annotations-1.0-rc5.jar.sha1
new file mode 100644
index 0000000..4c48b47
--- /dev/null
+++ b/lib/auto-service-annotations-1.0-rc5.jar.sha1
@@ -0,0 +1 @@
+6ea999af2b6262a7179a09c51a3d54e7b40a3833
\ No newline at end of file
diff --git a/lib/auto-value-1.6.5-sources.jar b/lib/auto-value-1.6.5-sources.jar
new file mode 100644
index 0000000..7d08fa7
--- /dev/null
+++ b/lib/auto-value-1.6.5-sources.jar
Binary files differ
diff --git a/lib/auto-value-1.6.5-sources.jar.asc b/lib/auto-value-1.6.5-sources.jar.asc
new file mode 100644
index 0000000..36551c1
--- /dev/null
+++ b/lib/auto-value-1.6.5-sources.jar.asc
@@ -0,0 +1,12 @@
+-----BEGIN PGP SIGNATURE-----
+Comment: GPGTools - https://gpgtools.org
+
+iQEzBAABCgAdFiEEx75bzJ/sFVGM/aiCsPNxD6ZJAOcFAlyuMe0ACgkQsPNxD6ZJ
+AOc+4wgAkYRN5mdnQ54oLb/YGL9jnU7tdcFnq73ddH9wJH9cTGE8dAHIlNT4lEjy
+ligUXdi6YbuAC2Fjs7nMZiSOjEEDlKRozbwE82WOiIdV/MltMJgFCdBbVpszHFmu
+NWxDq5KocdgLODHwmIWJ0Xey6M1rjVZEshNf/U70604eEbGl9Hu0aTVFFVcASMM5
+CC38/X/G72Ja1Cz404WqGpmAsrHgDHdcPUVT3xxDReV1B+yPKxazzuKZA8/+KkWP
+RddLifE3W2NYnLVX49DS9iWCBiEbh5P6jtHvQSiyXIawexhQJGhjQMwHoi0+jHJd
+INp5YyrB64PHqaSgtuXhwgTfXmxkMA==
+=5Cw9
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-value-1.6.5-sources.jar.md5 b/lib/auto-value-1.6.5-sources.jar.md5
new file mode 100644
index 0000000..ca18ea4
--- /dev/null
+++ b/lib/auto-value-1.6.5-sources.jar.md5
@@ -0,0 +1 @@
+4a433a939d3f77766c785288d5c24c10
\ No newline at end of file
diff --git a/lib/auto-value-1.6.5-sources.jar.sha1 b/lib/auto-value-1.6.5-sources.jar.sha1
new file mode 100644
index 0000000..17f16a8
--- /dev/null
+++ b/lib/auto-value-1.6.5-sources.jar.sha1
@@ -0,0 +1 @@
+bfc251753f9bbdd8855825361d5f8c7fec8a1471
\ No newline at end of file
diff --git a/lib/auto-value-1.6.5.jar b/lib/auto-value-1.6.5.jar
new file mode 100644
index 0000000..be17cd1
--- /dev/null
+++ b/lib/auto-value-1.6.5.jar
Binary files differ
diff --git a/lib/auto-value-1.6.5.jar.asc b/lib/auto-value-1.6.5.jar.asc
new file mode 100644
index 0000000..f0cdc39
--- /dev/null
+++ b/lib/auto-value-1.6.5.jar.asc
@@ -0,0 +1,12 @@
+-----BEGIN PGP SIGNATURE-----
+Comment: GPGTools - https://gpgtools.org
+
+iQEzBAABCgAdFiEEx75bzJ/sFVGM/aiCsPNxD6ZJAOcFAlyuMewACgkQsPNxD6ZJ
+AOd5ygf8DOjgClYv8hCaiHiu2mDwFV4s24SbyvSZrAeBrHOoY6/E7leSqilJ+mF9
+3kjDv/VtHTv9Ds2cX2daH5hnvuYIwiCzdze3ZWdKJ+PtWsKpqEAevfEMRmSPPUV4
+ZZ5Zd6VZspD+rUViKfwF8ZW1zjKjdcIPbhuiYR4TF718kPL8WCV2bGruYidjYBoe
+hzLUUqY0rv+IwV+OycbyZwtmx1DVCTkYlDdepSyswr2RGb/UFIf44E0koboI+Xue
+6nF+w6AaOaufjdqe2ObIWNa2tsPTj4KABh3tHmOMs35x367/PzwQmh0I25gFAQrX
+KYo6dYVZeLWmNpdIJxeMIZRok0MAKA==
+=KnCZ
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-value-1.6.5.jar.md5 b/lib/auto-value-1.6.5.jar.md5
new file mode 100644
index 0000000..11a5e9d
--- /dev/null
+++ b/lib/auto-value-1.6.5.jar.md5
@@ -0,0 +1 @@
+d3730b8e2f9c6f62153181618a13f3a2
\ No newline at end of file
diff --git a/lib/auto-value-1.6.5.jar.sha1 b/lib/auto-value-1.6.5.jar.sha1
new file mode 100644
index 0000000..edf62d8
--- /dev/null
+++ b/lib/auto-value-1.6.5.jar.sha1
@@ -0,0 +1 @@
+816872c85048f36a67a276ef7a49cc2e4595711c
\ No newline at end of file
diff --git a/lib/auto-value-annotations-1.6.5-sources.jar b/lib/auto-value-annotations-1.6.5-sources.jar
new file mode 100644
index 0000000..b1a8b08
--- /dev/null
+++ b/lib/auto-value-annotations-1.6.5-sources.jar
Binary files differ
diff --git a/lib/auto-value-annotations-1.6.5-sources.jar.asc b/lib/auto-value-annotations-1.6.5-sources.jar.asc
new file mode 100644
index 0000000..81a4515
--- /dev/null
+++ b/lib/auto-value-annotations-1.6.5-sources.jar.asc
@@ -0,0 +1,12 @@
+-----BEGIN PGP SIGNATURE-----
+Comment: GPGTools - https://gpgtools.org
+
+iQEzBAABCgAdFiEEx75bzJ/sFVGM/aiCsPNxD6ZJAOcFAlyuMdUACgkQsPNxD6ZJ
+AOfNYwgAqoJ9hi7JyS1iwf646TPLPbtRaaRzl/w9hrZntVlMiHL5Ov+LHq6WW1tS
+IWqz9K6dbEDW4O3WbNXUsiWTGzUvkNc/bjQOY4MTCthTj/LO9PqHVSDGgWo/Y37c
+jazTbUNxctFSziu9mVZdw1VdCI65LVCbhSaOeIc7Msmr/ALtZ1pBGdJ8dzxuC3Dl
+BeT2khADj7C13Kicu7QtZfZypbTqB6JnjAwMO56c4pRviIqRpJsOKHbJM1KBxms+
+6JGv63XTBP22f83XX38wAAPocT5NZBn+lZcDcbC6Mh0NIhaISdx73ujWtTwHX5fC
+x0NYKIIBdyEb5GkPeD1D/IjB4w8o5w==
+=Hbou
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-value-annotations-1.6.5-sources.jar.sha1 b/lib/auto-value-annotations-1.6.5-sources.jar.sha1
new file mode 100644
index 0000000..897752c
--- /dev/null
+++ b/lib/auto-value-annotations-1.6.5-sources.jar.sha1
@@ -0,0 +1 @@
+3499fd80025705c502699d1154c4b9631cb7a95e
\ No newline at end of file
diff --git a/lib/auto-value-annotations-1.6.5.jar b/lib/auto-value-annotations-1.6.5.jar
new file mode 100644
index 0000000..f68a013
--- /dev/null
+++ b/lib/auto-value-annotations-1.6.5.jar
Binary files differ
diff --git a/lib/auto-value-annotations-1.6.5.jar.asc b/lib/auto-value-annotations-1.6.5.jar.asc
new file mode 100644
index 0000000..1356995
--- /dev/null
+++ b/lib/auto-value-annotations-1.6.5.jar.asc
@@ -0,0 +1,12 @@
+-----BEGIN PGP SIGNATURE-----
+Comment: GPGTools - https://gpgtools.org
+
+iQEzBAABCgAdFiEEx75bzJ/sFVGM/aiCsPNxD6ZJAOcFAlyuMdQACgkQsPNxD6ZJ
+AOeeQQf/cRfXuh8RCDR5WWAHPXpK9JzA5OEEvtXl13uSqpcU+f2/APNOmG9tJz2B
+53bp6d18knaoSAWtC1Hl2kM8eZPYNlpB+MC8VJ+/JAZMf2arLMKGuvii9eYmGrvJ
+kXfRHqWgZQMQIKrd2ne/PMgnmixLPSF6HtyFh2JN/LbjR7ipQR3VAJe89QGmIFFf
+njSptIgKuDauQrjq//yXpWRyhUNheAH42y3aIaUvydcSOLsGIqQfTJLOe3sSMxlU
+d0fJWP47uW04y2j6kXv4SYKXGnBrv2M+c/6YRriPv69tSBc+2DY6SpMZsYdV9Car
+pDM+7m5lxCN8mI/KRRNcXaSR9GLJ2A==
+=ey6m
+-----END PGP SIGNATURE-----
diff --git a/lib/auto-value-annotations-1.6.5.jar.sha1 b/lib/auto-value-annotations-1.6.5.jar.sha1
new file mode 100644
index 0000000..858c96e
--- /dev/null
+++ b/lib/auto-value-annotations-1.6.5.jar.sha1
@@ -0,0 +1 @@
+c3dad10377f0e2242c9a4b88e9704eaf79103679
\ No newline at end of file
diff --git a/lib/google-java-format-1.7-all-deps.jar b/lib/google-java-format-1.7-all-deps.jar
new file mode 100644
index 0000000..e2d40de
--- /dev/null
+++ b/lib/google-java-format-1.7-all-deps.jar
Binary files differ
diff --git a/lib/google-java-format-1.7-all-deps.jar.asc b/lib/google-java-format-1.7-all-deps.jar.asc
new file mode 100644
index 0000000..73ae0e2
--- /dev/null
+++ b/lib/google-java-format-1.7-all-deps.jar.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEE53QXrBlBYKP6vQSWmiWcfuY2xe0FAlw2hwoACgkQmiWcfuY2
+xe22Ww//YIHLWoQApuSmLdq4A1fcNOYbSpm6J9I2J1i2VoK84XSXP1XJTWsoYNbx
+Y3Xx6I8p28AxH7LOWcdtds9enbF06blzz+1CxuSxvN32M7DDursiihsUYU9wmZVU
+7V1ZYBtaYTYYw8C5U+UchcIVJrHdG9KrAiBcn1s76gigNAtCYV/1PyryupS1wcDZ
+bdj48mI6adcnIpV+9D9W4rLuXw2Hg+ewktXTj3HYqkg+5Nvc/zP9ueBvqEsyh5Iz
+3+69egblhuN7gRaEWarlYfJ2n/kF9T/UMAkQrWD8+9cOgUcgTHkNADNOLpmDH6t7
+OYvZhgwQT920ZJgGP8e3DGyvMxBMxlr19ciTT19HL5qglyhFm/SeHvFdpaHkIjb9
+CmASWrlkALdEv2gPx+m79EJifyK5tYtViZgLhfjwYkS/opw5TfJX0+Ngh9ehgune
+c6TgEIzRQAEQ/9QoVk2crGT/lhXnJI3Zid7cSP2/fRdui91KaKGi9qFvXyJf7XKI
+vH0De+e3yZN/GXLYyQSUzmdQU8HMF9iuc81CT1ANgU+e9HU5k9FWSPHrA3gN7CKt
+/a3qIsIBpcdKe9zcPxSoEqRzVNept4IhszgiIVxZPNrPShzCRbS1sGURoOTbSFSP
++aKWNFoswX/RANGQVajOyfF5mJ3lB4N0u2eI0HIR3NzNx0HN+2Q=
+=+/96
+-----END PGP SIGNATURE-----
diff --git a/lib/google-java-format-1.7-all-deps.jar.sha1 b/lib/google-java-format-1.7-all-deps.jar.sha1
new file mode 100644
index 0000000..b247a7c
--- /dev/null
+++ b/lib/google-java-format-1.7-all-deps.jar.sha1
@@ -0,0 +1 @@
+b6d34a51e579b08db7c624505bdf9af4397f1702
\ No newline at end of file
diff --git a/lib/google-java-format-1.7-sources.jar b/lib/google-java-format-1.7-sources.jar
new file mode 100644
index 0000000..70fca1b
--- /dev/null
+++ b/lib/google-java-format-1.7-sources.jar
Binary files differ
diff --git a/lib/google-java-format-1.7-sources.jar.asc b/lib/google-java-format-1.7-sources.jar.asc
new file mode 100644
index 0000000..713333c
--- /dev/null
+++ b/lib/google-java-format-1.7-sources.jar.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEE53QXrBlBYKP6vQSWmiWcfuY2xe0FAlw2hwsACgkQmiWcfuY2
+xe1j6BAAsDY9DTTcjRtrT6AiZchELcJleOdqK3TRdbl193Mtw5eR+BdKqtcLZSmZ
+1EqYNcldOu9wgbZFpFL99xWNAPOt8tTU9hTsZvrRN0e5CwKXrlJl0MeJi/6yYquG
+FerYGZuDMMEza1q9D2TG5erLOjDEWVLjkSs3jw8mSyMvN0OJFhhMrU4sqhlXMGNV
+lDxeYXLXr+QtIi0tXAUQ5XSwtR7eukSevA7n3zQJKfYMlFbG82lMGJccfazJpdPf
+cJLAGY9/q3RVZx5vk00kz3sDmL+rMU01Lh+CHwT9D8ASRfzjkssHuKaMYBysuh7s
+YZ6X3Txvtkzf3fJjYl5jID3jEui82iR5jv5ncZFZFCsZsTRM0sLAP5/KeX128dHM
+fJzVH4GIUvOqt9aIDKQ+3aNsARsIH2Z2AHymUxVZoP33V9HoC8x0ghxM0xohvkh5
+L+VgUOEjekOneqWD1QEF+HD7S3hpy36+g37PYGcQRRaCIDn00Se+UbJ9RZrUVdvu
+JgmVXcpagrLmcSnkG265zdDW9Vu7vjAKhxjLXmbE0aowzdo/HZ+u3R2hpZbOyv33
+NmakhTwaUtQtDm34GVPqoypnu85va27vxVDQgTsk3im9M1l/UP65NidPuuSk7iOI
+UECD7wc6Ddh80jmDlXdlxSNG+zzGp95gS5UVoDXgwNEok7UgrY4=
+=zj6k
+-----END PGP SIGNATURE-----
diff --git a/lib/google-java-format-1.7-sources.jar.sha1 b/lib/google-java-format-1.7-sources.jar.sha1
new file mode 100644
index 0000000..31d6337
--- /dev/null
+++ b/lib/google-java-format-1.7-sources.jar.sha1
@@ -0,0 +1 @@
+dbb14f20004dfaf01a5ce9f5e75c5993f18cc0a5
\ No newline at end of file
diff --git a/lib/google-java-format-1.7.jar b/lib/google-java-format-1.7.jar
new file mode 100644
index 0000000..953541c
--- /dev/null
+++ b/lib/google-java-format-1.7.jar
Binary files differ
diff --git a/lib/google-java-format-1.7.jar.asc b/lib/google-java-format-1.7.jar.asc
new file mode 100644
index 0000000..3642d69
--- /dev/null
+++ b/lib/google-java-format-1.7.jar.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEE53QXrBlBYKP6vQSWmiWcfuY2xe0FAlw2hwkACgkQmiWcfuY2
+xe1uIhAAt9sWjStHkfHmWNFd5exYsjBmN0eObgOU5A386j5Q5P4hZjFDYsDvKlVo
+DWZKI2A9ZvpisuI083DwGJCXvbtD1WICh5Xx1B2tK2oCgl5bYiU88LCw5jS9F2IZ
+thPFhFDMIw4tQZp2J4o+itO7gtoUMfN5J9Y7ZcOWG60F3ouGc6vd8PnMk/CfxNZ0
+Zy21dkBzJVJsNghUWsHfP6WS2ySVBNQaarY+/4IuIrBVqRNZBhD+qEtZRG3mwc4X
+ydd4hCvoAQ7lysrdZEMDRx0qLQoqEWyfNFX7b8X/Oi6Ape765mD3Ss1WFgsjLqo+
+kt4Ge09f4QOCtMP95M8AnnHGjpVuibC0tb2E7qXfcrMWf+EX8ksFJKwaXZQfG4lv
+7kxZDTeeDdU6SUakiwfkEKN6s4v0MrGi8TM+776gLihcD/tx09555h+EwXrbp3IE
+1SWJCiYCuaqe1UXNEsZGYKv72GkPSEjY813Tn3endvGXX+QrLCU6DrLRyy1IWFKJ
+Yu6THeT0Z+M6h+oTO0ug2gJ6Ur7apQC4JBIi12XE+QhwuTuV0byiUArmO+3elLH4
+Nd9O0yFhKClaJ+ye+X+XLYkIjh+IJGFmbUahvCFuMMKuwbFRHwn5pw0DOJvE7qjg
+dBZhwjzKN8RHzik5nFwzhBBIzj3UglacGkUPFv7JW1TqcY2X6kE=
+=VIxo
+-----END PGP SIGNATURE-----
diff --git a/lib/google-java-format-1.7.jar.sha1 b/lib/google-java-format-1.7.jar.sha1
new file mode 100644
index 0000000..d0a76c2
--- /dev/null
+++ b/lib/google-java-format-1.7.jar.sha1
@@ -0,0 +1 @@
+97cb6afc835d65682edc248e19170a8e4ecfe4c4
\ No newline at end of file
diff --git a/lib/javax.inject-1-sources.jar b/lib/javax.inject-1-sources.jar
new file mode 100644
index 0000000..0c98053
--- /dev/null
+++ b/lib/javax.inject-1-sources.jar
Binary files differ
diff --git a/lib/javax.inject-1-sources.jar.sha1 b/lib/javax.inject-1-sources.jar.sha1
new file mode 100644
index 0000000..b69cdf0
--- /dev/null
+++ b/lib/javax.inject-1-sources.jar.sha1
@@ -0,0 +1 @@
+a00123f261762a7c5e0ec916a2c7c8298d29c400 /home/maven/repository-staging/to-ibiblio/maven2/javax/inject/javax.inject/1/javax.inject-1-sources.jar
diff --git a/lib/javax.inject-1.jar b/lib/javax.inject-1.jar
new file mode 100644
index 0000000..b2a9d0b
--- /dev/null
+++ b/lib/javax.inject-1.jar
Binary files differ
diff --git a/lib/javax.inject-1.jar.sha1 b/lib/javax.inject-1.jar.sha1
new file mode 100644
index 0000000..41e75ef
--- /dev/null
+++ b/lib/javax.inject-1.jar.sha1
@@ -0,0 +1 @@
+6975da39a7040257bd51d21a231b76c915872d38 /home/maven/repository-staging/to-ibiblio/maven2/javax/inject/javax.inject/1/javax.inject-1.jar
diff --git a/lint-baseline.xml b/lint-baseline.xml
deleted file mode 100644
index cf790c2..0000000
--- a/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Multi-catch with these reflection exceptions requires API level 19 (current min is 14) because they get compiled to the common but new super type `ReflectiveOperationException`. As a workaround either create individual catch statements, or catch `Exception`."
- errorLine1=" } catch (ClassNotFoundException"
- errorLine2=" ^">
- <location
- file="external/dagger2/java/dagger/hilt/android/internal/testing/TestApplicationComponentManager.java"
- line="85"
- column="14"/>
- </issue>
-
-</issues>
diff --git a/test_defs.bzl b/test_defs.bzl
index d16ad36..15ab299 100644
--- a/test_defs.bzl
+++ b/test_defs.bzl
@@ -12,18 +12,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-"""This file defines constants useful across the Dagger tests."""
-
-load("@rules_java//java:defs.bzl", "java_library", "java_test")
# Defines a set of build variants and the list of extra javacopts to build with.
# The key will be appended to the generated test names to ensure uniqueness.
BUILD_VARIANTS = {
"FastInit": ["-Adagger.fastInit=enabled"],
+ "AheadOfTimeSubcomponents": ["-Adagger.experimentalAheadOfTimeSubcomponents=enabled"],
+ "FastInitAndAheadOfTimeSubcomponents": [
+ "-Adagger.fastInit=enabled",
+ "-Adagger.experimentalAheadOfTimeSubcomponents=enabled",
+ ],
+ "AheadOfTimeSubcomponents_ForceUseSerializedComponentImplementations": [
+ "-Adagger.experimentalAheadOfTimeSubcomponents=enabled",
+ "-Adagger.forceUseSerializedComponentImplementations=enabled",
+ ],
}
# TODO(ronshapiro): convert this to use bazel_common
-# TODO(bcorso): split into two functions for functional vs non-functional tests?
+# TODO(user): split into two functions for functional vs non-functional tests?
def GenJavaTests(
name,
srcs,
@@ -35,8 +41,8 @@
test_javacopts = None,
functional = True):
_GenTests(
- java_library,
- java_test,
+ native.java_library,
+ native.java_test,
name,
srcs,
deps,
@@ -184,5 +190,6 @@
**test_kwargs
)
+
def _hjar_test(name, tags):
pass
diff --git a/tools/BUILD b/tools/BUILD
index 83d5048..7b3cc6c 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -15,30 +15,8 @@
# Description:
# Tools for Dagger
-load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
-load(":maven_info.bzl", "maven_info_tests")
-
package(default_visibility = ["//:src"])
-maven_info_tests()
-
exports_files([
"pom-template.xml",
])
-
-bzl_library(
- name = "maven_bzl",
- srcs = ["maven.bzl"],
- deps = [":maven_info_bzl"],
-)
-
-bzl_library(
- name = "maven_info_bzl",
- srcs = ["maven_info.bzl"],
- deps = ["@bazel_skylib//lib:unittest"],
-)
-
-bzl_library(
- name = "dejetify_bzl",
- srcs = ["dejetify.bzl"],
-)
diff --git a/tools/dejetify.bzl b/tools/dejetify.bzl
deleted file mode 100644
index 4f0b0ce..0000000
--- a/tools/dejetify.bzl
+++ /dev/null
@@ -1,47 +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.
-
-"""Macro for producing dejetified artifacts.
-"""
-
-# See: https://developer.android.com/studio/command-line/jetifier
-JETIFIER_STANDALONE = "https://dl.google.com/dl/android/studio/jetifier-zips/1.0.0-beta08/jetifier-standalone.zip"
-
-def dejetified_library(name, input, output):
- _dejetify_library(name, input, output)
-
-def _dejetify_library(name, input, output):
- """Generates a dejetified library artifact.
-
- A dejetified artifact is one that has been transformed to migrate its
- AndroidX APIs to the support equivalents.
-
- Args:
- name: The name of the target.
- input: The android_library input, e.g. ":myLibrary.aar".
- output: The name of the output artifact, e.g. "dejetified-myLibrary.aar".
- """
- native.genrule(
- name = name,
- srcs = [input],
- outs = [output],
- cmd = """
- TEMP="$$(mktemp -d)"
- curl {tool_link} --output $$TEMP/jetifier-standalone.zip
- unzip $$TEMP/jetifier-standalone.zip -d $$TEMP/
- $$TEMP/jetifier-standalone/bin/jetifier-standalone -r \
- -l info -i $< -o $@
- """.format(tool_link = JETIFIER_STANDALONE),
- local = 1,
- )
diff --git a/tools/maven.bzl b/tools/maven.bzl
index 2c648a2..2ac0359 100644
--- a/tools/maven.bzl
+++ b/tools/maven.bzl
@@ -16,9 +16,6 @@
"""
load("@google_bazel_common//tools/maven:pom_file.bzl", default_pom_file = "pom_file")
-load(":maven_info.bzl", "MavenInfo", "collect_maven_info")
-load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library")
-load("@google_bazel_common//tools/jarjar:jarjar.bzl", "jarjar_library")
def pom_file(name, targets, artifact_name, artifact_id, packaging = None, **kwargs):
default_pom_file(
@@ -38,366 +35,4 @@
**kwargs
)
-def gen_maven_artifact(
- name,
- artifact_name,
- artifact_coordinates,
- artifact_target,
- artifact_target_libs = None,
- artifact_target_maven_deps = None,
- artifact_target_maven_deps_banned = None,
- testonly = 0,
- pom_name = "pom",
- packaging = None,
- javadoc_srcs = None,
- javadoc_root_packages = None,
- javadoc_exclude_packages = None,
- javadoc_android_api_level = None,
- shaded_deps = None,
- shaded_rules = None,
- manifest = None,
- lint_deps = None,
- proguard_specs = None):
- _gen_maven_artifact(
- name,
- artifact_name,
- artifact_coordinates,
- artifact_target,
- artifact_target_libs,
- artifact_target_maven_deps,
- artifact_target_maven_deps_banned,
- testonly,
- pom_name,
- packaging,
- javadoc_srcs,
- javadoc_root_packages,
- javadoc_exclude_packages,
- javadoc_android_api_level,
- shaded_deps,
- shaded_rules,
- manifest,
- lint_deps,
- proguard_specs
- )
-
-def _gen_maven_artifact(
- name,
- artifact_name,
- artifact_coordinates,
- artifact_target,
- artifact_target_libs,
- artifact_target_maven_deps,
- artifact_target_maven_deps_banned,
- testonly,
- pom_name,
- packaging,
- javadoc_srcs,
- javadoc_root_packages,
- javadoc_exclude_packages,
- javadoc_android_api_level,
- shaded_deps,
- shaded_rules,
- manifest,
- lint_deps,
- proguard_specs):
- """Generates the files required for a maven artifact.
-
- This macro generates the following targets:
- * ":pom": The pom file for the given target and deps
- * ":<NAME>": The artifact file for the given target and deps
- * ":<NAME>-src": The sources jar file for the given target and deps
- * ":<NAME>-javadoc": The javadocs jar file for the given target and deps
-
- This macro also validates a few things. First, it validates that the
- given "target" is a maven artifact (i.e. the "tags" attribute contains
- "maven_coordinates=..."). Second, it calculates the list of transitive
- dependencies of the target that are not owned by another maven artifact,
- and validates that the given "deps" matches exactly.
-
- Args:
- name: The name associated with the various output targets.
- artifact_target: The target containing the maven_coordinates.
- artifact_name: The name of the maven artifact.
- artifact_coordinates: The coordinates of the maven artifact in the
- form: "<group_id>:<artifact_id>:<version>"
- artifact_target_libs: The set of transitive libraries of the target.
- artifact_target_maven_deps: The required maven deps of the target.
- artifact_target_maven_deps_banned: The banned maven deps of the target.
- testonly: True if the jar should be testonly.
- packaging: The packaging of the maven artifact. E.g. "aar"
- pom_name: The name of the pom file (or "pom" if absent).
- javadoc_srcs: The srcs for the javadocs.
- javadoc_root_packages: The root packages for the javadocs.
- javadoc_exclude_packages: The packages to exclude from the javadocs.
- javadoc_android_api_level: The android api level for the javadocs.
- shaded_deps: The shaded deps for the jarjar.
- shaded_rules: The shaded rules for the jarjar.
- manifest: The AndroidManifest.xml to bundle in when packaing an 'aar'.
- lint_deps: The lint targets to be bundled in when packaging an 'aar'.
- proguard_specs: The proguard spec files to be bundled in when packaging an 'aar'
- """
-
- _validate_maven_deps(
- name = name + "-validation",
- testonly = 1,
- target = artifact_target,
- expected_artifact = artifact_coordinates,
- expected_libs = artifact_target_libs,
- expected_maven_deps = artifact_target_maven_deps,
- banned_maven_deps = artifact_target_maven_deps_banned,
- )
-
- shaded_deps = shaded_deps or []
- shaded_rules = shaded_rules or []
- artifact_targets = [artifact_target] + (artifact_target_libs or [])
- lint_deps = lint_deps or []
-
- # META-INF resources files that can be combined by appending lines.
- merge_meta_inf_files = [
- "gradle/incremental.annotation.processors",
- ]
-
- artifact_id = artifact_coordinates.split(":")[1]
- pom_file(
- name = pom_name,
- testonly = testonly,
- artifact_id = artifact_id,
- artifact_name = artifact_name,
- packaging = packaging,
- targets = artifact_targets,
- )
-
- if (packaging == "aar"):
- jarjar_library(
- name = name + "-classes",
- testonly = testonly,
- jars = artifact_targets + shaded_deps,
- rules = shaded_rules,
- merge_meta_inf_files = merge_meta_inf_files,
- )
- if lint_deps:
- # jarjar all lint artifacts since an aar only contains a single lint.jar.
- jarjar_library(
- name = name + "-lint",
- jars = lint_deps,
- )
- lint_jar_name = name + "-lint.jar"
- else:
- lint_jar_name = None
-
- if proguard_specs:
- # Concatenate all proguard rules since an aar only contains a single proguard.txt
- native.genrule(
- name = name + "-proguard",
- srcs = proguard_specs,
- outs = [name + "-proguard.txt"],
- cmd = "cat $(SRCS) > $@",
- )
- proguard_file = name + "-proguard.txt"
- else:
- proguard_file = None
-
- _package_android_library(
- name = name + "-android-lib",
- manifest = manifest,
- classesJar = name + "-classes.jar",
- lintJar = lint_jar_name,
- proguardSpec = proguard_file,
- )
-
- # Copy intermediate outputs to final one.
- native.genrule(
- name = name,
- srcs = [name + "-android-lib"],
- outs = [name + ".aar"],
- cmd = "cp $< $@",
- )
- else:
- jarjar_library(
- name = name,
- testonly = testonly,
- jars = artifact_targets + shaded_deps,
- rules = shaded_rules,
- merge_meta_inf_files = merge_meta_inf_files,
- )
-
- jarjar_library(
- name = name + "-src",
- testonly = testonly,
- jars = [_src_jar(dep) for dep in artifact_targets],
- merge_meta_inf_files = merge_meta_inf_files,
- )
-
- if javadoc_srcs != None:
- javadoc_library(
- name = name + "-javadoc",
- srcs = javadoc_srcs,
- testonly = testonly,
- root_packages = javadoc_root_packages,
- exclude_packages = javadoc_exclude_packages,
- android_api_level = javadoc_android_api_level,
- deps = artifact_targets,
- )
- else:
- # Build an empty javadoc because Sonatype requires javadocs
- # even if the jar is empty.
- # https://central.sonatype.org/pages/requirements.html#supply-javadoc-and-sources
- native.java_binary(
- name = name + "-javadoc",
- )
-
-def _src_jar(target):
- if target.startswith(":"):
- target = Label("//" + native.package_name() + target)
- else:
- target = Label(target)
- return "//%s:lib%s-src.jar" % (target.package, target.name)
-
-def _validate_maven_deps_impl(ctx):
- """Validates the given Maven target and deps
-
- Validates that the given "target" is a maven artifact (i.e. the "tags"
- attribute contains "maven_coordinates=..."). Second, it calculates the
- list of transitive dependencies of the target that are not owned by
- another maven artifact, and validates that the given "deps" matches
- exactly.
- """
- target = ctx.attr.target
- artifact = target[MavenInfo].artifact
- if not artifact:
- fail("\t[Error]: %s is not a maven artifact" % target.label)
-
- if artifact != ctx.attr.expected_artifact:
- fail(
- "\t[Error]: %s expected artifact, %s, but was: %s" % (
- target.label,
- ctx.attr.expected_artifact,
- artifact,
- ),
- )
-
- all_transitive_deps = target[MavenInfo].all_transitive_deps.to_list()
- maven_nearest_artifacts = target[MavenInfo].maven_nearest_artifacts.to_list()
- maven_transitive_deps = target[MavenInfo].maven_transitive_deps.to_list()
-
- expected_libs = [dep.label for dep in getattr(ctx.attr, "expected_libs", [])]
- actual_libs = [dep for dep in all_transitive_deps if dep not in maven_transitive_deps]
- _validate_list("artifact_target_libs", actual_libs, expected_libs)
-
- expected_maven_deps = [dep for dep in getattr(ctx.attr, "expected_maven_deps", [])]
- actual_maven_deps = [_strip_artifact_version(artifact) for artifact in maven_nearest_artifacts]
- _validate_list(
- "artifact_target_maven_deps",
- actual_maven_deps,
- expected_maven_deps,
- ctx.attr.banned_maven_deps,
- )
-
-def _validate_list(name, actual_list, expected_list, banned_list = []):
- missing = sorted(['"{}",'.format(x) for x in actual_list if x not in expected_list])
- if missing:
- fail("\t[Error]: Found missing {}: \n\t\t".format(name) + "\n\t\t".join(missing))
-
- extra = sorted(['"{}",'.format(x) for x in expected_list if x not in actual_list])
- if extra:
- fail("\t[Error]: Found extra {}: \n\t\t".format(name) + "\n\t\t".join(extra))
-
- banned = sorted(['"{}",'.format(x) for x in actual_list if x in banned_list])
- if banned:
- fail("\t[Error]: Found banned {}: \n\t\t".format(name) + "\n\t\t".join(banned))
-
-def _strip_artifact_version(artifact):
- return artifact.rsplit(":", 1)[0]
-
-_validate_maven_deps = rule(
- implementation = _validate_maven_deps_impl,
- attrs = {
- "target": attr.label(
- doc = "The target to generate a maven artifact for.",
- aspects = [collect_maven_info],
- mandatory = True,
- ),
- "expected_artifact": attr.string(
- doc = "The artifact name of the target.",
- mandatory = True,
- ),
- "expected_libs": attr.label_list(
- doc = "The set of transitive libraries of the target, if any.",
- ),
- "expected_maven_deps": attr.string_list(
- doc = "The required maven dependencies of the target, if any.",
- ),
- "banned_maven_deps": attr.string_list(
- doc = "The required maven dependencies of the target, if any.",
- ),
- },
-)
-
-def _package_android_library_impl(ctx):
- """A very, very simple Android Library (aar) packaging rule.
-
- This rule only support packaging simple android libraries. No resources
- support, assets, extra libs, nor jni. This rule is needed because
- there is no 'JarJar equivalent' for AARs and some of our artifacts are
- composed of sources spread across multiple android_library targets.
-
- See: https://developer.android.com/studio/projects/android-library.html#aar-contents
- """
- inputs = [ctx.file.manifest, ctx.file.classesJar]
- if ctx.file.lintJar:
- inputs.append(ctx.file.lintJar)
- if ctx.file.proguardSpec:
- inputs.append(ctx.file.proguardSpec)
-
- ctx.actions.run_shell(
- inputs = inputs,
- outputs = [ctx.outputs.aar],
- command = """
- TMPDIR="$(mktemp -d)"
- cp {manifest} $TMPDIR/AndroidManifest.xml
- cp {classesJar} $TMPDIR/classes.jar
- if [[ -a {lintJar} ]]; then
- cp {lintJar} $TMPDIR/lint.jar
- fi
- if [[ -a {proguardSpec} ]]; then
- cp {proguardSpec} $TMPDIR/proguard.txt
- fi
- touch $TMPDIR/R.txt
- zip -j {outputFile} $TMPDIR/*
- """.format(
- manifest = ctx.file.manifest.path,
- classesJar = ctx.file.classesJar.path,
- lintJar = ctx.file.lintJar.path if ctx.file.lintJar else "none",
- proguardSpec = ctx.file.proguardSpec.path if ctx.file.proguardSpec else "none",
- outputFile = ctx.outputs.aar.path,
- ),
- )
-
-_package_android_library = rule(
- implementation = _package_android_library_impl,
- attrs = {
- "manifest": attr.label(
- doc = "The AndroidManifest.xml file.",
- allow_single_file = True,
- mandatory = True,
- ),
- "classesJar": attr.label(
- doc = "The classes.jar file.",
- allow_single_file = True,
- mandatory = True,
- ),
- "lintJar": attr.label(
- doc = "The lint.jar file.",
- allow_single_file = True,
- mandatory = False,
- ),
- "proguardSpec": attr.label(
- doc = "The proguard.txt file.",
- allow_single_file = True,
- mandatory = False,
- ),
- },
- outputs = {
- "aar": "%{name}.aar",
- },
-)
+POM_VERSION = "2.23.1"
diff --git a/tools/maven_info.bzl b/tools/maven_info.bzl
deleted file mode 100644
index 5ebed3f..0000000
--- a/tools/maven_info.bzl
+++ /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.
-"""Skylark rules to collect Maven artifacts information.
-"""
-
-load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest")
-
-# TODO(b/142057516): Unfork this file once we've settled on a more general API.
-MavenInfo = provider(
- fields = {
- "artifact": """
- The Maven coordinate for the artifact that is exported by this target, if one exists.
- """,
- "has_srcs": """
- True if this library contains srcs..
- """,
- "all_transitive_deps": """
- All transitive deps of the target with srcs.
- """,
- "maven_nearest_artifacts": """
- The nearest maven deps of the target.
- """,
- "maven_transitive_deps": """
- All transitive deps that are included in some maven dependency.
- """,
- },
-)
-
-_EMPTY_MAVEN_INFO = MavenInfo(
- artifact = None,
- has_srcs = False,
- maven_nearest_artifacts = depset(),
- maven_transitive_deps = depset(),
- all_transitive_deps = depset(),
-)
-
-_MAVEN_COORDINATES_PREFIX = "maven_coordinates="
-
-def _collect_maven_info_impl(target, ctx):
- tags = getattr(ctx.rule.attr, "tags", [])
- srcs = getattr(ctx.rule.attr, "srcs", [])
- deps = getattr(ctx.rule.attr, "deps", [])
- exports = getattr(ctx.rule.attr, "exports", [])
-
- artifact = None
- for tag in tags:
- if tag in ("maven:compile_only", "maven:shaded"):
- return [_EMPTY_MAVEN_INFO]
- if tag.startswith(_MAVEN_COORDINATES_PREFIX):
- artifact = tag[len(_MAVEN_COORDINATES_PREFIX):]
-
- all_deps = [dep.label for dep in (deps + exports) if dep[MavenInfo].has_srcs]
- all_transitive_deps = [dep[MavenInfo].all_transitive_deps for dep in (deps + exports)]
-
- maven_artifacts = []
- maven_nearest_artifacts = []
- maven_deps = []
- maven_transitive_deps = []
- for dep in (deps + exports):
- # If the dep is itself a maven artifact, add it and all of its transitive deps.
- # Otherwise, just propagate its transitive maven deps.
- if dep[MavenInfo].artifact or dep[MavenInfo] == _EMPTY_MAVEN_INFO:
- if (dep[MavenInfo].artifact):
- maven_artifacts.append(dep[MavenInfo].artifact)
- maven_deps.append(dep.label)
- maven_transitive_deps.append(dep[MavenInfo].all_transitive_deps)
- else:
- maven_nearest_artifacts.append(dep[MavenInfo].maven_nearest_artifacts)
- maven_transitive_deps.append(dep[MavenInfo].maven_transitive_deps)
-
- return [MavenInfo(
- artifact = artifact,
- has_srcs = len(srcs) > 0,
- maven_nearest_artifacts = depset(maven_artifacts, transitive = maven_nearest_artifacts),
- maven_transitive_deps = depset(maven_deps, transitive = maven_transitive_deps),
- all_transitive_deps = depset(all_deps, transitive = all_transitive_deps),
- )]
-
-collect_maven_info = aspect(
- attr_aspects = [
- "deps",
- "exports",
- ],
- doc = """
- Collects the Maven information for targets, their dependencies, and their transitive exports.
- """,
- implementation = _collect_maven_info_impl,
-)
-
-def _fake_java_library(name, deps = None, exports = None, is_artifact = True):
- src_file = ["%s.java" % name]
- native.genrule(
- name = "%s_source_file" % name,
- outs = src_file,
- cmd = "echo 'package pkg; class %s {}' > $@" % name,
- )
- native.java_library(
- name = name,
- srcs = src_file,
- tags = ["maven_coordinates=%s:_:_" % name] if is_artifact else [],
- deps = deps or [],
- exports = exports or [],
- )
-
-def _maven_info_test_impl(ctx):
- env = unittest.begin(ctx)
- asserts.equals(
- env,
- expected = ctx.attr.artifact if ctx.attr.artifact else None,
- actual = ctx.attr.target[MavenInfo].artifact,
- msg = "MavenInfo.artifact",
- )
- asserts.equals(
- env,
- expected = sorted([ctx.label.relative(dep) for dep in ctx.attr.maven_transitive_deps]),
- actual = sorted(ctx.attr.target[MavenInfo].maven_transitive_deps.to_list()),
- msg = "MavenInfo.maven_transitive_deps",
- )
- asserts.equals(
- env,
- expected = sorted([ctx.label.relative(dep) for dep in ctx.attr.all_transitive_deps]),
- actual = sorted(ctx.attr.target[MavenInfo].all_transitive_deps.to_list()),
- msg = "MavenInfo.all_transitive_deps",
- )
- return unittest.end(env)
-
-_maven_info_test = unittest.make(
- _maven_info_test_impl,
- attrs = {
- "target": attr.label(aspects = [collect_maven_info]),
- "artifact": attr.string(),
- "maven_transitive_deps": attr.string_list(),
- "all_transitive_deps": attr.string_list(),
- },
-)
-
-def maven_info_tests():
- """Tests for `pom_file` and `MavenInfo`.
- """
- _fake_java_library(name = "A")
- _fake_java_library(
- name = "DepOnA",
- deps = [":A"],
- )
-
- _maven_info_test(
- name = "a_test",
- target = ":A",
- artifact = "A:_:_",
- maven_transitive_deps = [],
- all_transitive_deps = [],
- )
-
- _maven_info_test(
- name = "dependencies_test",
- target = ":DepOnA",
- artifact = "DepOnA:_:_",
- maven_transitive_deps = [":A"],
- all_transitive_deps = [":A"],
- )
-
- _fake_java_library(
- name = "ExportsA",
- exports = [":A"],
- )
-
- _maven_info_test(
- name = "exports_test",
- target = ":ExportsA",
- artifact = "ExportsA:_:_",
- maven_transitive_deps = [":A"],
- all_transitive_deps = [":A"],
- )
-
- _fake_java_library(
- name = "TransitiveExports",
- exports = [":ExportsA"],
- )
-
- _maven_info_test(
- name = "transitive_exports_test",
- target = ":TransitiveExports",
- artifact = "TransitiveExports:_:_",
- maven_transitive_deps = [":ExportsA", ":A"],
- all_transitive_deps = [":ExportsA", ":A"],
- )
-
- _fake_java_library(
- name = "TransitiveDeps",
- deps = [":ExportsA"],
- )
-
- _maven_info_test(
- name = "transitive_deps_test",
- target = ":TransitiveDeps",
- artifact = "TransitiveDeps:_:_",
- maven_transitive_deps = [":ExportsA", ":A"],
- all_transitive_deps = [":ExportsA", ":A"],
- )
-
- _fake_java_library(name = "Node1", is_artifact = False)
- _maven_info_test(
- name = "test_node1",
- target = ":Node1",
- maven_transitive_deps = [],
- all_transitive_deps = [],
- )
-
- _fake_java_library(name = "Node2_Artifact", deps = [":Node1"])
- _maven_info_test(
- name = "test_node2",
- target = ":Node2_Artifact",
- artifact = "Node2_Artifact:_:_",
- maven_transitive_deps = [],
- all_transitive_deps = [":Node1"],
- )
-
- _fake_java_library(name = "Node3", deps = [":Node2_Artifact"], is_artifact = False)
- _maven_info_test(
- name = "test_node3",
- target = ":Node3",
- maven_transitive_deps = [":Node1", ":Node2_Artifact"],
- all_transitive_deps = [":Node1", ":Node2_Artifact"],
- )
-
- _fake_java_library(name = "Node4", deps = [":Node3"], is_artifact = False)
- _maven_info_test(
- name = "test_node4",
- target = ":Node4",
- maven_transitive_deps = [":Node1", ":Node2_Artifact"],
- all_transitive_deps = [":Node1", ":Node2_Artifact", ":Node3"],
- )
diff --git a/tools/pom-template.xml b/tools/pom-template.xml
index 68b6ac0..39ed62d 100644
--- a/tools/pom-template.xml
+++ b/tools/pom-template.xml
@@ -16,6 +16,7 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
+
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
@@ -31,7 +32,7 @@
<packaging>{packaging}</packaging>
<scm>
- <url>https://github.com/google/dagger/</url>
+ <url>http://github.com/google/dagger/</url>
<connection>scm:git:git://github.com/google/dagger.git</connection>
<developerConnection>scm:git:ssh://git@github.com/google/dagger.git</developerConnection>
<tag>HEAD</tag>
@@ -39,21 +40,22 @@
<issueManagement>
<system>GitHub Issues</system>
- <url>https://github.com/google/dagger/issues</url>
+ <url>http://github.com/google/dagger/issues</url>
</issueManagement>
<licenses>
<license>
<name>Apache 2.0</name>
- <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<organization>
<name>Google, Inc.</name>
- <url>https://www.google.com</url>
+ <url>http://www.google.com</url>
</organization>
+
<dependencies>
- {generated_bzl_deps}
+{generated_bzl_deps}
</dependencies>
</project>
diff --git a/util/deploy-dagger.sh b/util/deploy-dagger.sh
deleted file mode 100755
index ddf4926..0000000
--- a/util/deploy-dagger.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-readonly MVN_GOAL="$1"
-readonly VERSION_NAME="$2"
-shift 2
-readonly EXTRA_MAVEN_ARGS=("$@")
-
-# Builds and deploys the given artifacts to a configured maven goal.
-# @param {string} library the library to deploy.
-# @param {string} pomfile the pom file to deploy.
-# @param {string} srcjar the sources jar of the library. This is an optional
-# parameter, if provided then javadoc must also be provided.
-# @param {string} javadoc the java doc jar of the library. This is an optional
-# parameter, if provided then srcjar must also be provided.
-_deploy() {
- local library=$1
- local pomfile=$2
- local srcjar=$3
- local javadoc=$4
- bash $(dirname $0)/deploy-library.sh \
- "$library" \
- "$pomfile" \
- "$srcjar" \
- "$javadoc" \
- "$MVN_GOAL" \
- "$VERSION_NAME" \
- "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
-}
-
-_deploy \
- java/dagger/libcore.jar \
- java/dagger/pom.xml \
- java/dagger/libcore-src.jar \
- java/dagger/core-javadoc.jar
-
-_deploy \
- gwt/libgwt.jar \
- gwt/pom.xml \
- gwt/libgwt.jar \
- gwt/libgwt.jar
-
-_deploy \
- java/dagger/internal/codegen/artifact.jar \
- java/dagger/internal/codegen/pom.xml \
- java/dagger/internal/codegen/artifact-src.jar \
- java/dagger/internal/codegen/artifact-javadoc.jar
-
-_deploy \
- java/dagger/producers/artifact.jar \
- java/dagger/producers/pom.xml \
- java/dagger/producers/artifact-src.jar \
- java/dagger/producers/artifact-javadoc.jar
-
-_deploy \
- java/dagger/spi/artifact.jar \
- java/dagger/spi/pom.xml \
- java/dagger/spi/artifact-src.jar \
- java/dagger/spi/artifact-javadoc.jar
-
-_deploy \
- java/dagger/android/android.aar \
- java/dagger/android/pom.xml \
- java/dagger/android/libandroid-src.jar \
- java/dagger/android/android-javadoc.jar
-
-_deploy \
- java/dagger/android/android-legacy.aar \
- java/dagger/android/legacy-pom.xml \
- "" \
- ""
-
-# b/37741866 and https://github.com/google/dagger/issues/715
-_deploy \
- java/dagger/android/libandroid.jar \
- java/dagger/android/jarimpl-pom.xml \
- java/dagger/android/libandroid-src.jar \
- java/dagger/android/android-javadoc.jar
-
-_deploy \
- java/dagger/android/support/support.aar \
- java/dagger/android/support/pom.xml \
- java/dagger/android/support/libsupport-src.jar \
- java/dagger/android/support/support-javadoc.jar
-
-_deploy \
- java/dagger/android/support/support-legacy.aar \
- java/dagger/android/support/legacy-pom.xml \
- "" \
- ""
-
-_deploy \
- shaded_android_processor.jar \
- java/dagger/android/processor/pom.xml \
- java/dagger/android/processor/libprocessor-src.jar \
- java/dagger/android/processor/processor-javadoc.jar
-
-_deploy \
- java/dagger/grpc/server/libserver.jar \
- java/dagger/grpc/server/server-pom.xml \
- java/dagger/grpc/server/libserver-src.jar \
- java/dagger/grpc/server/javadoc.jar
-
-_deploy \
- java/dagger/grpc/server/libannotations.jar \
- java/dagger/grpc/server/annotations-pom.xml \
- java/dagger/grpc/server/libannotations-src.jar \
- java/dagger/grpc/server/javadoc.jar
-
-_deploy \
- shaded_grpc_server_processor.jar \
- java/dagger/grpc/server/processor/pom.xml \
- java/dagger/grpc/server/processor/libprocessor-src.jar \
- java/dagger/grpc/server/processor/javadoc.jar
-
-_deploy \
- java/dagger/lint/lint-artifact.jar \
- java/dagger/lint/lint-pom.xml \
- java/dagger/lint/lint-artifact-src.jar \
- java/dagger/lint/lint-artifact-javadoc.jar
-
-_deploy \
- java/dagger/lint/lint-android-artifact.aar \
- java/dagger/lint/lint-android-pom.xml \
- "" \
- ""
diff --git a/util/deploy-hilt.sh b/util/deploy-hilt.sh
deleted file mode 100755
index 3c25c10..0000000
--- a/util/deploy-hilt.sh
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-readonly MVN_GOAL="$1"
-readonly VERSION_NAME="$2"
-shift 2
-readonly EXTRA_MAVEN_ARGS=("$@")
-
-# Builds and deploys the given artifacts to a configured maven goal.
-# @param {string} library the library to deploy.
-# @param {string} pomfile the pom file to deploy.
-# @param {string} srcjar the sources jar of the library. This is an optional
-# parameter, if provided then javadoc must also be provided.
-# @param {string} javadoc the java doc jar of the library. This is an optional
-# parameter, if provided then srcjar must also be provided.
-_deploy() {
- local library=$1
- local pomfile=$2
- local srcjar=$3
- local javadoc=$4
- bash $(dirname $0)/deploy-library.sh \
- "$library" \
- "$pomfile" \
- "$srcjar" \
- "$javadoc" \
- "$MVN_GOAL" \
- "$VERSION_NAME" \
- "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
-}
-
-_deploy \
- java/dagger/hilt/android/artifact.aar \
- java/dagger/hilt/android/pom.xml \
- java/dagger/hilt/android/artifact-src.jar \
- java/dagger/hilt/android/artifact-javadoc.jar
-
-_deploy \
- java/dagger/hilt/android/testing/artifact.aar \
- java/dagger/hilt/android/testing/pom.xml \
- java/dagger/hilt/android/testing/artifact-src.jar \
- java/dagger/hilt/android/testing/artifact-javadoc.jar
-
-_deploy \
- java/dagger/hilt/processor/artifact.jar \
- java/dagger/hilt/processor/pom.xml \
- java/dagger/hilt/processor/artifact-src.jar \
- java/dagger/hilt/processor/artifact-javadoc.jar
-
-_deploy \
- java/dagger/hilt/android/processor/artifact.jar \
- java/dagger/hilt/android/processor/pom.xml \
- java/dagger/hilt/android/processor/artifact-src.jar \
- java/dagger/hilt/android/processor/artifact-javadoc.jar
-
-_deploy \
- java/dagger/hilt/artifact-core.jar \
- java/dagger/hilt/pom.xml \
- java/dagger/hilt/artifact-core-src.jar \
- java/dagger/hilt/artifact-core-javadoc.jar
-
-# Builds and deploy the Gradle plugin.
-_deploy_plugin() {
- local plugindir=java/dagger/hilt/android/plugin
- ./$plugindir/gradlew -p $plugindir --no-daemon clean \
- publishAllPublicationsToMavenRepository -PPublishVersion="$VERSION_NAME"
- local outdir=$plugindir/build/repo/com/google/dagger/hilt-android-gradle-plugin/$VERSION_NAME
- # When building '-SNAPSHOT' versions in gradle, the filenames replaces
- # '-SNAPSHOT' with timestamps, so we need to disambiguate by finding each file
- # to deploy. See: https://stackoverflow.com/questions/54182823/
- local suffix
- if [[ "$VERSION_NAME" == *"-SNAPSHOT" ]]; then
- # Gets the timestamp part out of the name to be used as suffix.
- # Timestamp format is ########.######-#.
- suffix=$(find $outdir -name "*.pom" | grep -Eo '[0-9]{8}\.[0-9]{6}-[0-9]{1}')
- else
- suffix=$VERSION_NAME
- fi
- mvn "$MVN_GOAL" \
- -Dfile="$(find $outdir -name "*-$suffix.jar")" \
- -DpomFile="$(find $outdir -name "*-$suffix.pom")" \
- -Dsources="$(find $outdir -name "*-$suffix-sources.jar")" \
- -Djavadoc="$(find $outdir -name "*-$suffix-javadoc.jar")" \
- "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
-}
-
-# Gradle Plugin is built with Gradle, but still deployed via Maven (mvn)
-_deploy_plugin
diff --git a/util/deploy-library.sh b/util/deploy-library.sh
deleted file mode 100755
index a744402..0000000
--- a/util/deploy-library.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/bin/bash
-
-set -eu
-
-# Builds and deploys the given artifacts to a configured maven goal.
-# @param {string} library the library to deploy.
-# @param {string} pomfile the pom file to deploy.
-# @param {string} srcjar the sources jar of the library. This is an optional
-# parameter, if provided then javadoc must also be provided.
-# @param {string} javadoc the java doc jar of the library. This is an optional
-# parameter, if provided then srcjar must also be provided.
-deploy_library() {
- local library=$1
- local pomfile=$2
- local srcjar=$3
- local javadoc=$4
- local mvn_goal=$5
- local version_name=$6
- shift 6
- local extra_maven_args=("$@")
-
- bazel build --define=pom_version="$version_name" \
- $library $pomfile
-
- # TODO(bcorso): Consider moving this into the "gen_maven_artifact" macro, this
- # requires having the version checked-in for the build system.
- add_tracking_version \
- $(bazel_output_file $library) \
- $(bazel_output_file $pomfile) \
- $version_name
-
- if [ -n "$srcjar" ] && [ -n "$javadoc" ] ; then
- bazel build --define=pom_version="$version_name" \
- $srcjar $javadoc
- mvn $mvn_goal \
- -Dfile=$(bazel_output_file $library) \
- -Djavadoc=$(bazel_output_file $javadoc) \
- -DpomFile=$(bazel_output_file $pomfile) \
- -Dsources=$(bazel_output_file $srcjar) \
- "${extra_maven_args[@]:+${extra_maven_args[@]}}"
- else
- mvn $mvn_goal \
- -Dfile=$(bazel_output_file $library) \
- -DpomFile=$(bazel_output_file $pomfile) \
- "${extra_maven_args[@]:+${extra_maven_args[@]}}"
- fi
-}
-
-bazel_output_file() {
- local library=$1
- local output_file=bazel-bin/$library
- if [[ ! -e $output_file ]]; then
- output_file=bazel-genfiles/$library
- fi
- if [[ ! -e $output_file ]]; then
- echo "Could not find bazel output file for $library"
- exit 1
- fi
- echo -n $output_file
-}
-
-add_tracking_version() {
- local library=$1
- local pomfile=$2
- local version_name=$3
- local group_id=$(find_pom_value $pomfile "groupId")
- local artifact_id=$(find_pom_value $pomfile "artifactId")
- local temp_dir=$(mktemp -d)
- local version_file="META-INF/${group_id}_${artifact_id}.version"
- mkdir -p "$temp_dir/META-INF/"
- echo $version_name >> "$temp_dir/$version_file"
- if [[ $library =~ \.jar$ ]]; then
- jar uf $library -C $temp_dir $version_file
- elif [[ $library =~ \.aar$ ]]; then
- unzip $library classes.jar -d $temp_dir
- jar uf $temp_dir/classes.jar -C $temp_dir $version_file
- jar uf $library -C $temp_dir classes.jar
- else
- echo "Could not add tracking version file to $library"
- exit 1
- fi
-}
-
-find_pom_value() {
- local pomfile=$1
- local attribute=$2
- # Using Python here because `mvn help:evaluate` doesn't work with our gen pom
- # files since they don't include the aar packaging plugin.
- python $(dirname $0)/find_pom_value.py $pomfile $attribute
-}
-
-deploy_library "$@"
diff --git a/util/deploy-to-maven-central.sh b/util/deploy-to-maven-central.sh
index de2b49c..1f721a1 100755
--- a/util/deploy-to-maven-central.sh
+++ b/util/deploy-to-maven-central.sh
@@ -6,69 +6,50 @@
echo "usage $0 <ssl-key> <version-name> [<param> ...]"
exit 1;
fi
-readonly KEY=$1
-readonly VERSION_NAME=$2
+key=$1
+version_name=$2
shift 2
-if [[ ! "$VERSION_NAME" =~ ^2\. ]]; then
+if [[ ! "$version_name" =~ ^2\. ]]; then
echo 'Version name must begin with "2."'
exit 2
fi
-if [[ "$VERSION_NAME" =~ " " ]]; then
+if [[ "$version_name" =~ " " ]]; then
echo "Version name must not have any spaces"
exit 3
fi
-bash $(dirname $0)/run-local-tests.sh
+bazel test //...
-# Note: we detach from head before making any sed changes to avoid commiting
-# a particular version to master. This sed change used to be done at the very
-# end of the script, but with the introduction of "-alpha" to the Hilt
-# artifacts, we need to do the sed replacement before deploying the artifacts to
-# maven. Note, that this sed replacement is only done for versioned releases.
-# HEAD-SNAPSHOT and LOCAL_SNAPSHOT versions of Hilt artifacts do not contain
-# "-alpha".
-git checkout --detach
-
-# Set the version string that is used as a tag in all of our libraries. If
-# another repo depends on a versioned tag of Dagger, their java_library.tags
-# should match the versioned release.
-sed -i s/'#ALPHA_POSTFIX'/'+ "-alpha"'/g build_defs.bzl
-sed -i s/'${project.version}'/"${VERSION_NAME}"/g build_defs.bzl
-
-bash $(dirname $0)/deploy-dagger.sh \
+bash $(dirname $0)/execute-deploy.sh \
"gpg:sign-and-deploy-file" \
- "$VERSION_NAME" \
+ "$version_name" \
"-DrepositoryId=sonatype-nexus-staging" \
"-Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/" \
- "-Dgpg.keyname=${KEY}"
-
-bash $(dirname $0)/deploy-hilt.sh \
- "gpg:sign-and-deploy-file" \
- "${VERSION_NAME}-alpha" \
- "-DrepositoryId=sonatype-nexus-staging" \
- "-Durl=https://oss.sonatype.org/service/local/staging/deploy/maven2/" \
- "-Dgpg.keyname=${KEY}"
-
-# Note: We avoid commiting until after deploying in case deploying fails and
-# we need to run the script again.
-git commit -m "${VERSION_NAME} release" build_defs.bzl
-git tag -a -m "Dagger ${VERSION_NAME}" dagger-"${VERSION_NAME}"
-git push origin tag dagger-"${VERSION_NAME}"
-
-# Switch back to the original HEAD
-git checkout -
+ "-Dgpg.keyname=${key}"
# Publish javadocs to gh-pages
bazel build //:user-docs.jar
git clone --quiet --branch gh-pages \
https://github.com/google/dagger gh-pages > /dev/null
cd gh-pages
-unzip ../bazel-bin/user-docs.jar -d api/$VERSION_NAME
-rm -rf api/$VERSION_NAME/META-INF/
-git add api/$VERSION_NAME
-git commit -m "$VERSION_NAME docs"
+unzip ../bazel-bin/user-docs.jar -d api/$version_name
+rm -rf api/$version_name/META-INF/
+git add api/$version_name
+git commit -m "$version_name docs"
git push origin gh-pages
cd ..
rm -rf gh-pages
+
+git checkout --detach
+# Set the version string that is used as a tag in all of our libraries. If another repo depends on
+# a versioned tag of Dagger, their java_library.tags should match the versioned release.
+sed -i s/'${project.version}'/"${version_name}"/g tools/maven.bzl
+git commit -m "${version_name} release" tools/maven.bzl
+
+git tag -a -m "Dagger ${version_name}" dagger-"${version_name}"
+git push origin tag dagger-"${version_name}"
+
+# Switch back to the original HEAD
+git checkout -
diff --git a/util/execute-deploy.sh b/util/execute-deploy.sh
new file mode 100755
index 0000000..1153468
--- /dev/null
+++ b/util/execute-deploy.sh
@@ -0,0 +1,110 @@
+#!/bin/bash
+
+set -eu
+
+readonly MVN_GOAL="$1"
+readonly VERSION_NAME="$2"
+shift 2
+readonly EXTRA_MAVEN_ARGS=("$@")
+
+bazel_output_file() {
+ local library=$1
+ local output_file=bazel-bin/$library
+ if [[ ! -e $output_file ]]; then
+ output_file=bazel-genfiles/$library
+ fi
+ if [[ ! -e $output_file ]]; then
+ echo "Could not find bazel output file for $library"
+ exit 1
+ fi
+ echo -n $output_file
+}
+
+deploy_library() {
+ local library=$1
+ local srcjar=$2
+ local javadoc=$3
+ local pomfile=$4
+ bazel build --define=pom_version="$VERSION_NAME" \
+ $library $srcjar $javadoc $pomfile
+
+ mvn $MVN_GOAL \
+ -Dfile=$(bazel_output_file $library) \
+ -Djavadoc=$(bazel_output_file $javadoc) \
+ -DpomFile=$(bazel_output_file $pomfile) \
+ -Dsources=$(bazel_output_file $srcjar) \
+ "${EXTRA_MAVEN_ARGS[@]:+${EXTRA_MAVEN_ARGS[@]}}"
+}
+
+deploy_library \
+ java/dagger/libcore.jar \
+ java/dagger/libcore-src.jar \
+ java/dagger/core-javadoc.jar \
+ java/dagger/pom.xml
+
+deploy_library \
+ gwt/libgwt.jar \
+ gwt/libgwt.jar \
+ gwt/libgwt.jar \
+ gwt/pom.xml
+
+deploy_library \
+ shaded_compiler.jar \
+ shaded_compiler_src.jar \
+ java/dagger/internal/codegen/codegen-javadoc.jar \
+ java/dagger/internal/codegen/pom.xml
+
+deploy_library \
+ java/dagger/producers/libproducers.jar \
+ java/dagger/producers/libproducers-src.jar \
+ java/dagger/producers/producers-javadoc.jar \
+ java/dagger/producers/pom.xml
+
+deploy_library \
+ shaded_spi.jar \
+ shaded_spi_src.jar \
+ spi-javadoc.jar \
+ java/dagger/spi/pom.xml
+
+deploy_library \
+ java/dagger/android/android.aar \
+ java/dagger/android/libandroid-src.jar \
+ java/dagger/android/android-javadoc.jar \
+ java/dagger/android/pom.xml
+
+# b/37741866 and https://github.com/google/dagger/issues/715
+deploy_library \
+ java/dagger/android/libandroid.jar \
+ java/dagger/android/libandroid-src.jar \
+ java/dagger/android/android-javadoc.jar \
+ java/dagger/android/jarimpl-pom.xml
+
+deploy_library \
+ java/dagger/android/support/support.aar \
+ java/dagger/android/support/libsupport-src.jar \
+ java/dagger/android/support/support-javadoc.jar \
+ java/dagger/android/support/pom.xml
+
+deploy_library \
+ shaded_android_processor.jar \
+ java/dagger/android/processor/libprocessor-src.jar \
+ java/dagger/android/processor/processor-javadoc.jar \
+ java/dagger/android/processor/pom.xml
+
+deploy_library \
+ java/dagger/grpc/server/libserver.jar \
+ java/dagger/grpc/server/libserver-src.jar \
+ java/dagger/grpc/server/javadoc.jar \
+ java/dagger/grpc/server/server-pom.xml
+
+deploy_library \
+ java/dagger/grpc/server/libannotations.jar \
+ java/dagger/grpc/server/libannotations-src.jar \
+ java/dagger/grpc/server/javadoc.jar \
+ java/dagger/grpc/server/annotations-pom.xml
+
+deploy_library \
+ shaded_grpc_server_processor.jar \
+ java/dagger/grpc/server/processor/libprocessor-src.jar \
+ java/dagger/grpc/server/processor/javadoc.jar \
+ java/dagger/grpc/server/processor/pom.xml
diff --git a/util/find_pom_value.py b/util/find_pom_value.py
deleted file mode 100644
index c662b0e..0000000
--- a/util/find_pom_value.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Find value of a Maven pom attribute given a pom file.
-
- Usage:
- python find_pom_value.py <pom-file> <pom-attribute>
-"""
-import sys
-import xml.etree.ElementTree as Xml
-
-
-def main(argv):
- pom_file = argv[1]
- pom_attribute = argv[2]
- print(
- Xml.ElementTree(file=pom_file).findtext(
- "{http://maven.apache.org/POM/4.0.0}%s" % pom_attribute))
-
-
-if __name__ == "__main__":
- main(sys.argv)
diff --git a/util/generate-latest-docs.sh b/util/generate-latest-docs.sh
index c5f71fd..8e9304c 100755
--- a/util/generate-latest-docs.sh
+++ b/util/generate-latest-docs.sh
@@ -1,35 +1,30 @@
-set -eux
+# see http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/ for details
-if [ "$GITHUB_REPOSITORY" == "google/dagger" ] && \
- [ "$GITHUB_EVENT_NAME" == "push" ] && \
- [ "$GITHUB_REF" == "refs/heads/master" ]; then
+set -eu
+
+if [ "$TRAVIS_REPO_SLUG" == "google/dagger" ] && \
+ [ "$TRAVIS_JDK_VERSION" == "$JDK_FOR_PUBLISHING" ] && \
+ [ "$TRAVIS_PULL_REQUEST" == "false" ] && \
+ [ "$TRAVIS_BRANCH" == "master" ]; then
echo -e "Publishing javadoc...\n"
bazel build //:user-docs.jar
JAVADOC_JAR="$(pwd)/bazel-bin/user-docs.jar"
cd $HOME
- git clone --quiet --branch=gh-pages https://x-access-token:${GH_TOKEN}@github.com/google/dagger gh-pages > /dev/null
+ git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/google/dagger gh-pages > /dev/null
cd gh-pages
- git config --global user.email "dagger-dev+github@google.com"
- git config --global user.name "Dagger Team"
+ git config --global user.email "travis@travis-ci.org"
+ git config --global user.name "travis-ci"
git rm -rf api/latest
mkdir -p api
unzip "$JAVADOC_JAR" -d api/latest
rm -rf api/latest/META-INF/
git add -f api/latest
+ git commit -m "Latest javadoc on successful travis build $TRAVIS_BUILD_NUMBER auto-pushed to gh-pages"
+ git push -fq origin gh-pages > /dev/null
- # Check if there are any changes before committing, otherwise attempting
- # to commit will fail the build (https://stackoverflow.com/a/2659808).
- if [[ $(git diff-index --quiet HEAD --) || $? == 1 ]]; then
- # The exist status is 1, meaning there are changes to commit
- git commit -m "Latest javadoc on successful Github build $GITHUB_WORKFLOW/$GITHUB_RUN_ID auto-pushed to gh-pages"
- git push -fq origin gh-pages > /dev/null
- echo -e "Published Javadoc to gh-pages.\n"
- else
- # The exist status is 0, meaning there are no changes to commit
- echo -e "Skipping publishing docs since no changes were detected."
- fi
+ echo -e "Published Javadoc to gh-pages.\n"
else
- echo -e "Not publishing docs for branch=${$GITHUB_REF}"
+ echo -e "Not publishing docs for jdk=${TRAVIS_JDK_VERSION} and branch=${TRAVIS_BRANCH}"
fi
diff --git a/util/install-local-snapshot.sh b/util/install-local-snapshot.sh
index be6030c..8f77a41 100755
--- a/util/install-local-snapshot.sh
+++ b/util/install-local-snapshot.sh
@@ -4,43 +4,8 @@
echo -e "Installing maven snapshot locally...\n"
-bash $(dirname $0)/deploy-dagger.sh \
- "install:install-file" \
- "LOCAL-SNAPSHOT"
-
-bash $(dirname $0)/deploy-hilt.sh \
+bash $(dirname $0)/execute-deploy.sh \
"install:install-file" \
"LOCAL-SNAPSHOT"
echo -e "Installed local snapshot"
-
-verify_version_file() {
- local m2_repo=$(mvn help:evaluate -Dexpression=settings.localRepository -q -DforceStdout)
- local group_path=com/google/dagger
- local artifact_id=$1
- local type=$2
- local version="LOCAL-SNAPSHOT"
- local temp_dir=$(mktemp -d)
- local content
- if [ $type = "jar" ]; then
- unzip $m2_repo/$group_path/$artifact_id/$version/$artifact_id-$version.jar \
- META-INF/com.google.dagger_$artifact_id.version \
- -d $temp_dir
- elif [ $type = "aar" ]; then
- unzip $m2_repo/$group_path/$artifact_id/$version/$artifact_id-$version.aar \
- classes.jar \
- -d $temp_dir
- unzip $temp_dir/classes.jar \
- META-INF/com.google.dagger_$artifact_id.version \
- -d $temp_dir
- fi
- local content=$(cat $temp_dir/META-INF/com.google.dagger_${artifact_id}.version)
- if [[ $content != $version ]]; then
- echo "Version file failed verification for artifact: $artifact_id"
- exit 1
- fi
-}
-
-# Verify tracking version file in Dagger and Dagger Android
-verify_version_file "dagger" "jar"
-verify_version_file "dagger-android" "aar"
diff --git a/util/publish-snapshot-on-commit.sh b/util/publish-snapshot-on-commit.sh
index 63cc3ea..944a2c3 100755
--- a/util/publish-snapshot-on-commit.sh
+++ b/util/publish-snapshot-on-commit.sh
@@ -1,20 +1,14 @@
# see https://coderwall.com/p/9b_lfq
-set -eux
+set -eu
-if [ "$GITHUB_REPOSITORY" == "google/dagger" ] && \
- [ "$GITHUB_EVENT_NAME" == "push" ] && \
- [ "$GITHUB_REF" == "refs/heads/master" ]; then
+if [ "$TRAVIS_REPO_SLUG" == "google/dagger" ] && \
+ [ "$TRAVIS_JDK_VERSION" == "$JDK_FOR_PUBLISHING" ] && \
+ [ "$TRAVIS_PULL_REQUEST" == "false" ] && \
+ [ "$TRAVIS_BRANCH" == "master" ]; then
echo -e "Publishing maven snapshot...\n"
- bash $(dirname $0)/deploy-dagger.sh \
- "deploy:deploy-file" \
- "HEAD-SNAPSHOT" \
- "-DrepositoryId=sonatype-nexus-snapshots" \
- "-Durl=https://oss.sonatype.org/content/repositories/snapshots" \
- "--settings=$(dirname $0)/settings.xml"
-
- bash $(dirname $0)/deploy-hilt.sh \
+ bash $(dirname $0)/execute-deploy.sh \
"deploy:deploy-file" \
"HEAD-SNAPSHOT" \
"-DrepositoryId=sonatype-nexus-snapshots" \
@@ -23,5 +17,5 @@
echo -e "Published maven snapshot"
else
- echo -e "Not publishing snapshot for branch=${$GITHUB_REF}"
+ echo -e "Not publishing snapshot for jdk=${TRAVIS_JDK_VERSION} and branch=${TRAVIS_BRANCH}"
fi
diff --git a/util/run-local-emulator-tests.sh b/util/run-local-emulator-tests.sh
deleted file mode 100755
index 7fc7762..0000000
--- a/util/run-local-emulator-tests.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-readonly GRADLE_PROJECTS=(
- "javatests/artifacts/hilt-android/simple"
- "javatests/artifacts/hilt-android/simpleKotlin"
-)
-for project in "${GRADLE_PROJECTS[@]}"; do
- echo "Running gradle Android emulator tests for $project"
- ./$project/gradlew -p $project connectedAndroidTest --no-daemon --stacktrace
-done
-
-# Run emulator tests in a project with configuration cache enabled
-# TODO(danysantiago): Once AGP 4.2.0 is stable, remove these project and enable
-# config cache in the other test projects.
-readonly CONFIG_CACHE_PROJECT="javatests/artifacts/hilt-android/gradleConfigCache"
-./$CONFIG_CACHE_PROJECT/gradlew -p $CONFIG_CACHE_PROJECT connectedAndroidTest --no-daemon --stacktrace --configuration-cache
diff --git a/util/run-local-gradle-android-tests.sh b/util/run-local-gradle-android-tests.sh
deleted file mode 100755
index ba51078..0000000
--- a/util/run-local-gradle-android-tests.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-readonly AGP_VERSION_INPUT=$1
-readonly ANDROID_GRADLE_PROJECTS=(
- "java/dagger/example/gradle/android/simple"
- "javatests/artifacts/dagger-android/simple"
- "javatests/artifacts/hilt-android/simple"
- "javatests/artifacts/hilt-android/simpleKotlin"
-)
-for project in "${ANDROID_GRADLE_PROJECTS[@]}"; do
- echo "Running gradle tests for $project with AGP $AGP_VERSION_INPUT"
- AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project buildDebug --no-daemon --stacktrace
- AGP_VERSION=$AGP_VERSION_INPUT ./$project/gradlew -p $project testDebug --no-daemon --stacktrace
-done
-
-# Run gradle tests in a project with configuration cache enabled
-# TODO(danysantiago): Once AGP 4.2.0 is stable, remove these project and enable
-# config cache in the other test projects.
-readonly CONFIG_CACHE_PROJECT="javatests/artifacts/hilt-android/gradleConfigCache"
-./$CONFIG_CACHE_PROJECT/gradlew -p $CONFIG_CACHE_PROJECT assembleDebug --no-daemon --stacktrace --configuration-cache
diff --git a/util/run-local-gradle-tests.sh b/util/run-local-gradle-tests.sh
deleted file mode 100755
index b88ccab..0000000
--- a/util/run-local-gradle-tests.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-readonly GRADLE_PROJECTS=(
- "java/dagger/example/gradle/simple"
- "java/dagger/hilt/android/plugin"
- "javatests/artifacts/dagger/simple"
-)
-for project in "${GRADLE_PROJECTS[@]}"; do
- echo "Running gradle tests for $project"
- ./$project/gradlew -p $project build --no-daemon --stacktrace
- ./$project/gradlew -p $project test --no-daemon --stacktrace
-done
diff --git a/util/run-local-tests.sh b/util/run-local-tests.sh
deleted file mode 100755
index ea78671..0000000
--- a/util/run-local-tests.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-# These jobs should match .github/workflows/ci.yml. We can't run this script
-# directly in Github since it's too slow for a single job.
-
-# Run local bazel tests
-bazel test --test_output=errors //...
-
-# Install local maven artifacts.
-util/install-local-snapshot.sh
-
-# Run local mvn tests
-pushd examples/maven && mvn compile && popd
-
-# Run local gradle tests
-util/run-local-gradle-tests.sh
-util/run-local-gradle-android-tests.sh "4.1.0"
-util/run-local-gradle-android-tests.sh "4.2.0-beta04"
-
diff --git a/workspace_defs.bzl b/workspace_defs.bzl
deleted file mode 100644
index c017b76..0000000
--- a/workspace_defs.bzl
+++ /dev/null
@@ -1,292 +0,0 @@
-# Copyright (C) 2020 The Google Bazel Common 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.
-
-"""A macro to configure Dagger deps within a workspace"""
-
-load("//:build_defs.bzl", "POM_VERSION", "POM_VERSION_ALPHA")
-
-_DAGGER_VERSION = POM_VERSION
-_HILT_VERSION = POM_VERSION_ALPHA
-
-DAGGER_ARTIFACTS = [
- "com.google.dagger:dagger:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-compiler:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-producers:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-spi:" + _DAGGER_VERSION,
-]
-
-DAGGER_ANDROID_ARTIFACTS = [
- "com.google.dagger:dagger-android-processor:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-android-support:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-android:" + _DAGGER_VERSION,
-]
-
-HILT_ANDROID_ARTIFACTS = [
- "androidx.test:core:1.1.0", # Export for ApplicationProvider
- "javax.annotation:jsr250-api:1.0", # Export for @Generated
- "androidx.annotation:annotation:1.1.0", # Export for @CallSuper/@Nullable
- "com.google.dagger:dagger:" + _DAGGER_VERSION,
- "com.google.dagger:dagger-compiler:" + _DAGGER_VERSION,
- "com.google.dagger:hilt-android:" + _HILT_VERSION,
- "com.google.dagger:hilt-android-testing:" + _HILT_VERSION,
- "com.google.dagger:hilt-android-compiler:" + _HILT_VERSION,
-]
-
-DAGGER_REPOSITORIES = [
- "https://maven.google.com",
- "https://repo1.maven.org/maven2",
-]
-
-DAGGER_ANDROID_REPOSITORIES = DAGGER_REPOSITORIES
-
-HILT_ANDROID_REPOSITORIES = DAGGER_REPOSITORIES
-
-# https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#unnamed-macro
-# buildifier: disable=unnamed-macro
-def dagger_rules(repo_name = "@maven"):
- """Defines the Dagger targets with proper exported dependencies and plugins.
-
- The targets will be of the form ":<artifact-id>".
-
- Args:
- repo_name: The name of the dependency repository (default is "@maven").
- """
- native.java_library(
- name = "dagger",
- exported_plugins = [":dagger-compiler"],
- visibility = ["//visibility:public"],
- exports = [
- "%s//:com_google_dagger_dagger" % repo_name,
- "%s//:javax_inject_javax_inject" % repo_name,
- ],
- )
-
- native.java_plugin(
- name = "dagger-compiler",
- generates_api = 1,
- processor_class = "dagger.internal.codegen.ComponentProcessor",
- deps = [
- "%s//:com_google_dagger_dagger_compiler" % repo_name,
- ],
- )
-
- native.java_library(
- name = "dagger-producers",
- visibility = ["//visibility:public"],
- exports = [
- ":dagger",
- "%s//:com_google_dagger_dagger_producers" % repo_name,
- ],
- )
-
- native.java_library(
- name = "dagger-spi",
- visibility = ["//visibility:public"],
- exports = [
- "%s//:com_google_dagger_dagger_spi" % repo_name,
- ],
- )
-
-# https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#unnamed-macro
-# buildifier: disable=unnamed-macro
-def dagger_android_rules(repo_name = "@maven"):
- """Defines the Dagger Android targets with proper exported dependencies and plugins.
-
- The targets will be of the form ":<artifact-id>".
-
- Args:
- repo_name: The name of the dependency repository (default is "@maven").
- """
-
- # https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#native-android
- # buildifier: disable=native-android
- native.android_library(
- name = "dagger-android",
- exported_plugins = [":dagger-android-processor"],
- visibility = ["//visibility:public"],
- exports = [
- "%s//:com_google_dagger_dagger_android" % repo_name,
- ],
- )
-
- # https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#native-android
- # buildifier: disable=native-android
- native.android_library(
- name = "dagger-android-support",
- exported_plugins = [":dagger-android-processor"],
- visibility = ["//visibility:public"],
- exports = [
- ":dagger-android",
- "%s//:com_google_dagger_dagger_android_support" % repo_name,
- ],
- )
-
- native.java_plugin(
- name = "dagger-android-processor",
- generates_api = 1,
- processor_class = "dagger.android.processor.AndroidProcessor",
- deps = [
- "%s//:com_google_dagger_dagger_android_processor" % repo_name,
- ],
- )
-
-# https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#unnamed-macro
-# buildifier: disable=unnamed-macro
-def hilt_android_rules(repo_name = "@maven"):
- """Defines the Hilt Android targets with proper exported dependencies and plugins.
-
- The targets will be of the form ":<artifact-id>".
-
- Args:
- repo_name: The name of the dependency repository (default is "@maven").
- """
-
- # https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#native-android
- # buildifier: disable=native-android
- native.android_library(
- name = "hilt-android",
- exported_plugins = [
- ":hilt_dagger_compiler",
- ":hilt_android_entry_point_processor",
- ":hilt_aggregated_deps_processor",
- ":hilt_alias_of_processor",
- ":hilt_define_component_processor",
- ":hilt_generates_root_input_processor",
- ":hilt_originating_element_processor",
- ":hilt_root_processor",
- ":hilt_view_model_processor",
- ],
- visibility = ["//visibility:public"],
- exports = [
- "%s//:com_google_dagger_dagger" % repo_name, # For Dagger APIs
- "%s//:javax_inject_javax_inject" % repo_name, # For @Inject
- "%s//:androidx_annotation_annotation" % repo_name, # For @CallSuper
- "%s//:com_google_dagger_hilt_android" % repo_name,
- "%s//:javax_annotation_jsr250_api" % repo_name, # For @Generated
- ],
- )
-
- # This target is same as dagger-compiler, but we're redefining it here
- # so that users don't have to call dagger_rules() first.
- native.java_plugin(
- name = "hilt_dagger_compiler",
- generates_api = 1,
- processor_class = "dagger.internal.codegen.ComponentProcessor",
- deps = [
- "%s//:com_google_dagger_dagger_compiler" % repo_name,
- ],
- )
-
- native.java_plugin(
- name = "hilt_android_entry_point_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.androidentrypoint.AndroidEntryPointProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_aggregated_deps_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_alias_of_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.aliasof.AliasOfProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_define_component_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.definecomponent.DefineComponentProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_generates_root_input_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_originating_element_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.originatingelement.OriginatingElementProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_root_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.processor.internal.root.RootProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_view_model_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.viewmodel.ViewModelProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- # https://github.com/bazelbuild/buildtools/blob/master/WARNINGS.md#native-android
- # buildifier: disable=native-android
- native.android_library(
- name = "hilt-android-testing",
- testonly = 1,
- exported_plugins = [
- ":hilt_bind_value_processor",
- ":hilt_custom_test_application_processor",
- ":hilt_testroot_processor",
- ":hilt_uninstall_modules_processor",
- ],
- visibility = ["//visibility:public"],
- exports = [
- ":hilt-android",
- "%s//:androidx_test_core" % repo_name, # For ApplicationProvider
- "%s//:com_google_dagger_hilt_android_testing" % repo_name,
- ],
- )
-
- native.java_plugin(
- name = "hilt_bind_value_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.bindvalue.BindValueProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_custom_test_application_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.customtestapplication.CustomTestApplicationProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_testroot_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.testroot.TestRootProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )
-
- native.java_plugin(
- name = "hilt_uninstall_modules_processor",
- generates_api = 1,
- processor_class = "dagger.hilt.android.processor.internal.uninstallmodules.UninstallModulesProcessor",
- deps = ["%s//:com_google_dagger_hilt_android_compiler" % repo_name],
- )